| 1 | //===-- XCoreFrameLowering.cpp - Frame info for XCore Target --------------===// |
| 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 XCore frame information that doesn't fit anywhere else |
| 10 | // cleanly... |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "XCoreFrameLowering.h" |
| 15 | #include "XCoreInstrInfo.h" |
| 16 | #include "XCoreMachineFunctionInfo.h" |
| 17 | #include "XCoreSubtarget.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/CodeGen/RegisterScavenging.h" |
| 24 | #include "llvm/CodeGen/TargetLowering.h" |
| 25 | #include "llvm/IR/Function.h" |
| 26 | #include "llvm/Support/ErrorHandling.h" |
| 27 | #include "llvm/Target/TargetOptions.h" |
| 28 | #include <algorithm> |
| 29 | |
| 30 | using namespace llvm; |
| 31 | |
| 32 | static const unsigned FramePtr = XCore::R10; |
| 33 | static const int MaxImmU16 = (1<<16) - 1; |
| 34 | |
| 35 | // helper functions. FIXME: Eliminate. |
| 36 | static inline bool isImmU6(unsigned val) { |
| 37 | return val < (1 << 6); |
| 38 | } |
| 39 | |
| 40 | static inline bool isImmU16(unsigned val) { |
| 41 | return val < (1 << 16); |
| 42 | } |
| 43 | |
| 44 | // Helper structure with compare function for handling stack slots. |
| 45 | namespace { |
| 46 | struct StackSlotInfo { |
| 47 | int FI; |
| 48 | int Offset; |
| 49 | unsigned Reg; |
| 50 | StackSlotInfo(int f, int o, int r) : FI(f), Offset(o), Reg(r){}; |
| 51 | }; |
| 52 | } // end anonymous namespace |
| 53 | |
| 54 | static bool CompareSSIOffset(const StackSlotInfo& a, const StackSlotInfo& b) { |
| 55 | return a.Offset < b.Offset; |
| 56 | } |
| 57 | |
| 58 | static void EmitDefCfaRegister(MachineBasicBlock &MBB, |
| 59 | MachineBasicBlock::iterator MBBI, |
| 60 | const DebugLoc &dl, const TargetInstrInfo &TII, |
| 61 | MachineFunction &MF, unsigned DRegNum) { |
| 62 | unsigned CFIIndex = MF.addFrameInst( |
| 63 | Inst: MCCFIInstruction::createDefCfaRegister(L: nullptr, Register: DRegNum)); |
| 64 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: TargetOpcode::CFI_INSTRUCTION)) |
| 65 | .addCFIIndex(CFIIndex); |
| 66 | } |
| 67 | |
| 68 | static void EmitDefCfaOffset(MachineBasicBlock &MBB, |
| 69 | MachineBasicBlock::iterator MBBI, |
| 70 | const DebugLoc &dl, const TargetInstrInfo &TII, |
| 71 | int Offset) { |
| 72 | MachineFunction &MF = *MBB.getParent(); |
| 73 | unsigned CFIIndex = |
| 74 | MF.addFrameInst(Inst: MCCFIInstruction::cfiDefCfaOffset(L: nullptr, Offset)); |
| 75 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: TargetOpcode::CFI_INSTRUCTION)) |
| 76 | .addCFIIndex(CFIIndex); |
| 77 | } |
| 78 | |
| 79 | static void EmitCfiOffset(MachineBasicBlock &MBB, |
| 80 | MachineBasicBlock::iterator MBBI, const DebugLoc &dl, |
| 81 | const TargetInstrInfo &TII, unsigned DRegNum, |
| 82 | int Offset) { |
| 83 | MachineFunction &MF = *MBB.getParent(); |
| 84 | unsigned CFIIndex = MF.addFrameInst( |
| 85 | Inst: MCCFIInstruction::createOffset(L: nullptr, Register: DRegNum, Offset)); |
| 86 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: TargetOpcode::CFI_INSTRUCTION)) |
| 87 | .addCFIIndex(CFIIndex); |
| 88 | } |
| 89 | |
| 90 | /// The SP register is moved in steps of 'MaxImmU16' towards the bottom of the |
| 91 | /// frame. During these steps, it may be necessary to spill registers. |
| 92 | /// IfNeededExtSP emits the necessary EXTSP instructions to move the SP only |
| 93 | /// as far as to make 'OffsetFromBottom' reachable using an STWSP_lru6. |
| 94 | /// \param OffsetFromTop the spill offset from the top of the frame. |
| 95 | /// \param [in,out] Adjusted the current SP offset from the top of the frame. |
| 96 | static void IfNeededExtSP(MachineBasicBlock &MBB, |
| 97 | MachineBasicBlock::iterator MBBI, const DebugLoc &dl, |
| 98 | const TargetInstrInfo &TII, int OffsetFromTop, |
| 99 | int &Adjusted, int FrameSize, bool emitFrameMoves) { |
| 100 | while (OffsetFromTop > Adjusted) { |
| 101 | assert(Adjusted < FrameSize && "OffsetFromTop is beyond FrameSize" ); |
| 102 | int remaining = FrameSize - Adjusted; |
| 103 | int OpImm = (remaining > MaxImmU16) ? MaxImmU16 : remaining; |
| 104 | int Opcode = isImmU6(val: OpImm) ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; |
| 105 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode)).addImm(Val: OpImm); |
| 106 | Adjusted += OpImm; |
| 107 | if (emitFrameMoves) |
| 108 | EmitDefCfaOffset(MBB, MBBI, dl, TII, Offset: Adjusted*4); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | /// The SP register is moved in steps of 'MaxImmU16' towards the top of the |
| 113 | /// frame. During these steps, it may be necessary to re-load registers. |
| 114 | /// IfNeededLDAWSP emits the necessary LDAWSP instructions to move the SP only |
| 115 | /// as far as to make 'OffsetFromTop' reachable using an LDAWSP_lru6. |
| 116 | /// \param OffsetFromTop the spill offset from the top of the frame. |
| 117 | /// \param [in,out] RemainingAdj the current SP offset from the top of the |
| 118 | /// frame. |
| 119 | static void IfNeededLDAWSP(MachineBasicBlock &MBB, |
| 120 | MachineBasicBlock::iterator MBBI, const DebugLoc &dl, |
| 121 | const TargetInstrInfo &TII, int OffsetFromTop, |
| 122 | int &RemainingAdj) { |
| 123 | while (OffsetFromTop < RemainingAdj - MaxImmU16) { |
| 124 | assert(RemainingAdj && "OffsetFromTop is beyond FrameSize" ); |
| 125 | int OpImm = (RemainingAdj > MaxImmU16) ? MaxImmU16 : RemainingAdj; |
| 126 | int Opcode = isImmU6(val: OpImm) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; |
| 127 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode), DestReg: XCore::SP).addImm(Val: OpImm); |
| 128 | RemainingAdj -= OpImm; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | /// Creates an ordered list of registers that are spilled |
| 133 | /// during the emitPrologue/emitEpilogue. |
| 134 | /// Registers are ordered according to their frame offset. |
| 135 | /// As offsets are negative, the largest offsets will be first. |
| 136 | static void GetSpillList(SmallVectorImpl<StackSlotInfo> &SpillList, |
| 137 | MachineFrameInfo &MFI, XCoreFunctionInfo *XFI, |
| 138 | bool fetchLR, bool fetchFP) { |
| 139 | if (fetchLR) { |
| 140 | int Offset = MFI.getObjectOffset(ObjectIdx: XFI->getLRSpillSlot()); |
| 141 | SpillList.push_back(Elt: StackSlotInfo(XFI->getLRSpillSlot(), |
| 142 | Offset, |
| 143 | XCore::LR)); |
| 144 | } |
| 145 | if (fetchFP) { |
| 146 | int Offset = MFI.getObjectOffset(ObjectIdx: XFI->getFPSpillSlot()); |
| 147 | SpillList.push_back(Elt: StackSlotInfo(XFI->getFPSpillSlot(), |
| 148 | Offset, |
| 149 | FramePtr)); |
| 150 | } |
| 151 | llvm::sort(C&: SpillList, Comp: CompareSSIOffset); |
| 152 | } |
| 153 | |
| 154 | /// Creates an ordered list of EH info register 'spills'. |
| 155 | /// These slots are only used by the unwinder and calls to llvm.eh.return(). |
| 156 | /// Registers are ordered according to their frame offset. |
| 157 | /// As offsets are negative, the largest offsets will be first. |
| 158 | static void GetEHSpillList(SmallVectorImpl<StackSlotInfo> &SpillList, |
| 159 | MachineFrameInfo &MFI, XCoreFunctionInfo *XFI, |
| 160 | const Constant *PersonalityFn, |
| 161 | const TargetLowering *TL) { |
| 162 | assert(XFI->hasEHSpillSlot() && "There are no EH register spill slots" ); |
| 163 | const int *EHSlot = XFI->getEHSpillSlot(); |
| 164 | SpillList.push_back( |
| 165 | Elt: StackSlotInfo(EHSlot[0], MFI.getObjectOffset(ObjectIdx: EHSlot[0]), |
| 166 | TL->getExceptionPointerRegister(PersonalityFn))); |
| 167 | SpillList.push_back( |
| 168 | Elt: StackSlotInfo(EHSlot[0], MFI.getObjectOffset(ObjectIdx: EHSlot[1]), |
| 169 | TL->getExceptionSelectorRegister(PersonalityFn))); |
| 170 | llvm::sort(C&: SpillList, Comp: CompareSSIOffset); |
| 171 | } |
| 172 | |
| 173 | static MachineMemOperand *getFrameIndexMMO(MachineBasicBlock &MBB, |
| 174 | int FrameIndex, |
| 175 | MachineMemOperand::Flags flags) { |
| 176 | MachineFunction *MF = MBB.getParent(); |
| 177 | const MachineFrameInfo &MFI = MF->getFrameInfo(); |
| 178 | MachineMemOperand *MMO = MF->getMachineMemOperand( |
| 179 | PtrInfo: MachinePointerInfo::getFixedStack(MF&: *MF, FI: FrameIndex), F: flags, |
| 180 | Size: MFI.getObjectSize(ObjectIdx: FrameIndex), BaseAlignment: MFI.getObjectAlign(ObjectIdx: FrameIndex)); |
| 181 | return MMO; |
| 182 | } |
| 183 | |
| 184 | |
| 185 | /// Restore clobbered registers with their spill slot value. |
| 186 | /// The SP will be adjusted at the same time, thus the SpillList must be ordered |
| 187 | /// with the largest (negative) offsets first. |
| 188 | static void RestoreSpillList(MachineBasicBlock &MBB, |
| 189 | MachineBasicBlock::iterator MBBI, |
| 190 | const DebugLoc &dl, const TargetInstrInfo &TII, |
| 191 | int &RemainingAdj, |
| 192 | SmallVectorImpl<StackSlotInfo> &SpillList) { |
| 193 | for (unsigned i = 0, e = SpillList.size(); i != e; ++i) { |
| 194 | assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset" ); |
| 195 | assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset" ); |
| 196 | int OffsetFromTop = - SpillList[i].Offset/4; |
| 197 | IfNeededLDAWSP(MBB, MBBI, dl, TII, OffsetFromTop, RemainingAdj); |
| 198 | int Offset = RemainingAdj - OffsetFromTop; |
| 199 | int Opcode = isImmU6(val: Offset) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; |
| 200 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode), DestReg: SpillList[i].Reg) |
| 201 | .addImm(Val: Offset) |
| 202 | .addMemOperand(MMO: getFrameIndexMMO(MBB, FrameIndex: SpillList[i].FI, |
| 203 | flags: MachineMemOperand::MOLoad)); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | //===----------------------------------------------------------------------===// |
| 208 | // XCoreFrameLowering: |
| 209 | //===----------------------------------------------------------------------===// |
| 210 | |
| 211 | XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti) |
| 212 | : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0) { |
| 213 | // Do nothing |
| 214 | } |
| 215 | |
| 216 | bool XCoreFrameLowering::hasFPImpl(const MachineFunction &MF) const { |
| 217 | return MF.getTarget().Options.DisableFramePointerElim(MF) || |
| 218 | MF.getFrameInfo().hasVarSizedObjects(); |
| 219 | } |
| 220 | |
| 221 | void XCoreFrameLowering::emitPrologue(MachineFunction &MF, |
| 222 | MachineBasicBlock &MBB) const { |
| 223 | assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported" ); |
| 224 | MachineBasicBlock::iterator MBBI = MBB.begin(); |
| 225 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
| 226 | const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo(); |
| 227 | const XCoreInstrInfo &TII = *MF.getSubtarget<XCoreSubtarget>().getInstrInfo(); |
| 228 | XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); |
| 229 | // Debug location must be unknown since the first debug location is used |
| 230 | // to determine the end of the prologue. |
| 231 | DebugLoc dl; |
| 232 | |
| 233 | if (MFI.getMaxAlign() > getStackAlign()) |
| 234 | report_fatal_error(reason: "emitPrologue unsupported alignment: " + |
| 235 | Twine(MFI.getMaxAlign().value())); |
| 236 | |
| 237 | const AttributeList &PAL = MF.getFunction().getAttributes(); |
| 238 | if (PAL.hasAttrSomewhere(Kind: Attribute::Nest)) |
| 239 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: XCore::LDWSP_ru6), DestReg: XCore::R11).addImm(Val: 0); |
| 240 | // FIX: Needs addMemOperand() but can't use getFixedStack() or getStack(). |
| 241 | |
| 242 | // Work out frame sizes. |
| 243 | // We will adjust the SP in stages towards the final FrameSize. |
| 244 | assert(MFI.getStackSize()%4 == 0 && "Misaligned frame size" ); |
| 245 | const int FrameSize = MFI.getStackSize() / 4; |
| 246 | int Adjusted = 0; |
| 247 | |
| 248 | bool saveLR = XFI->hasLRSpillSlot(); |
| 249 | bool UseENTSP = saveLR && FrameSize |
| 250 | && (MFI.getObjectOffset(ObjectIdx: XFI->getLRSpillSlot()) == 0); |
| 251 | if (UseENTSP) |
| 252 | saveLR = false; |
| 253 | bool FP = hasFP(MF); |
| 254 | bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(MF); |
| 255 | |
| 256 | if (UseENTSP) { |
| 257 | // Allocate space on the stack at the same time as saving LR. |
| 258 | Adjusted = (FrameSize > MaxImmU16) ? MaxImmU16 : FrameSize; |
| 259 | int Opcode = isImmU6(val: Adjusted) ? XCore::ENTSP_u6 : XCore::ENTSP_lu6; |
| 260 | MBB.addLiveIn(PhysReg: XCore::LR); |
| 261 | MachineInstrBuilder MIB = BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode)); |
| 262 | MIB.addImm(Val: Adjusted); |
| 263 | MIB->addRegisterKilled(IncomingReg: XCore::LR, RegInfo: MF.getSubtarget().getRegisterInfo(), |
| 264 | AddIfNotFound: true); |
| 265 | if (emitFrameMoves) { |
| 266 | EmitDefCfaOffset(MBB, MBBI, dl, TII, Offset: Adjusted*4); |
| 267 | unsigned DRegNum = MRI->getDwarfRegNum(RegNum: XCore::LR, isEH: true); |
| 268 | EmitCfiOffset(MBB, MBBI, dl, TII, DRegNum, Offset: 0); |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | // If necessary, save LR and FP to the stack, as we EXTSP. |
| 273 | SmallVector<StackSlotInfo,2> SpillList; |
| 274 | GetSpillList(SpillList, MFI, XFI, fetchLR: saveLR, fetchFP: FP); |
| 275 | // We want the nearest (negative) offsets first, so reverse list. |
| 276 | std::reverse(first: SpillList.begin(), last: SpillList.end()); |
| 277 | for (unsigned i = 0, e = SpillList.size(); i != e; ++i) { |
| 278 | assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset" ); |
| 279 | assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset" ); |
| 280 | int OffsetFromTop = - SpillList[i].Offset/4; |
| 281 | IfNeededExtSP(MBB, MBBI, dl, TII, OffsetFromTop, Adjusted, FrameSize, |
| 282 | emitFrameMoves); |
| 283 | int Offset = Adjusted - OffsetFromTop; |
| 284 | int Opcode = isImmU6(val: Offset) ? XCore::STWSP_ru6 : XCore::STWSP_lru6; |
| 285 | MBB.addLiveIn(PhysReg: SpillList[i].Reg); |
| 286 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode)) |
| 287 | .addReg(RegNo: SpillList[i].Reg, flags: RegState::Kill) |
| 288 | .addImm(Val: Offset) |
| 289 | .addMemOperand(MMO: getFrameIndexMMO(MBB, FrameIndex: SpillList[i].FI, |
| 290 | flags: MachineMemOperand::MOStore)); |
| 291 | if (emitFrameMoves) { |
| 292 | unsigned DRegNum = MRI->getDwarfRegNum(RegNum: SpillList[i].Reg, isEH: true); |
| 293 | EmitCfiOffset(MBB, MBBI, dl, TII, DRegNum, Offset: SpillList[i].Offset); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | // Complete any remaining Stack adjustment. |
| 298 | IfNeededExtSP(MBB, MBBI, dl, TII, OffsetFromTop: FrameSize, Adjusted, FrameSize, |
| 299 | emitFrameMoves); |
| 300 | assert(Adjusted==FrameSize && "IfNeededExtSP has not completed adjustment" ); |
| 301 | |
| 302 | if (FP) { |
| 303 | // Set the FP from the SP. |
| 304 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: XCore::LDAWSP_ru6), DestReg: FramePtr).addImm(Val: 0); |
| 305 | if (emitFrameMoves) |
| 306 | EmitDefCfaRegister(MBB, MBBI, dl, TII, MF, |
| 307 | DRegNum: MRI->getDwarfRegNum(RegNum: FramePtr, isEH: true)); |
| 308 | } |
| 309 | |
| 310 | if (emitFrameMoves) { |
| 311 | // Frame moves for callee saved. |
| 312 | for (const auto &SpillLabel : XFI->getSpillLabels()) { |
| 313 | MachineBasicBlock::iterator Pos = SpillLabel.first; |
| 314 | ++Pos; |
| 315 | const CalleeSavedInfo &CSI = SpillLabel.second; |
| 316 | int Offset = MFI.getObjectOffset(ObjectIdx: CSI.getFrameIdx()); |
| 317 | unsigned DRegNum = MRI->getDwarfRegNum(RegNum: CSI.getReg(), isEH: true); |
| 318 | EmitCfiOffset(MBB, MBBI: Pos, dl, TII, DRegNum, Offset); |
| 319 | } |
| 320 | if (XFI->hasEHSpillSlot()) { |
| 321 | // The unwinder requires stack slot & CFI offsets for the exception info. |
| 322 | // We do not save/spill these registers. |
| 323 | const Function *Fn = &MF.getFunction(); |
| 324 | const Constant *PersonalityFn = |
| 325 | Fn->hasPersonalityFn() ? Fn->getPersonalityFn() : nullptr; |
| 326 | SmallVector<StackSlotInfo, 2> SpillList; |
| 327 | GetEHSpillList(SpillList, MFI, XFI, PersonalityFn, |
| 328 | TL: MF.getSubtarget().getTargetLowering()); |
| 329 | assert(SpillList.size()==2 && "Unexpected SpillList size" ); |
| 330 | EmitCfiOffset(MBB, MBBI, dl, TII, |
| 331 | DRegNum: MRI->getDwarfRegNum(RegNum: SpillList[0].Reg, isEH: true), |
| 332 | Offset: SpillList[0].Offset); |
| 333 | EmitCfiOffset(MBB, MBBI, dl, TII, |
| 334 | DRegNum: MRI->getDwarfRegNum(RegNum: SpillList[1].Reg, isEH: true), |
| 335 | Offset: SpillList[1].Offset); |
| 336 | } |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | void XCoreFrameLowering::emitEpilogue(MachineFunction &MF, |
| 341 | MachineBasicBlock &MBB) const { |
| 342 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
| 343 | MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); |
| 344 | const XCoreInstrInfo &TII = *MF.getSubtarget<XCoreSubtarget>().getInstrInfo(); |
| 345 | XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); |
| 346 | DebugLoc dl = MBBI->getDebugLoc(); |
| 347 | unsigned RetOpcode = MBBI->getOpcode(); |
| 348 | |
| 349 | // Work out frame sizes. |
| 350 | // We will adjust the SP in stages towards the final FrameSize. |
| 351 | int RemainingAdj = MFI.getStackSize(); |
| 352 | assert(RemainingAdj%4 == 0 && "Misaligned frame size" ); |
| 353 | RemainingAdj /= 4; |
| 354 | |
| 355 | if (RetOpcode == XCore::EH_RETURN) { |
| 356 | // 'Restore' the exception info the unwinder has placed into the stack |
| 357 | // slots. |
| 358 | const Function *Fn = &MF.getFunction(); |
| 359 | const Constant *PersonalityFn = |
| 360 | Fn->hasPersonalityFn() ? Fn->getPersonalityFn() : nullptr; |
| 361 | SmallVector<StackSlotInfo, 2> SpillList; |
| 362 | GetEHSpillList(SpillList, MFI, XFI, PersonalityFn, |
| 363 | TL: MF.getSubtarget().getTargetLowering()); |
| 364 | RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList); |
| 365 | |
| 366 | // Return to the landing pad. |
| 367 | Register EhStackReg = MBBI->getOperand(i: 0).getReg(); |
| 368 | Register EhHandlerReg = MBBI->getOperand(i: 1).getReg(); |
| 369 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: XCore::SETSP_1r)).addReg(RegNo: EhStackReg); |
| 370 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: XCore::BAU_1r)).addReg(RegNo: EhHandlerReg); |
| 371 | MBB.erase(I: MBBI); // Erase the previous return instruction. |
| 372 | return; |
| 373 | } |
| 374 | |
| 375 | bool restoreLR = XFI->hasLRSpillSlot(); |
| 376 | bool UseRETSP = restoreLR && RemainingAdj |
| 377 | && (MFI.getObjectOffset(ObjectIdx: XFI->getLRSpillSlot()) == 0); |
| 378 | if (UseRETSP) |
| 379 | restoreLR = false; |
| 380 | bool FP = hasFP(MF); |
| 381 | |
| 382 | if (FP) // Restore the stack pointer. |
| 383 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: XCore::SETSP_1r)).addReg(RegNo: FramePtr); |
| 384 | |
| 385 | // If necessary, restore LR and FP from the stack, as we EXTSP. |
| 386 | SmallVector<StackSlotInfo,2> SpillList; |
| 387 | GetSpillList(SpillList, MFI, XFI, fetchLR: restoreLR, fetchFP: FP); |
| 388 | RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList); |
| 389 | |
| 390 | if (RemainingAdj) { |
| 391 | // Complete all but one of the remaining Stack adjustments. |
| 392 | IfNeededLDAWSP(MBB, MBBI, dl, TII, OffsetFromTop: 0, RemainingAdj); |
| 393 | if (UseRETSP) { |
| 394 | // Fold prologue into return instruction |
| 395 | assert(RetOpcode == XCore::RETSP_u6 |
| 396 | || RetOpcode == XCore::RETSP_lu6); |
| 397 | int Opcode = isImmU6(val: RemainingAdj) ? XCore::RETSP_u6 : XCore::RETSP_lu6; |
| 398 | MachineInstrBuilder MIB = BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode)) |
| 399 | .addImm(Val: RemainingAdj); |
| 400 | for (unsigned i = 3, e = MBBI->getNumOperands(); i < e; ++i) |
| 401 | MIB->addOperand(Op: MBBI->getOperand(i)); // copy any variadic operands |
| 402 | MBB.erase(I: MBBI); // Erase the previous return instruction. |
| 403 | } else { |
| 404 | int Opcode = isImmU6(val: RemainingAdj) ? XCore::LDAWSP_ru6 : |
| 405 | XCore::LDAWSP_lru6; |
| 406 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode), DestReg: XCore::SP).addImm(Val: RemainingAdj); |
| 407 | // Don't erase the return instruction. |
| 408 | } |
| 409 | } // else Don't erase the return instruction. |
| 410 | } |
| 411 | |
| 412 | bool XCoreFrameLowering::spillCalleeSavedRegisters( |
| 413 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
| 414 | ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { |
| 415 | if (CSI.empty()) |
| 416 | return true; |
| 417 | |
| 418 | MachineFunction *MF = MBB.getParent(); |
| 419 | const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); |
| 420 | XCoreFunctionInfo *XFI = MF->getInfo<XCoreFunctionInfo>(); |
| 421 | bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(MF: *MF); |
| 422 | |
| 423 | DebugLoc DL; |
| 424 | if (MI != MBB.end() && !MI->isDebugInstr()) |
| 425 | DL = MI->getDebugLoc(); |
| 426 | |
| 427 | for (const CalleeSavedInfo &I : CSI) { |
| 428 | MCRegister Reg = I.getReg(); |
| 429 | assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) && |
| 430 | "LR & FP are always handled in emitPrologue" ); |
| 431 | |
| 432 | // Add the callee-saved register as live-in. It's killed at the spill. |
| 433 | MBB.addLiveIn(PhysReg: Reg); |
| 434 | const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); |
| 435 | TII.storeRegToStackSlot(MBB, MI, SrcReg: Reg, isKill: true, FrameIndex: I.getFrameIdx(), RC, TRI, |
| 436 | VReg: Register()); |
| 437 | if (emitFrameMoves) { |
| 438 | auto Store = MI; |
| 439 | --Store; |
| 440 | XFI->getSpillLabels().push_back(x: std::make_pair(x&: Store, y: I)); |
| 441 | } |
| 442 | } |
| 443 | return true; |
| 444 | } |
| 445 | |
| 446 | bool XCoreFrameLowering::restoreCalleeSavedRegisters( |
| 447 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
| 448 | MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { |
| 449 | MachineFunction *MF = MBB.getParent(); |
| 450 | const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); |
| 451 | bool AtStart = MI == MBB.begin(); |
| 452 | MachineBasicBlock::iterator BeforeI = MI; |
| 453 | if (!AtStart) |
| 454 | --BeforeI; |
| 455 | for (const CalleeSavedInfo &CSR : CSI) { |
| 456 | MCRegister Reg = CSR.getReg(); |
| 457 | assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) && |
| 458 | "LR & FP are always handled in emitEpilogue" ); |
| 459 | |
| 460 | const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); |
| 461 | TII.loadRegFromStackSlot(MBB, MI, DestReg: Reg, FrameIndex: CSR.getFrameIdx(), RC, TRI, |
| 462 | VReg: Register()); |
| 463 | assert(MI != MBB.begin() && |
| 464 | "loadRegFromStackSlot didn't insert any code!" ); |
| 465 | // Insert in reverse order. loadRegFromStackSlot can insert multiple |
| 466 | // instructions. |
| 467 | if (AtStart) |
| 468 | MI = MBB.begin(); |
| 469 | else { |
| 470 | MI = BeforeI; |
| 471 | ++MI; |
| 472 | } |
| 473 | } |
| 474 | return true; |
| 475 | } |
| 476 | |
| 477 | // This function eliminates ADJCALLSTACKDOWN, |
| 478 | // ADJCALLSTACKUP pseudo instructions |
| 479 | MachineBasicBlock::iterator XCoreFrameLowering::eliminateCallFramePseudoInstr( |
| 480 | MachineFunction &MF, MachineBasicBlock &MBB, |
| 481 | MachineBasicBlock::iterator I) const { |
| 482 | const XCoreInstrInfo &TII = *MF.getSubtarget<XCoreSubtarget>().getInstrInfo(); |
| 483 | if (!hasReservedCallFrame(MF)) { |
| 484 | // Turn the adjcallstackdown instruction into 'extsp <amt>' and the |
| 485 | // adjcallstackup instruction into 'ldaw sp, sp[<amt>]' |
| 486 | MachineInstr &Old = *I; |
| 487 | uint64_t Amount = Old.getOperand(i: 0).getImm(); |
| 488 | if (Amount != 0) { |
| 489 | // We need to keep the stack aligned properly. To do this, we round the |
| 490 | // amount of space needed for the outgoing arguments up to the next |
| 491 | // alignment boundary. |
| 492 | Amount = alignTo(Size: Amount, A: getStackAlign()); |
| 493 | |
| 494 | assert(Amount%4 == 0); |
| 495 | Amount /= 4; |
| 496 | |
| 497 | bool isU6 = isImmU6(val: Amount); |
| 498 | if (!isU6 && !isImmU16(val: Amount)) { |
| 499 | // FIX could emit multiple instructions in this case. |
| 500 | #ifndef NDEBUG |
| 501 | errs() << "eliminateCallFramePseudoInstr size too big: " |
| 502 | << Amount << "\n" ; |
| 503 | #endif |
| 504 | llvm_unreachable(nullptr); |
| 505 | } |
| 506 | |
| 507 | MachineInstr *New; |
| 508 | if (Old.getOpcode() == XCore::ADJCALLSTACKDOWN) { |
| 509 | int Opcode = isU6 ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; |
| 510 | New = BuildMI(MF, MIMD: Old.getDebugLoc(), MCID: TII.get(Opcode)).addImm(Val: Amount); |
| 511 | } else { |
| 512 | assert(Old.getOpcode() == XCore::ADJCALLSTACKUP); |
| 513 | int Opcode = isU6 ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; |
| 514 | New = BuildMI(MF, MIMD: Old.getDebugLoc(), MCID: TII.get(Opcode), DestReg: XCore::SP) |
| 515 | .addImm(Val: Amount); |
| 516 | } |
| 517 | |
| 518 | // Replace the pseudo instruction with a new instruction... |
| 519 | MBB.insert(I, MI: New); |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | return MBB.erase(I); |
| 524 | } |
| 525 | |
| 526 | void XCoreFrameLowering::determineCalleeSaves(MachineFunction &MF, |
| 527 | BitVector &SavedRegs, |
| 528 | RegScavenger *RS) const { |
| 529 | TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); |
| 530 | |
| 531 | XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); |
| 532 | |
| 533 | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
| 534 | bool LRUsed = MRI.isPhysRegModified(PhysReg: XCore::LR); |
| 535 | |
| 536 | if (!LRUsed && !MF.getFunction().isVarArg() && |
| 537 | MF.getFrameInfo().estimateStackSize(MF)) |
| 538 | // If we need to extend the stack it is more efficient to use entsp / retsp. |
| 539 | // We force the LR to be saved so these instructions are used. |
| 540 | LRUsed = true; |
| 541 | |
| 542 | if (MF.callsUnwindInit() || MF.callsEHReturn()) { |
| 543 | // The unwinder expects to find spill slots for the exception info regs R0 |
| 544 | // & R1. These are used during llvm.eh.return() to 'restore' the exception |
| 545 | // info. N.B. we do not spill or restore R0, R1 during normal operation. |
| 546 | XFI->createEHSpillSlot(MF); |
| 547 | // As we will have a stack, we force the LR to be saved. |
| 548 | LRUsed = true; |
| 549 | } |
| 550 | |
| 551 | if (LRUsed) { |
| 552 | // We will handle the LR in the prologue/epilogue |
| 553 | // and allocate space on the stack ourselves. |
| 554 | SavedRegs.reset(Idx: XCore::LR); |
| 555 | XFI->createLRSpillSlot(MF); |
| 556 | } |
| 557 | |
| 558 | if (hasFP(MF)) |
| 559 | // A callee save register is used to hold the FP. |
| 560 | // This needs saving / restoring in the epilogue / prologue. |
| 561 | XFI->createFPSpillSlot(MF); |
| 562 | } |
| 563 | |
| 564 | void XCoreFrameLowering:: |
| 565 | processFunctionBeforeFrameFinalized(MachineFunction &MF, |
| 566 | RegScavenger *RS) const { |
| 567 | assert(RS && "requiresRegisterScavenging failed" ); |
| 568 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
| 569 | const TargetRegisterClass &RC = XCore::GRRegsRegClass; |
| 570 | const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); |
| 571 | XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); |
| 572 | // Reserve slots close to SP or frame pointer for Scavenging spills. |
| 573 | // When using SP for small frames, we don't need any scratch registers. |
| 574 | // When using SP for large frames, we may need 2 scratch registers. |
| 575 | // When using FP, for large or small frames, we may need 1 scratch register. |
| 576 | unsigned Size = TRI.getSpillSize(RC); |
| 577 | Align Alignment = TRI.getSpillAlign(RC); |
| 578 | if (XFI->isLargeFrame(MF) || hasFP(MF)) |
| 579 | RS->addScavengingFrameIndex(FI: MFI.CreateSpillStackObject(Size, Alignment)); |
| 580 | if (XFI->isLargeFrame(MF) && !hasFP(MF)) |
| 581 | RS->addScavengingFrameIndex(FI: MFI.CreateSpillStackObject(Size, Alignment)); |
| 582 | } |
| 583 | |