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