xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMCallingConv.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //=== ARMCallingConv.cpp - ARM Custom CC Routines ---------------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file contains the custom routines for the ARM Calling Convention that
10*0b57cec5SDimitry Andric // aren't done by tablegen, and includes the table generated implementations.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "ARM.h"
15*0b57cec5SDimitry Andric #include "ARMCallingConv.h"
16*0b57cec5SDimitry Andric #include "ARMSubtarget.h"
17*0b57cec5SDimitry Andric #include "ARMRegisterInfo.h"
18*0b57cec5SDimitry Andric using namespace llvm;
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric // APCS f64 is in register pairs, possibly split to stack
21*0b57cec5SDimitry Andric static bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
22*0b57cec5SDimitry Andric                           CCValAssign::LocInfo &LocInfo,
23*0b57cec5SDimitry Andric                           CCState &State, bool CanFail) {
24*0b57cec5SDimitry Andric   static const MCPhysReg RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 };
25*0b57cec5SDimitry Andric 
26*0b57cec5SDimitry Andric   // Try to get the first register.
27*0b57cec5SDimitry Andric   if (unsigned Reg = State.AllocateReg(RegList))
28*0b57cec5SDimitry Andric     State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
29*0b57cec5SDimitry Andric   else {
30*0b57cec5SDimitry Andric     // For the 2nd half of a v2f64, do not fail.
31*0b57cec5SDimitry Andric     if (CanFail)
32*0b57cec5SDimitry Andric       return false;
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric     // Put the whole thing on the stack.
35*0b57cec5SDimitry Andric     State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
36*0b57cec5SDimitry Andric                                            State.AllocateStack(8, 4),
37*0b57cec5SDimitry Andric                                            LocVT, LocInfo));
38*0b57cec5SDimitry Andric     return true;
39*0b57cec5SDimitry Andric   }
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric   // Try to get the second register.
42*0b57cec5SDimitry Andric   if (unsigned Reg = State.AllocateReg(RegList))
43*0b57cec5SDimitry Andric     State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
44*0b57cec5SDimitry Andric   else
45*0b57cec5SDimitry Andric     State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
46*0b57cec5SDimitry Andric                                            State.AllocateStack(4, 4),
47*0b57cec5SDimitry Andric                                            LocVT, LocInfo));
48*0b57cec5SDimitry Andric   return true;
49*0b57cec5SDimitry Andric }
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
52*0b57cec5SDimitry Andric                                    CCValAssign::LocInfo &LocInfo,
53*0b57cec5SDimitry Andric                                    ISD::ArgFlagsTy &ArgFlags,
54*0b57cec5SDimitry Andric                                    CCState &State) {
55*0b57cec5SDimitry Andric   if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true))
56*0b57cec5SDimitry Andric     return false;
57*0b57cec5SDimitry Andric   if (LocVT == MVT::v2f64 &&
58*0b57cec5SDimitry Andric       !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false))
59*0b57cec5SDimitry Andric     return false;
60*0b57cec5SDimitry Andric   return true;  // we handled it
61*0b57cec5SDimitry Andric }
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric // AAPCS f64 is in aligned register pairs
64*0b57cec5SDimitry Andric static bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
65*0b57cec5SDimitry Andric                            CCValAssign::LocInfo &LocInfo,
66*0b57cec5SDimitry Andric                            CCState &State, bool CanFail) {
67*0b57cec5SDimitry Andric   static const MCPhysReg HiRegList[] = { ARM::R0, ARM::R2 };
68*0b57cec5SDimitry Andric   static const MCPhysReg LoRegList[] = { ARM::R1, ARM::R3 };
69*0b57cec5SDimitry Andric   static const MCPhysReg ShadowRegList[] = { ARM::R0, ARM::R1 };
70*0b57cec5SDimitry Andric   static const MCPhysReg GPRArgRegs[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 };
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric   unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList);
73*0b57cec5SDimitry Andric   if (Reg == 0) {
74*0b57cec5SDimitry Andric 
75*0b57cec5SDimitry Andric     // If we had R3 unallocated only, now we still must to waste it.
76*0b57cec5SDimitry Andric     Reg = State.AllocateReg(GPRArgRegs);
77*0b57cec5SDimitry Andric     assert((!Reg || Reg == ARM::R3) && "Wrong GPRs usage for f64");
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric     // For the 2nd half of a v2f64, do not just fail.
80*0b57cec5SDimitry Andric     if (CanFail)
81*0b57cec5SDimitry Andric       return false;
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric     // Put the whole thing on the stack.
84*0b57cec5SDimitry Andric     State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
85*0b57cec5SDimitry Andric                                            State.AllocateStack(8, 8),
86*0b57cec5SDimitry Andric                                            LocVT, LocInfo));
87*0b57cec5SDimitry Andric     return true;
88*0b57cec5SDimitry Andric   }
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric   unsigned i;
91*0b57cec5SDimitry Andric   for (i = 0; i < 2; ++i)
92*0b57cec5SDimitry Andric     if (HiRegList[i] == Reg)
93*0b57cec5SDimitry Andric       break;
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric   unsigned T = State.AllocateReg(LoRegList[i]);
96*0b57cec5SDimitry Andric   (void)T;
97*0b57cec5SDimitry Andric   assert(T == LoRegList[i] && "Could not allocate register");
98*0b57cec5SDimitry Andric 
99*0b57cec5SDimitry Andric   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
100*0b57cec5SDimitry Andric   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
101*0b57cec5SDimitry Andric                                          LocVT, LocInfo));
102*0b57cec5SDimitry Andric   return true;
103*0b57cec5SDimitry Andric }
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
106*0b57cec5SDimitry Andric                                     CCValAssign::LocInfo &LocInfo,
107*0b57cec5SDimitry Andric                                     ISD::ArgFlagsTy &ArgFlags,
108*0b57cec5SDimitry Andric                                     CCState &State) {
109*0b57cec5SDimitry Andric   if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true))
110*0b57cec5SDimitry Andric     return false;
111*0b57cec5SDimitry Andric   if (LocVT == MVT::v2f64 &&
112*0b57cec5SDimitry Andric       !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false))
113*0b57cec5SDimitry Andric     return false;
114*0b57cec5SDimitry Andric   return true;  // we handled it
115*0b57cec5SDimitry Andric }
116*0b57cec5SDimitry Andric 
117*0b57cec5SDimitry Andric static bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
118*0b57cec5SDimitry Andric                          CCValAssign::LocInfo &LocInfo, CCState &State) {
119*0b57cec5SDimitry Andric   static const MCPhysReg HiRegList[] = { ARM::R0, ARM::R2 };
120*0b57cec5SDimitry Andric   static const MCPhysReg LoRegList[] = { ARM::R1, ARM::R3 };
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   unsigned Reg = State.AllocateReg(HiRegList, LoRegList);
123*0b57cec5SDimitry Andric   if (Reg == 0)
124*0b57cec5SDimitry Andric     return false; // we didn't handle it
125*0b57cec5SDimitry Andric 
126*0b57cec5SDimitry Andric   unsigned i;
127*0b57cec5SDimitry Andric   for (i = 0; i < 2; ++i)
128*0b57cec5SDimitry Andric     if (HiRegList[i] == Reg)
129*0b57cec5SDimitry Andric       break;
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
132*0b57cec5SDimitry Andric   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
133*0b57cec5SDimitry Andric                                          LocVT, LocInfo));
134*0b57cec5SDimitry Andric   return true;
135*0b57cec5SDimitry Andric }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
138*0b57cec5SDimitry Andric                                       CCValAssign::LocInfo &LocInfo,
139*0b57cec5SDimitry Andric                                       ISD::ArgFlagsTy &ArgFlags,
140*0b57cec5SDimitry Andric                                       CCState &State) {
141*0b57cec5SDimitry Andric   if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State))
142*0b57cec5SDimitry Andric     return false;
143*0b57cec5SDimitry Andric   if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State))
144*0b57cec5SDimitry Andric     return false;
145*0b57cec5SDimitry Andric   return true;  // we handled it
146*0b57cec5SDimitry Andric }
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
149*0b57cec5SDimitry Andric                                        CCValAssign::LocInfo &LocInfo,
150*0b57cec5SDimitry Andric                                        ISD::ArgFlagsTy &ArgFlags,
151*0b57cec5SDimitry Andric                                        CCState &State) {
152*0b57cec5SDimitry Andric   return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags,
153*0b57cec5SDimitry Andric                                    State);
154*0b57cec5SDimitry Andric }
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric static const MCPhysReg RRegList[] = { ARM::R0,  ARM::R1,  ARM::R2,  ARM::R3 };
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric static const MCPhysReg SRegList[] = { ARM::S0,  ARM::S1,  ARM::S2,  ARM::S3,
159*0b57cec5SDimitry Andric                                       ARM::S4,  ARM::S5,  ARM::S6,  ARM::S7,
160*0b57cec5SDimitry Andric                                       ARM::S8,  ARM::S9,  ARM::S10, ARM::S11,
161*0b57cec5SDimitry Andric                                       ARM::S12, ARM::S13, ARM::S14,  ARM::S15 };
162*0b57cec5SDimitry Andric static const MCPhysReg DRegList[] = { ARM::D0, ARM::D1, ARM::D2, ARM::D3,
163*0b57cec5SDimitry Andric                                       ARM::D4, ARM::D5, ARM::D6, ARM::D7 };
164*0b57cec5SDimitry Andric static const MCPhysReg QRegList[] = { ARM::Q0, ARM::Q1, ARM::Q2, ARM::Q3 };
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric 
167*0b57cec5SDimitry Andric // Allocate part of an AAPCS HFA or HVA. We assume that each member of the HA
168*0b57cec5SDimitry Andric // has InConsecutiveRegs set, and that the last member also has
169*0b57cec5SDimitry Andric // InConsecutiveRegsLast set. We must process all members of the HA before
170*0b57cec5SDimitry Andric // we can allocate it, as we need to know the total number of registers that
171*0b57cec5SDimitry Andric // will be needed in order to (attempt to) allocate a contiguous block.
172*0b57cec5SDimitry Andric static bool CC_ARM_AAPCS_Custom_Aggregate(unsigned &ValNo, MVT &ValVT,
173*0b57cec5SDimitry Andric                                           MVT &LocVT,
174*0b57cec5SDimitry Andric                                           CCValAssign::LocInfo &LocInfo,
175*0b57cec5SDimitry Andric                                           ISD::ArgFlagsTy &ArgFlags,
176*0b57cec5SDimitry Andric                                           CCState &State) {
177*0b57cec5SDimitry Andric   SmallVectorImpl<CCValAssign> &PendingMembers = State.getPendingLocs();
178*0b57cec5SDimitry Andric 
179*0b57cec5SDimitry Andric   // AAPCS HFAs must have 1-4 elements, all of the same type
180*0b57cec5SDimitry Andric   if (PendingMembers.size() > 0)
181*0b57cec5SDimitry Andric     assert(PendingMembers[0].getLocVT() == LocVT);
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric   // Add the argument to the list to be allocated once we know the size of the
184*0b57cec5SDimitry Andric   // aggregate. Store the type's required alignmnent as extra info for later: in
185*0b57cec5SDimitry Andric   // the [N x i64] case all trace has been removed by the time we actually get
186*0b57cec5SDimitry Andric   // to do allocation.
187*0b57cec5SDimitry Andric   PendingMembers.push_back(CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo,
188*0b57cec5SDimitry Andric                                                    ArgFlags.getOrigAlign()));
189*0b57cec5SDimitry Andric 
190*0b57cec5SDimitry Andric   if (!ArgFlags.isInConsecutiveRegsLast())
191*0b57cec5SDimitry Andric     return true;
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric   // Try to allocate a contiguous block of registers, each of the correct
194*0b57cec5SDimitry Andric   // size to hold one member.
195*0b57cec5SDimitry Andric   auto &DL = State.getMachineFunction().getDataLayout();
196*0b57cec5SDimitry Andric   unsigned StackAlign = DL.getStackAlignment();
197*0b57cec5SDimitry Andric   unsigned Align = std::min(PendingMembers[0].getExtraInfo(), StackAlign);
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric   ArrayRef<MCPhysReg> RegList;
200*0b57cec5SDimitry Andric   switch (LocVT.SimpleTy) {
201*0b57cec5SDimitry Andric   case MVT::i32: {
202*0b57cec5SDimitry Andric     RegList = RRegList;
203*0b57cec5SDimitry Andric     unsigned RegIdx = State.getFirstUnallocated(RegList);
204*0b57cec5SDimitry Andric 
205*0b57cec5SDimitry Andric     // First consume all registers that would give an unaligned object. Whether
206*0b57cec5SDimitry Andric     // we go on stack or in regs, no-one will be using them in future.
207*0b57cec5SDimitry Andric     unsigned RegAlign = alignTo(Align, 4) / 4;
208*0b57cec5SDimitry Andric     while (RegIdx % RegAlign != 0 && RegIdx < RegList.size())
209*0b57cec5SDimitry Andric       State.AllocateReg(RegList[RegIdx++]);
210*0b57cec5SDimitry Andric 
211*0b57cec5SDimitry Andric     break;
212*0b57cec5SDimitry Andric   }
213*0b57cec5SDimitry Andric   case MVT::f16:
214*0b57cec5SDimitry Andric   case MVT::f32:
215*0b57cec5SDimitry Andric     RegList = SRegList;
216*0b57cec5SDimitry Andric     break;
217*0b57cec5SDimitry Andric   case MVT::v4f16:
218*0b57cec5SDimitry Andric   case MVT::f64:
219*0b57cec5SDimitry Andric     RegList = DRegList;
220*0b57cec5SDimitry Andric     break;
221*0b57cec5SDimitry Andric   case MVT::v8f16:
222*0b57cec5SDimitry Andric   case MVT::v2f64:
223*0b57cec5SDimitry Andric     RegList = QRegList;
224*0b57cec5SDimitry Andric     break;
225*0b57cec5SDimitry Andric   default:
226*0b57cec5SDimitry Andric     llvm_unreachable("Unexpected member type for block aggregate");
227*0b57cec5SDimitry Andric     break;
228*0b57cec5SDimitry Andric   }
229*0b57cec5SDimitry Andric 
230*0b57cec5SDimitry Andric   unsigned RegResult = State.AllocateRegBlock(RegList, PendingMembers.size());
231*0b57cec5SDimitry Andric   if (RegResult) {
232*0b57cec5SDimitry Andric     for (SmallVectorImpl<CCValAssign>::iterator It = PendingMembers.begin();
233*0b57cec5SDimitry Andric          It != PendingMembers.end(); ++It) {
234*0b57cec5SDimitry Andric       It->convertToReg(RegResult);
235*0b57cec5SDimitry Andric       State.addLoc(*It);
236*0b57cec5SDimitry Andric       ++RegResult;
237*0b57cec5SDimitry Andric     }
238*0b57cec5SDimitry Andric     PendingMembers.clear();
239*0b57cec5SDimitry Andric     return true;
240*0b57cec5SDimitry Andric   }
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric   // Register allocation failed, we'll be needing the stack
243*0b57cec5SDimitry Andric   unsigned Size = LocVT.getSizeInBits() / 8;
244*0b57cec5SDimitry Andric   if (LocVT == MVT::i32 && State.getNextStackOffset() == 0) {
245*0b57cec5SDimitry Andric     // If nothing else has used the stack until this point, a non-HFA aggregate
246*0b57cec5SDimitry Andric     // can be split between regs and stack.
247*0b57cec5SDimitry Andric     unsigned RegIdx = State.getFirstUnallocated(RegList);
248*0b57cec5SDimitry Andric     for (auto &It : PendingMembers) {
249*0b57cec5SDimitry Andric       if (RegIdx >= RegList.size())
250*0b57cec5SDimitry Andric         It.convertToMem(State.AllocateStack(Size, Size));
251*0b57cec5SDimitry Andric       else
252*0b57cec5SDimitry Andric         It.convertToReg(State.AllocateReg(RegList[RegIdx++]));
253*0b57cec5SDimitry Andric 
254*0b57cec5SDimitry Andric       State.addLoc(It);
255*0b57cec5SDimitry Andric     }
256*0b57cec5SDimitry Andric     PendingMembers.clear();
257*0b57cec5SDimitry Andric     return true;
258*0b57cec5SDimitry Andric   } else if (LocVT != MVT::i32)
259*0b57cec5SDimitry Andric     RegList = SRegList;
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric   // Mark all regs as unavailable (AAPCS rule C.2.vfp for VFP, C.6 for core)
262*0b57cec5SDimitry Andric   for (auto Reg : RegList)
263*0b57cec5SDimitry Andric     State.AllocateReg(Reg);
264*0b57cec5SDimitry Andric 
265*0b57cec5SDimitry Andric   // After the first item has been allocated, the rest are packed as tightly as
266*0b57cec5SDimitry Andric   // possible. (E.g. an incoming i64 would have starting Align of 8, but we'll
267*0b57cec5SDimitry Andric   // be allocating a bunch of i32 slots).
268*0b57cec5SDimitry Andric   unsigned RestAlign = std::min(Align, Size);
269*0b57cec5SDimitry Andric 
270*0b57cec5SDimitry Andric   for (auto &It : PendingMembers) {
271*0b57cec5SDimitry Andric     It.convertToMem(State.AllocateStack(Size, Align));
272*0b57cec5SDimitry Andric     State.addLoc(It);
273*0b57cec5SDimitry Andric     Align = RestAlign;
274*0b57cec5SDimitry Andric   }
275*0b57cec5SDimitry Andric 
276*0b57cec5SDimitry Andric   // All pending members have now been allocated
277*0b57cec5SDimitry Andric   PendingMembers.clear();
278*0b57cec5SDimitry Andric 
279*0b57cec5SDimitry Andric   // This will be allocated by the last member of the aggregate
280*0b57cec5SDimitry Andric   return true;
281*0b57cec5SDimitry Andric }
282*0b57cec5SDimitry Andric 
283*0b57cec5SDimitry Andric // Include the table generated calling convention implementations.
284*0b57cec5SDimitry Andric #include "ARMGenCallingConv.inc"
285