1 | //===-- SparcFrameLowering.cpp - Sparc Frame Information ------------------===// |
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 | // This file contains the Sparc implementation of TargetFrameLowering class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "SparcFrameLowering.h" |
14 | #include "SparcInstrInfo.h" |
15 | #include "SparcMachineFunctionInfo.h" |
16 | #include "SparcSubtarget.h" |
17 | #include "llvm/CodeGen/CFIInstBuilder.h" |
18 | #include "llvm/CodeGen/MachineFrameInfo.h" |
19 | #include "llvm/CodeGen/MachineFunction.h" |
20 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
21 | #include "llvm/CodeGen/MachineModuleInfo.h" |
22 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
23 | #include "llvm/Support/CommandLine.h" |
24 | #include "llvm/Target/TargetOptions.h" |
25 | |
26 | using namespace llvm; |
27 | |
28 | static cl::opt<bool> |
29 | DisableLeafProc("disable-sparc-leaf-proc" , |
30 | cl::init(Val: false), |
31 | cl::desc("Disable Sparc leaf procedure optimization." ), |
32 | cl::Hidden); |
33 | |
34 | SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST) |
35 | : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, |
36 | ST.is64Bit() ? Align(16) : Align(8), 0, |
37 | ST.is64Bit() ? Align(16) : Align(8), |
38 | /*StackRealignable=*/false) {} |
39 | |
40 | void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF, |
41 | MachineBasicBlock &MBB, |
42 | MachineBasicBlock::iterator MBBI, |
43 | int NumBytes, |
44 | unsigned ADDrr, |
45 | unsigned ADDri) const { |
46 | |
47 | DebugLoc dl; |
48 | const SparcInstrInfo &TII = |
49 | *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
50 | |
51 | if (NumBytes >= -4096 && NumBytes < 4096) { |
52 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ADDri), DestReg: SP::O6) |
53 | .addReg(RegNo: SP::O6).addImm(Val: NumBytes); |
54 | return; |
55 | } |
56 | |
57 | // Emit this the hard way. This clobbers G1 which we always know is |
58 | // available here. |
59 | if (NumBytes >= 0) { |
60 | // Emit nonnegative numbers with sethi + or. |
61 | // sethi %hi(NumBytes), %g1 |
62 | // or %g1, %lo(NumBytes), %g1 |
63 | // add %sp, %g1, %sp |
64 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::SETHIi), DestReg: SP::G1) |
65 | .addImm(Val: HI22(imm: NumBytes)); |
66 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::ORri), DestReg: SP::G1) |
67 | .addReg(RegNo: SP::G1).addImm(Val: LO10(imm: NumBytes)); |
68 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ADDrr), DestReg: SP::O6) |
69 | .addReg(RegNo: SP::O6).addReg(RegNo: SP::G1); |
70 | return ; |
71 | } |
72 | |
73 | // Emit negative numbers with sethi + xor. |
74 | // sethi %hix(NumBytes), %g1 |
75 | // xor %g1, %lox(NumBytes), %g1 |
76 | // add %sp, %g1, %sp |
77 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::SETHIi), DestReg: SP::G1) |
78 | .addImm(Val: HIX22(imm: NumBytes)); |
79 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::XORri), DestReg: SP::G1) |
80 | .addReg(RegNo: SP::G1).addImm(Val: LOX10(imm: NumBytes)); |
81 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ADDrr), DestReg: SP::O6) |
82 | .addReg(RegNo: SP::O6).addReg(RegNo: SP::G1); |
83 | } |
84 | |
85 | void SparcFrameLowering::emitPrologue(MachineFunction &MF, |
86 | MachineBasicBlock &MBB) const { |
87 | SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>(); |
88 | |
89 | assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported" ); |
90 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
91 | const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>(); |
92 | MachineBasicBlock::iterator MBBI = MBB.begin(); |
93 | |
94 | // Get the number of bytes to allocate from the FrameInfo |
95 | int NumBytes = (int) MFI.getStackSize(); |
96 | |
97 | unsigned SAVEri = SP::SAVEri; |
98 | unsigned SAVErr = SP::SAVErr; |
99 | if (FuncInfo->isLeafProc()) { |
100 | if (NumBytes == 0) |
101 | return; |
102 | SAVEri = SP::ADDri; |
103 | SAVErr = SP::ADDrr; |
104 | } |
105 | |
106 | // The SPARC ABI is a bit odd in that it requires a reserved 92-byte |
107 | // (128 in v9) area in the user's stack, starting at %sp. Thus, the |
108 | // first part of the stack that can actually be used is located at |
109 | // %sp + 92. |
110 | // |
111 | // We therefore need to add that offset to the total stack size |
112 | // after all the stack objects are placed by |
113 | // PrologEpilogInserter calculateFrameObjectOffsets. However, since the stack needs to be |
114 | // aligned *after* the extra size is added, we need to disable |
115 | // calculateFrameObjectOffsets's built-in stack alignment, by having |
116 | // targetHandlesStackFrameRounding return true. |
117 | |
118 | |
119 | // Add the extra call frame stack size, if needed. (This is the same |
120 | // code as in PrologEpilogInserter, but also gets disabled by |
121 | // targetHandlesStackFrameRounding) |
122 | if (MFI.adjustsStack() && hasReservedCallFrame(MF)) |
123 | NumBytes += MFI.getMaxCallFrameSize(); |
124 | |
125 | // Adds the SPARC subtarget-specific spill area to the stack |
126 | // size. Also ensures target-required alignment. |
127 | NumBytes = Subtarget.getAdjustedFrameSize(stackSize: NumBytes); |
128 | |
129 | // Finally, ensure that the size is sufficiently aligned for the |
130 | // data on the stack. |
131 | NumBytes = alignTo(Size: NumBytes, A: MFI.getMaxAlign()); |
132 | |
133 | // Update stack size with corrected value. |
134 | MFI.setStackSize(NumBytes); |
135 | |
136 | emitSPAdjustment(MF, MBB, MBBI, NumBytes: -NumBytes, ADDrr: SAVErr, ADDri: SAVEri); |
137 | |
138 | if (MF.needsFrameMoves()) { |
139 | CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::NoFlags); |
140 | CFIBuilder.buildDefCFARegister(Reg: SP::I6); |
141 | CFIBuilder.buildWindowSave(); |
142 | CFIBuilder.buildRegister(Reg1: SP::O7, Reg2: SP::I7); |
143 | } |
144 | } |
145 | |
146 | MachineBasicBlock::iterator SparcFrameLowering:: |
147 | eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, |
148 | MachineBasicBlock::iterator I) const { |
149 | if (!hasReservedCallFrame(MF)) { |
150 | MachineInstr &MI = *I; |
151 | int Size = MI.getOperand(i: 0).getImm(); |
152 | if (MI.getOpcode() == SP::ADJCALLSTACKDOWN) |
153 | Size = -Size; |
154 | |
155 | if (Size) |
156 | emitSPAdjustment(MF, MBB, MBBI: I, NumBytes: Size, ADDrr: SP::ADDrr, ADDri: SP::ADDri); |
157 | } |
158 | return MBB.erase(I); |
159 | } |
160 | |
161 | |
162 | void SparcFrameLowering::emitEpilogue(MachineFunction &MF, |
163 | MachineBasicBlock &MBB) const { |
164 | SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>(); |
165 | MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); |
166 | const SparcInstrInfo &TII = |
167 | *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
168 | DebugLoc dl = MBBI->getDebugLoc(); |
169 | assert((MBBI->getOpcode() == SP::RETL || MBBI->getOpcode() == SP::TAIL_CALL || |
170 | MBBI->getOpcode() == SP::TAIL_CALLri) && |
171 | "Can only put epilog before 'retl' or 'tail_call' instruction!" ); |
172 | if (!FuncInfo->isLeafProc()) { |
173 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::RESTORErr), DestReg: SP::G0).addReg(RegNo: SP::G0) |
174 | .addReg(RegNo: SP::G0); |
175 | return; |
176 | } |
177 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
178 | |
179 | int NumBytes = (int) MFI.getStackSize(); |
180 | if (NumBytes != 0) |
181 | emitSPAdjustment(MF, MBB, MBBI, NumBytes, ADDrr: SP::ADDrr, ADDri: SP::ADDri); |
182 | |
183 | // Preserve return address in %o7 |
184 | if (MBBI->getOpcode() == SP::TAIL_CALL) { |
185 | MBB.addLiveIn(PhysReg: SP::O7); |
186 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::ORrr), DestReg: SP::G1) |
187 | .addReg(RegNo: SP::G0) |
188 | .addReg(RegNo: SP::O7); |
189 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: SP::ORrr), DestReg: SP::O7) |
190 | .addReg(RegNo: SP::G0) |
191 | .addReg(RegNo: SP::G1); |
192 | } |
193 | } |
194 | |
195 | bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { |
196 | // Reserve call frame if there are no variable sized objects on the stack. |
197 | return !MF.getFrameInfo().hasVarSizedObjects(); |
198 | } |
199 | |
200 | // hasFPImpl - Return true if the specified function should have a dedicated |
201 | // frame pointer register. This is true if the function has variable sized |
202 | // allocas or if frame pointer elimination is disabled. |
203 | bool SparcFrameLowering::hasFPImpl(const MachineFunction &MF) const { |
204 | const MachineFrameInfo &MFI = MF.getFrameInfo(); |
205 | return MF.getTarget().Options.DisableFramePointerElim(MF) || |
206 | MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken(); |
207 | } |
208 | |
209 | StackOffset |
210 | SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, |
211 | Register &FrameReg) const { |
212 | const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>(); |
213 | const MachineFrameInfo &MFI = MF.getFrameInfo(); |
214 | const SparcRegisterInfo *RegInfo = Subtarget.getRegisterInfo(); |
215 | const SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>(); |
216 | bool isFixed = MFI.isFixedObjectIndex(ObjectIdx: FI); |
217 | |
218 | // Addressable stack objects are accessed using neg. offsets from |
219 | // %fp, or positive offsets from %sp. |
220 | bool UseFP; |
221 | |
222 | // Sparc uses FP-based references in general, even when "hasFP" is |
223 | // false. That function is rather a misnomer, because %fp is |
224 | // actually always available, unless isLeafProc. |
225 | if (FuncInfo->isLeafProc()) { |
226 | // If there's a leaf proc, all offsets need to be %sp-based, |
227 | // because we haven't caused %fp to actually point to our frame. |
228 | UseFP = false; |
229 | } else if (isFixed) { |
230 | // Otherwise, argument access should always use %fp. |
231 | UseFP = true; |
232 | } else { |
233 | // Finally, default to using %fp. |
234 | UseFP = true; |
235 | } |
236 | |
237 | int64_t FrameOffset = MF.getFrameInfo().getObjectOffset(ObjectIdx: FI) + |
238 | Subtarget.getStackPointerBias(); |
239 | |
240 | if (UseFP) { |
241 | FrameReg = RegInfo->getFrameRegister(MF); |
242 | return StackOffset::getFixed(Fixed: FrameOffset); |
243 | } else { |
244 | FrameReg = SP::O6; // %sp |
245 | return StackOffset::getFixed(Fixed: FrameOffset + MF.getFrameInfo().getStackSize()); |
246 | } |
247 | } |
248 | |
249 | static bool LLVM_ATTRIBUTE_UNUSED verifyLeafProcRegUse(MachineRegisterInfo *MRI) |
250 | { |
251 | |
252 | for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) |
253 | if (MRI->isPhysRegUsed(PhysReg: reg)) |
254 | return false; |
255 | |
256 | for (unsigned reg = SP::L0; reg <= SP::L7; ++reg) |
257 | if (MRI->isPhysRegUsed(PhysReg: reg)) |
258 | return false; |
259 | |
260 | return true; |
261 | } |
262 | |
263 | bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const |
264 | { |
265 | |
266 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
267 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
268 | |
269 | return !(MFI.hasCalls() // has calls |
270 | || MRI.isPhysRegUsed(PhysReg: SP::L0) // Too many registers needed |
271 | || MRI.isPhysRegUsed(PhysReg: SP::O6) // %sp is used |
272 | || hasFP(MF) // need %fp |
273 | || MF.hasInlineAsm()); // has inline assembly |
274 | } |
275 | |
276 | void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const { |
277 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
278 | // Remap %i[0-7] to %o[0-7]. |
279 | for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) { |
280 | if (!MRI.isPhysRegUsed(PhysReg: reg)) |
281 | continue; |
282 | |
283 | unsigned mapped_reg = reg - SP::I0 + SP::O0; |
284 | |
285 | // Replace I register with O register. |
286 | MRI.replaceRegWith(FromReg: reg, ToReg: mapped_reg); |
287 | |
288 | // Also replace register pair super-registers. |
289 | if ((reg - SP::I0) % 2 == 0) { |
290 | unsigned preg = (reg - SP::I0) / 2 + SP::I0_I1; |
291 | unsigned mapped_preg = preg - SP::I0_I1 + SP::O0_O1; |
292 | MRI.replaceRegWith(FromReg: preg, ToReg: mapped_preg); |
293 | } |
294 | } |
295 | |
296 | // Rewrite MBB's Live-ins. |
297 | for (MachineBasicBlock &MBB : MF) { |
298 | for (unsigned reg = SP::I0_I1; reg <= SP::I6_I7; ++reg) { |
299 | if (!MBB.isLiveIn(Reg: reg)) |
300 | continue; |
301 | MBB.removeLiveIn(Reg: reg); |
302 | MBB.addLiveIn(PhysReg: reg - SP::I0_I1 + SP::O0_O1); |
303 | } |
304 | for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) { |
305 | if (!MBB.isLiveIn(Reg: reg)) |
306 | continue; |
307 | MBB.removeLiveIn(Reg: reg); |
308 | MBB.addLiveIn(PhysReg: reg - SP::I0 + SP::O0); |
309 | } |
310 | } |
311 | |
312 | assert(verifyLeafProcRegUse(&MRI)); |
313 | #ifdef EXPENSIVE_CHECKS |
314 | MF.verify(0, "After LeafProc Remapping" ); |
315 | #endif |
316 | } |
317 | |
318 | void SparcFrameLowering::determineCalleeSaves(MachineFunction &MF, |
319 | BitVector &SavedRegs, |
320 | RegScavenger *RS) const { |
321 | TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); |
322 | if (!DisableLeafProc && isLeafProc(MF)) { |
323 | SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>(); |
324 | MFI->setLeafProc(true); |
325 | |
326 | remapRegsForLeafProc(MF); |
327 | } |
328 | |
329 | } |
330 | |