1 //===-- ARMCallingConv.h - ARM Custom Calling Convention Routines ---------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains the custom routines for the ARM Calling Convention that
11 // aren't done by tablegen.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef ARMCALLINGCONV_H
16 #define ARMCALLINGCONV_H
17 
18 #include "llvm/CallingConv.h"
19 #include "llvm/CodeGen/CallingConvLower.h"
20 #include "llvm/Target/TargetInstrInfo.h"
21 #include "ARMBaseInstrInfo.h"
22 #include "ARMRegisterInfo.h"
23 #include "ARMSubtarget.h"
24 #include "ARM.h"
25 
26 namespace llvm {
27 
28 // APCS f64 is in register pairs, possibly split to stack
29 static bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
30                           CCValAssign::LocInfo &LocInfo,
31                           CCState &State, bool CanFail) {
32   static const unsigned RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 };
33 
34   // Try to get the first register.
35   if (unsigned Reg = State.AllocateReg(RegList, 4))
36     State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
37   else {
38     // For the 2nd half of a v2f64, do not fail.
39     if (CanFail)
40       return false;
41 
42     // Put the whole thing on the stack.
43     State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
44                                            State.AllocateStack(8, 4),
45                                            LocVT, LocInfo));
46     return true;
47   }
48 
49   // Try to get the second register.
50   if (unsigned Reg = State.AllocateReg(RegList, 4))
51     State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
52   else
53     State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
54                                            State.AllocateStack(4, 4),
55                                            LocVT, LocInfo));
56   return true;
57 }
58 
59 static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
60                                    CCValAssign::LocInfo &LocInfo,
61                                    ISD::ArgFlagsTy &ArgFlags,
62                                    CCState &State) {
63   if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true))
64     return false;
65   if (LocVT == MVT::v2f64 &&
66       !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false))
67     return false;
68   return true;  // we handled it
69 }
70 
71 // AAPCS f64 is in aligned register pairs
72 static bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
73                            CCValAssign::LocInfo &LocInfo,
74                            CCState &State, bool CanFail) {
75   static const unsigned HiRegList[] = { ARM::R0, ARM::R2 };
76   static const unsigned LoRegList[] = { ARM::R1, ARM::R3 };
77   static const unsigned ShadowRegList[] = { ARM::R0, ARM::R1 };
78 
79   unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2);
80   if (Reg == 0) {
81     // For the 2nd half of a v2f64, do not just fail.
82     if (CanFail)
83       return false;
84 
85     // Put the whole thing on the stack.
86     State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
87                                            State.AllocateStack(8, 8),
88                                            LocVT, LocInfo));
89     return true;
90   }
91 
92   unsigned i;
93   for (i = 0; i < 2; ++i)
94     if (HiRegList[i] == Reg)
95       break;
96 
97   unsigned T = State.AllocateReg(LoRegList[i]);
98   (void)T;
99   assert(T == LoRegList[i] && "Could not allocate register");
100 
101   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
102   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
103                                          LocVT, LocInfo));
104   return true;
105 }
106 
107 static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
108                                     CCValAssign::LocInfo &LocInfo,
109                                     ISD::ArgFlagsTy &ArgFlags,
110                                     CCState &State) {
111   if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true))
112     return false;
113   if (LocVT == MVT::v2f64 &&
114       !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false))
115     return false;
116   return true;  // we handled it
117 }
118 
119 static bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
120                          CCValAssign::LocInfo &LocInfo, CCState &State) {
121   static const unsigned HiRegList[] = { ARM::R0, ARM::R2 };
122   static const unsigned LoRegList[] = { ARM::R1, ARM::R3 };
123 
124   unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2);
125   if (Reg == 0)
126     return false; // we didn't handle it
127 
128   unsigned i;
129   for (i = 0; i < 2; ++i)
130     if (HiRegList[i] == Reg)
131       break;
132 
133   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
134   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
135                                          LocVT, LocInfo));
136   return true;
137 }
138 
139 static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
140                                       CCValAssign::LocInfo &LocInfo,
141                                       ISD::ArgFlagsTy &ArgFlags,
142                                       CCState &State) {
143   if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State))
144     return false;
145   if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State))
146     return false;
147   return true;  // we handled it
148 }
149 
150 static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
151                                        CCValAssign::LocInfo &LocInfo,
152                                        ISD::ArgFlagsTy &ArgFlags,
153                                        CCState &State) {
154   return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags,
155                                    State);
156 }
157 
158 } // End llvm namespace
159 
160 #endif
161