xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCCallingConv.cpp (revision 02e9120893770924227138ba49df1edb3896112a)
1 //===-- PPCCallingConv.cpp - ------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PPCRegisterInfo.h"
10 #include "PPCCallingConv.h"
11 #include "PPCSubtarget.h"
12 #include "PPCCCState.h"
13 using namespace llvm;
14 
15 inline bool CC_PPC_AnyReg_Error(unsigned &, MVT &, MVT &,
16                                 CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
17                                 CCState &) {
18   llvm_unreachable("The AnyReg calling convention is only supported by the " \
19                    "stackmap and patchpoint intrinsics.");
20   // gracefully fallback to PPC C calling convention on Release builds.
21   return false;
22 }
23 
24 // This function handles the shadowing of GPRs for fp and vector types,
25 // and is a depiction of the algorithm described in the ELFv2 ABI,
26 // Section 2.2.4.1: Parameter Passing Register Selection Algorithm.
27 inline bool CC_PPC64_ELF_Shadow_GPR_Regs(unsigned &ValNo, MVT &ValVT,
28                                          MVT &LocVT,
29                                          CCValAssign::LocInfo &LocInfo,
30                                          ISD::ArgFlagsTy &ArgFlags,
31                                          CCState &State) {
32 
33   // The 64-bit ELFv2 ABI-defined parameter passing general purpose registers.
34   static const MCPhysReg ELF64ArgGPRs[] = {PPC::X3, PPC::X4, PPC::X5, PPC::X6,
35                                            PPC::X7, PPC::X8, PPC::X9, PPC::X10};
36   const unsigned ELF64NumArgGPRs = std::size(ELF64ArgGPRs);
37 
38   unsigned FirstUnallocGPR = State.getFirstUnallocated(ELF64ArgGPRs);
39   if (FirstUnallocGPR == ELF64NumArgGPRs)
40     return false;
41 
42   // As described in 2.2.4.1 under the "float" section, shadow a single GPR
43   // for single/double precision. ppcf128 gets broken up into two doubles
44   // and will also shadow GPRs within this section.
45   if (LocVT == MVT::f32 || LocVT == MVT::f64)
46     State.AllocateReg(ELF64ArgGPRs);
47   else if (LocVT.is128BitVector() || (LocVT == MVT::f128)) {
48     // For vector and __float128 (which is represents the "vector" section
49     // in 2.2.4.1), shadow two even GPRs (skipping the odd one if it is next
50     // in the allocation order). To check if the GPR is even, the specific
51     // condition checks if the register allocated is odd, because the even
52     // physical registers are odd values.
53     if ((State.AllocateReg(ELF64ArgGPRs) - PPC::X3) % 2 == 1)
54       State.AllocateReg(ELF64ArgGPRs);
55     State.AllocateReg(ELF64ArgGPRs);
56   }
57   return false;
58 }
59 
60 static bool CC_PPC32_SVR4_Custom_Dummy(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
61                                        CCValAssign::LocInfo &LocInfo,
62                                        ISD::ArgFlagsTy &ArgFlags,
63                                        CCState &State) {
64   return true;
65 }
66 
67 static bool CC_PPC32_SVR4_Custom_AlignArgRegs(unsigned &ValNo, MVT &ValVT,
68                                               MVT &LocVT,
69                                               CCValAssign::LocInfo &LocInfo,
70                                               ISD::ArgFlagsTy &ArgFlags,
71                                               CCState &State) {
72   static const MCPhysReg ArgRegs[] = {
73     PPC::R3, PPC::R4, PPC::R5, PPC::R6,
74     PPC::R7, PPC::R8, PPC::R9, PPC::R10,
75   };
76   const unsigned NumArgRegs = std::size(ArgRegs);
77 
78   unsigned RegNum = State.getFirstUnallocated(ArgRegs);
79 
80   // Skip one register if the first unallocated register has an even register
81   // number and there are still argument registers available which have not been
82   // allocated yet. RegNum is actually an index into ArgRegs, which means we
83   // need to skip a register if RegNum is odd.
84   if (RegNum != NumArgRegs && RegNum % 2 == 1) {
85     State.AllocateReg(ArgRegs[RegNum]);
86   }
87 
88   // Always return false here, as this function only makes sure that the first
89   // unallocated register has an odd register number and does not actually
90   // allocate a register for the current argument.
91   return false;
92 }
93 
94 static bool CC_PPC32_SVR4_Custom_SkipLastArgRegsPPCF128(
95     unsigned &ValNo, MVT &ValVT, MVT &LocVT, CCValAssign::LocInfo &LocInfo,
96     ISD::ArgFlagsTy &ArgFlags, CCState &State) {
97   static const MCPhysReg ArgRegs[] = {
98     PPC::R3, PPC::R4, PPC::R5, PPC::R6,
99     PPC::R7, PPC::R8, PPC::R9, PPC::R10,
100   };
101   const unsigned NumArgRegs = std::size(ArgRegs);
102 
103   unsigned RegNum = State.getFirstUnallocated(ArgRegs);
104   int RegsLeft = NumArgRegs - RegNum;
105 
106   // Skip if there is not enough registers left for long double type (4 gpr regs
107   // in soft float mode) and put long double argument on the stack.
108   if (RegNum != NumArgRegs && RegsLeft < 4) {
109     for (int i = 0; i < RegsLeft; i++) {
110       State.AllocateReg(ArgRegs[RegNum + i]);
111     }
112   }
113 
114   return false;
115 }
116 
117 static bool CC_PPC32_SVR4_Custom_AlignFPArgRegs(unsigned &ValNo, MVT &ValVT,
118                                                 MVT &LocVT,
119                                                 CCValAssign::LocInfo &LocInfo,
120                                                 ISD::ArgFlagsTy &ArgFlags,
121                                                 CCState &State) {
122   static const MCPhysReg ArgRegs[] = {
123     PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
124     PPC::F8
125   };
126 
127   const unsigned NumArgRegs = std::size(ArgRegs);
128 
129   unsigned RegNum = State.getFirstUnallocated(ArgRegs);
130 
131   // If there is only one Floating-point register left we need to put both f64
132   // values of a split ppc_fp128 value on the stack.
133   if (RegNum != NumArgRegs && ArgRegs[RegNum] == PPC::F8) {
134     State.AllocateReg(ArgRegs[RegNum]);
135   }
136 
137   // Always return false here, as this function only makes sure that the two f64
138   // values a ppc_fp128 value is split into are both passed in registers or both
139   // passed on the stack and does not actually allocate a register for the
140   // current argument.
141   return false;
142 }
143 
144 // Split F64 arguments into two 32-bit consecutive registers.
145 static bool CC_PPC32_SPE_CustomSplitFP64(unsigned &ValNo, MVT &ValVT,
146                                         MVT &LocVT,
147                                         CCValAssign::LocInfo &LocInfo,
148                                         ISD::ArgFlagsTy &ArgFlags,
149                                         CCState &State) {
150   static const MCPhysReg HiRegList[] = { PPC::R3, PPC::R5, PPC::R7, PPC::R9 };
151   static const MCPhysReg LoRegList[] = { PPC::R4, PPC::R6, PPC::R8, PPC::R10 };
152 
153   // Try to get the first register.
154   unsigned Reg = State.AllocateReg(HiRegList);
155   if (!Reg)
156     return false;
157 
158   unsigned i;
159   for (i = 0; i < std::size(HiRegList); ++i)
160     if (HiRegList[i] == Reg)
161       break;
162 
163   unsigned T = State.AllocateReg(LoRegList[i]);
164   (void)T;
165   assert(T == LoRegList[i] && "Could not allocate register");
166 
167   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
168   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
169                                          LocVT, LocInfo));
170   return true;
171 }
172 
173 // Same as above, but for return values, so only allocate for R3 and R4
174 static bool CC_PPC32_SPE_RetF64(unsigned &ValNo, MVT &ValVT,
175                                MVT &LocVT,
176                                CCValAssign::LocInfo &LocInfo,
177                                ISD::ArgFlagsTy &ArgFlags,
178                                CCState &State) {
179   static const MCPhysReg HiRegList[] = { PPC::R3 };
180   static const MCPhysReg LoRegList[] = { PPC::R4 };
181 
182   // Try to get the first register.
183   unsigned Reg = State.AllocateReg(HiRegList, LoRegList);
184   if (!Reg)
185     return false;
186 
187   unsigned i;
188   for (i = 0; i < std::size(HiRegList); ++i)
189     if (HiRegList[i] == Reg)
190       break;
191 
192   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
193   State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i],
194                                          LocVT, LocInfo));
195   return true;
196 }
197 
198 #include "PPCGenCallingConv.inc"
199