1235633Sdim//=== ARMCallingConv.h - ARM Custom Calling Convention Routines -*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file contains the custom routines for the ARM Calling Convention that
11218885Sdim// aren't done by tablegen.
12218885Sdim//
13218885Sdim//===----------------------------------------------------------------------===//
14218885Sdim
15218885Sdim#ifndef ARMCALLINGCONV_H
16218885Sdim#define ARMCALLINGCONV_H
17218885Sdim
18235633Sdim#include "ARM.h"
19235633Sdim#include "ARMBaseInstrInfo.h"
20235633Sdim#include "ARMSubtarget.h"
21218885Sdim#include "llvm/CodeGen/CallingConvLower.h"
22252723Sdim#include "llvm/IR/CallingConv.h"
23218885Sdim#include "llvm/Target/TargetInstrInfo.h"
24218885Sdim
25218885Sdimnamespace llvm {
26218885Sdim
27218885Sdim// APCS f64 is in register pairs, possibly split to stack
28218885Sdimstatic bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
29218885Sdim                          CCValAssign::LocInfo &LocInfo,
30218885Sdim                          CCState &State, bool CanFail) {
31235633Sdim  static const uint16_t RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 };
32218885Sdim
33218885Sdim  // Try to get the first register.
34218885Sdim  if (unsigned Reg = State.AllocateReg(RegList, 4))
35218885Sdim    State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
36218885Sdim  else {
37218885Sdim    // For the 2nd half of a v2f64, do not fail.
38218885Sdim    if (CanFail)
39218885Sdim      return false;
40218885Sdim
41218885Sdim    // Put the whole thing on the stack.
42218885Sdim    State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
43218885Sdim                                           State.AllocateStack(8, 4),
44218885Sdim                                           LocVT, LocInfo));
45218885Sdim    return true;
46218885Sdim  }
47218885Sdim
48218885Sdim  // Try to get the second register.
49218885Sdim  if (unsigned Reg = State.AllocateReg(RegList, 4))
50218885Sdim    State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
51218885Sdim  else
52218885Sdim    State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
53218885Sdim                                           State.AllocateStack(4, 4),
54218885Sdim                                           LocVT, LocInfo));
55218885Sdim  return true;
56218885Sdim}
57218885Sdim
58218885Sdimstatic bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
59218885Sdim                                   CCValAssign::LocInfo &LocInfo,
60218885Sdim                                   ISD::ArgFlagsTy &ArgFlags,
61218885Sdim                                   CCState &State) {
62218885Sdim  if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true))
63218885Sdim    return false;
64218885Sdim  if (LocVT == MVT::v2f64 &&
65218885Sdim      !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false))
66218885Sdim    return false;
67218885Sdim  return true;  // we handled it
68218885Sdim}
69218885Sdim
70218885Sdim// AAPCS f64 is in aligned register pairs
71218885Sdimstatic bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
72218885Sdim                           CCValAssign::LocInfo &LocInfo,
73218885Sdim                           CCState &State, bool CanFail) {
74235633Sdim  static const uint16_t HiRegList[] = { ARM::R0, ARM::R2 };
75235633Sdim  static const uint16_t LoRegList[] = { ARM::R1, ARM::R3 };
76235633Sdim  static const uint16_t ShadowRegList[] = { ARM::R0, ARM::R1 };
77252723Sdim  static const uint16_t GPRArgRegs[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 };
78218885Sdim
79218885Sdim  unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2);
80218885Sdim  if (Reg == 0) {
81252723Sdim
82252723Sdim    // If we had R3 unallocated only, now we still must to waste it.
83252723Sdim    Reg = State.AllocateReg(GPRArgRegs, 4);
84252723Sdim    assert((!Reg || Reg == ARM::R3) && "Wrong GPRs usage for f64");
85252723Sdim
86218885Sdim    // For the 2nd half of a v2f64, do not just fail.
87218885Sdim    if (CanFail)
88218885Sdim      return false;
89218885Sdim
90218885Sdim    // Put the whole thing on the stack.
91218885Sdim    State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
92218885Sdim                                           State.AllocateStack(8, 8),
93218885Sdim                                           LocVT, LocInfo));
94218885Sdim    return true;
95218885Sdim  }
96218885Sdim
97218885Sdim  unsigned i;
98218885Sdim  for (i = 0; i < 2; ++i)
99218885Sdim    if (HiRegList[i] == Reg)
100218885Sdim      break;
101218885Sdim
102218885Sdim  unsigned T = State.AllocateReg(LoRegList[i]);
103218885Sdim  (void)T;
104218885Sdim  assert(T == LoRegList[i] && "Could not allocate register");
105218885Sdim
106218885Sdim  State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
107218885Sdim  State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
108218885Sdim                                         LocVT, LocInfo));
109218885Sdim  return true;
110218885Sdim}
111218885Sdim
112218885Sdimstatic bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
113218885Sdim                                    CCValAssign::LocInfo &LocInfo,
114218885Sdim                                    ISD::ArgFlagsTy &ArgFlags,
115218885Sdim                                    CCState &State) {
116218885Sdim  if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true))
117218885Sdim    return false;
118218885Sdim  if (LocVT == MVT::v2f64 &&
119218885Sdim      !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false))
120218885Sdim    return false;
121218885Sdim  return true;  // we handled it
122218885Sdim}
123218885Sdim
124218885Sdimstatic bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
125218885Sdim                         CCValAssign::LocInfo &LocInfo, CCState &State) {
126235633Sdim  static const uint16_t HiRegList[] = { ARM::R0, ARM::R2 };
127235633Sdim  static const uint16_t LoRegList[] = { ARM::R1, ARM::R3 };
128218885Sdim
129218885Sdim  unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2);
130218885Sdim  if (Reg == 0)
131218885Sdim    return false; // we didn't handle it
132218885Sdim
133218885Sdim  unsigned i;
134218885Sdim  for (i = 0; i < 2; ++i)
135218885Sdim    if (HiRegList[i] == Reg)
136218885Sdim      break;
137218885Sdim
138218885Sdim  State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
139218885Sdim  State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
140218885Sdim                                         LocVT, LocInfo));
141218885Sdim  return true;
142218885Sdim}
143218885Sdim
144218885Sdimstatic bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
145218885Sdim                                      CCValAssign::LocInfo &LocInfo,
146218885Sdim                                      ISD::ArgFlagsTy &ArgFlags,
147218885Sdim                                      CCState &State) {
148218885Sdim  if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State))
149218885Sdim    return false;
150218885Sdim  if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State))
151218885Sdim    return false;
152218885Sdim  return true;  // we handled it
153218885Sdim}
154218885Sdim
155218885Sdimstatic bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
156218885Sdim                                       CCValAssign::LocInfo &LocInfo,
157218885Sdim                                       ISD::ArgFlagsTy &ArgFlags,
158218885Sdim                                       CCState &State) {
159218885Sdim  return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags,
160218885Sdim                                   State);
161218885Sdim}
162218885Sdim
163218885Sdim} // End llvm namespace
164218885Sdim
165218885Sdim#endif
166