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(Regs: 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(Regs: 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(Regs: ELF64ArgGPRs) - PPC::X3) % 2 == 1) |
54 | State.AllocateReg(Regs: ELF64ArgGPRs); |
55 | State.AllocateReg(Regs: 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(Regs: 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(Reg: 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(Regs: 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(Reg: 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(Regs: 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(Reg: 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(Regs: 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(Reg: LoRegList[i]); |
164 | (void)T; |
165 | assert(T == LoRegList[i] && "Could not allocate register" ); |
166 | |
167 | State.addLoc(V: CCValAssign::getCustomReg(ValNo, ValVT, RegNo: Reg, LocVT, HTP: LocInfo)); |
168 | State.addLoc(V: CCValAssign::getCustomReg(ValNo, ValVT, RegNo: LoRegList[i], |
169 | LocVT, HTP: 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(Regs: HiRegList, ShadowRegs: 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(V: CCValAssign::getCustomReg(ValNo, ValVT, RegNo: Reg, LocVT, HTP: LocInfo)); |
193 | State.addLoc(V: CCValAssign::getCustomReg(ValNo, ValVT, RegNo: LoRegList[i], |
194 | LocVT, HTP: LocInfo)); |
195 | return true; |
196 | } |
197 | |
198 | #include "PPCGenCallingConv.inc" |
199 | |