| 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 | |