18971842fSAlex Bradbury //===-- RISCVFrameLowering.cpp - RISCV Frame Information ------------------===// 28971842fSAlex Bradbury // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68971842fSAlex Bradbury // 78971842fSAlex Bradbury //===----------------------------------------------------------------------===// 88971842fSAlex Bradbury // 98971842fSAlex Bradbury // This file contains the RISCV implementation of TargetFrameLowering class. 108971842fSAlex Bradbury // 118971842fSAlex Bradbury //===----------------------------------------------------------------------===// 128971842fSAlex Bradbury 138971842fSAlex Bradbury #include "RISCVFrameLowering.h" 14c85be0deSAlex Bradbury #include "RISCVMachineFunctionInfo.h" 158971842fSAlex Bradbury #include "RISCVSubtarget.h" 168971842fSAlex Bradbury #include "llvm/CodeGen/MachineFrameInfo.h" 178971842fSAlex Bradbury #include "llvm/CodeGen/MachineFunction.h" 188971842fSAlex Bradbury #include "llvm/CodeGen/MachineInstrBuilder.h" 198971842fSAlex Bradbury #include "llvm/CodeGen/MachineRegisterInfo.h" 200715d35eSAlex Bradbury #include "llvm/CodeGen/RegisterScavenging.h" 21aed9d6d6SSimon Cook #include "llvm/IR/DiagnosticInfo.h" 2204ddf39bSHsiangkai Wang #include "llvm/MC/MCDwarf.h" 238971842fSAlex Bradbury 248971842fSAlex Bradbury using namespace llvm; 258971842fSAlex Bradbury 267d6aa1f7SAlex Bradbury bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const { 277d6aa1f7SAlex Bradbury const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 287d6aa1f7SAlex Bradbury 297d6aa1f7SAlex Bradbury const MachineFrameInfo &MFI = MF.getFrameInfo(); 307d6aa1f7SAlex Bradbury return MF.getTarget().Options.DisableFramePointerElim(MF) || 317d6aa1f7SAlex Bradbury RegInfo->needsStackRealignment(MF) || MFI.hasVarSizedObjects() || 327d6aa1f7SAlex Bradbury MFI.isFrameAddressTaken(); 337d6aa1f7SAlex Bradbury } 348971842fSAlex Bradbury 35*cf6cf0cdSShiva Chen bool RISCVFrameLowering::hasBP(const MachineFunction &MF) const { 36*cf6cf0cdSShiva Chen const MachineFrameInfo &MFI = MF.getFrameInfo(); 37*cf6cf0cdSShiva Chen const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 38*cf6cf0cdSShiva Chen 39*cf6cf0cdSShiva Chen return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF); 40*cf6cf0cdSShiva Chen } 41*cf6cf0cdSShiva Chen 42b014e3deSAlex Bradbury // Determines the size of the frame and maximum call frame size. 43b014e3deSAlex Bradbury void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { 44b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 45b014e3deSAlex Bradbury const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 46b014e3deSAlex Bradbury 47b014e3deSAlex Bradbury // Get the number of bytes to allocate from the FrameInfo. 48b014e3deSAlex Bradbury uint64_t FrameSize = MFI.getStackSize(); 49b014e3deSAlex Bradbury 50b014e3deSAlex Bradbury // Get the alignment. 51cd44aee3SSam Elliott unsigned StackAlign = getStackAlignment(); 52cd44aee3SSam Elliott if (RI->needsStackRealignment(MF)) { 53cd44aee3SSam Elliott unsigned MaxStackAlign = std::max(StackAlign, MFI.getMaxAlignment()); 54cd44aee3SSam Elliott FrameSize += (MaxStackAlign - StackAlign); 55cd44aee3SSam Elliott StackAlign = MaxStackAlign; 56cd44aee3SSam Elliott } 57cd44aee3SSam Elliott 58cd44aee3SSam Elliott // Set Max Call Frame Size 59cd44aee3SSam Elliott uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign); 60cd44aee3SSam Elliott MFI.setMaxCallFrameSize(MaxCallSize); 61b014e3deSAlex Bradbury 62b014e3deSAlex Bradbury // Make sure the frame is aligned. 63b014e3deSAlex Bradbury FrameSize = alignTo(FrameSize, StackAlign); 64b014e3deSAlex Bradbury 65b014e3deSAlex Bradbury // Update frame info. 66b014e3deSAlex Bradbury MFI.setStackSize(FrameSize); 67b014e3deSAlex Bradbury } 68b014e3deSAlex Bradbury 69b014e3deSAlex Bradbury void RISCVFrameLowering::adjustReg(MachineBasicBlock &MBB, 70b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI, 71fa06e958SLuis Marques const DebugLoc &DL, Register DestReg, 72fa06e958SLuis Marques Register SrcReg, int64_t Val, 73b014e3deSAlex Bradbury MachineInstr::MIFlag Flag) const { 749fea4881SAlex Bradbury MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); 75b014e3deSAlex Bradbury const RISCVInstrInfo *TII = STI.getInstrInfo(); 76b014e3deSAlex Bradbury 77b014e3deSAlex Bradbury if (DestReg == SrcReg && Val == 0) 78b014e3deSAlex Bradbury return; 79b014e3deSAlex Bradbury 809fea4881SAlex Bradbury if (isInt<12>(Val)) { 81b014e3deSAlex Bradbury BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DestReg) 82b014e3deSAlex Bradbury .addReg(SrcReg) 83b014e3deSAlex Bradbury .addImm(Val) 84b014e3deSAlex Bradbury .setMIFlag(Flag); 85a49a16ddSShiva Chen } else { 869fea4881SAlex Bradbury unsigned Opc = RISCV::ADD; 879fea4881SAlex Bradbury bool isSub = Val < 0; 889fea4881SAlex Bradbury if (isSub) { 899fea4881SAlex Bradbury Val = -Val; 909fea4881SAlex Bradbury Opc = RISCV::SUB; 919fea4881SAlex Bradbury } 929fea4881SAlex Bradbury 933836874dSDaniel Sanders Register ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 94a49a16ddSShiva Chen TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag); 959fea4881SAlex Bradbury BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) 969fea4881SAlex Bradbury .addReg(SrcReg) 979fea4881SAlex Bradbury .addReg(ScratchReg, RegState::Kill) 989fea4881SAlex Bradbury .setMIFlag(Flag); 999fea4881SAlex Bradbury } 100b014e3deSAlex Bradbury } 101b014e3deSAlex Bradbury 102b014e3deSAlex Bradbury // Returns the register used to hold the frame pointer. 103fa06e958SLuis Marques static Register getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; } 104b014e3deSAlex Bradbury 105b014e3deSAlex Bradbury // Returns the register used to hold the stack pointer. 106fa06e958SLuis Marques static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; } 107b014e3deSAlex Bradbury 1088971842fSAlex Bradbury void RISCVFrameLowering::emitPrologue(MachineFunction &MF, 109b014e3deSAlex Bradbury MachineBasicBlock &MBB) const { 110b014e3deSAlex Bradbury assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 111b014e3deSAlex Bradbury 112b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 113c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 11404ddf39bSHsiangkai Wang const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 11504ddf39bSHsiangkai Wang const RISCVInstrInfo *TII = STI.getInstrInfo(); 116b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI = MBB.begin(); 117b014e3deSAlex Bradbury 118fa06e958SLuis Marques Register FPReg = getFPReg(STI); 119fa06e958SLuis Marques Register SPReg = getSPReg(STI); 120*cf6cf0cdSShiva Chen Register BPReg = RISCVABI::getBPReg(); 121b014e3deSAlex Bradbury 122b014e3deSAlex Bradbury // Debug location must be unknown since the first debug location is used 123b014e3deSAlex Bradbury // to determine the end of the prologue. 124b014e3deSAlex Bradbury DebugLoc DL; 125b014e3deSAlex Bradbury 126b014e3deSAlex Bradbury // Determine the correct frame layout 127b014e3deSAlex Bradbury determineFrameLayout(MF); 128b014e3deSAlex Bradbury 129b014e3deSAlex Bradbury // FIXME (note copied from Lanai): This appears to be overallocating. Needs 130b014e3deSAlex Bradbury // investigation. Get the number of bytes to allocate from the FrameInfo. 131b014e3deSAlex Bradbury uint64_t StackSize = MFI.getStackSize(); 132b014e3deSAlex Bradbury 133b014e3deSAlex Bradbury // Early exit if there is no need to allocate on the stack 134b014e3deSAlex Bradbury if (StackSize == 0 && !MFI.adjustsStack()) 135b014e3deSAlex Bradbury return; 136b014e3deSAlex Bradbury 137aed9d6d6SSimon Cook // If the stack pointer has been marked as reserved, then produce an error if 138aed9d6d6SSimon Cook // the frame requires stack allocation 139aed9d6d6SSimon Cook if (STI.isRegisterReservedByUser(SPReg)) 140aed9d6d6SSimon Cook MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ 141aed9d6d6SSimon Cook MF.getFunction(), "Stack pointer required, but has been reserved."}); 142aed9d6d6SSimon Cook 143ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 144ff55e2e0SShiva Chen // Split the SP adjustment to reduce the offsets of callee saved spill. 145ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 146ff55e2e0SShiva Chen StackSize = FirstSPAdjustAmount; 147ff55e2e0SShiva Chen 148b014e3deSAlex Bradbury // Allocate space on the stack if necessary. 149b014e3deSAlex Bradbury adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); 150b014e3deSAlex Bradbury 15104ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa_offset StackSize" 15204ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst( 15304ddf39bSHsiangkai Wang MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); 15404ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 15504ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 15604ddf39bSHsiangkai Wang 157b014e3deSAlex Bradbury // The frame pointer is callee-saved, and code has been generated for us to 158b014e3deSAlex Bradbury // save it to the stack. We need to skip over the storing of callee-saved 159b014e3deSAlex Bradbury // registers as the frame pointer must be modified after it has been saved 160b014e3deSAlex Bradbury // to the stack, not before. 161b014e3deSAlex Bradbury // FIXME: assumes exactly one instruction is used to save each callee-saved 162b014e3deSAlex Bradbury // register. 163b014e3deSAlex Bradbury const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 164b014e3deSAlex Bradbury std::advance(MBBI, CSI.size()); 165b014e3deSAlex Bradbury 16604ddf39bSHsiangkai Wang // Iterate over list of callee-saved registers and emit .cfi_offset 16704ddf39bSHsiangkai Wang // directives. 16804ddf39bSHsiangkai Wang for (const auto &Entry : CSI) { 16904ddf39bSHsiangkai Wang int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); 170fa06e958SLuis Marques Register Reg = Entry.getReg(); 17104ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 17204ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(Reg, true), Offset)); 17304ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 17404ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 17504ddf39bSHsiangkai Wang } 17604ddf39bSHsiangkai Wang 177b014e3deSAlex Bradbury // Generate new FP. 17804ddf39bSHsiangkai Wang if (hasFP(MF)) { 179aed9d6d6SSimon Cook if (STI.isRegisterReservedByUser(FPReg)) 180aed9d6d6SSimon Cook MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ 181aed9d6d6SSimon Cook MF.getFunction(), "Frame pointer required, but has been reserved."}); 182aed9d6d6SSimon Cook 1837d6aa1f7SAlex Bradbury adjustReg(MBB, MBBI, DL, FPReg, SPReg, 1847d6aa1f7SAlex Bradbury StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); 18504ddf39bSHsiangkai Wang 18604ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa $fp, 0" 18704ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( 18804ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(FPReg, true), 0)); 18904ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 19004ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 191ff55e2e0SShiva Chen } 192cd44aee3SSam Elliott 193ff55e2e0SShiva Chen // Emit the second SP adjustment after saving callee saved registers. 194ff55e2e0SShiva Chen if (FirstSPAdjustAmount) { 195ff55e2e0SShiva Chen uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; 196ff55e2e0SShiva Chen assert(SecondSPAdjustAmount > 0 && 197ff55e2e0SShiva Chen "SecondSPAdjustAmount should be greater than zero"); 198ff55e2e0SShiva Chen adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, 199ff55e2e0SShiva Chen MachineInstr::FrameSetup); 2001c737f54SLuís Marques 2011c737f54SLuís Marques // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", 2021c737f54SLuís Marques // don't emit an sp-based .cfi_def_cfa_offset 2031c737f54SLuís Marques if (!hasFP(MF)) { 204ff55e2e0SShiva Chen // Emit ".cfi_def_cfa_offset StackSize" 205ff55e2e0SShiva Chen unsigned CFIIndex = MF.addFrameInst( 206ff55e2e0SShiva Chen MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); 207ff55e2e0SShiva Chen BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 208ff55e2e0SShiva Chen .addCFIIndex(CFIIndex); 209ff55e2e0SShiva Chen } 2101c737f54SLuís Marques } 211ff55e2e0SShiva Chen 212ff55e2e0SShiva Chen if (hasFP(MF)) { 213cd44aee3SSam Elliott // Realign Stack 214cd44aee3SSam Elliott const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 215cd44aee3SSam Elliott if (RI->needsStackRealignment(MF)) { 216cd44aee3SSam Elliott unsigned MaxAlignment = MFI.getMaxAlignment(); 217cd44aee3SSam Elliott 218cd44aee3SSam Elliott const RISCVInstrInfo *TII = STI.getInstrInfo(); 219cd44aee3SSam Elliott if (isInt<12>(-(int)MaxAlignment)) { 220cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) 221cd44aee3SSam Elliott .addReg(SPReg) 222cd44aee3SSam Elliott .addImm(-(int)MaxAlignment); 223cd44aee3SSam Elliott } else { 224cd44aee3SSam Elliott unsigned ShiftAmount = countTrailingZeros(MaxAlignment); 225fa06e958SLuis Marques Register VR = 226cd44aee3SSam Elliott MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); 227cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR) 228cd44aee3SSam Elliott .addReg(SPReg) 229cd44aee3SSam Elliott .addImm(ShiftAmount); 230cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::SLLI), SPReg) 231cd44aee3SSam Elliott .addReg(VR) 232cd44aee3SSam Elliott .addImm(ShiftAmount); 233cd44aee3SSam Elliott } 234*cf6cf0cdSShiva Chen // FP will be used to restore the frame in the epilogue, so we need 235*cf6cf0cdSShiva Chen // another base register BP to record SP after re-alignment. SP will 236*cf6cf0cdSShiva Chen // track the current stack after allocating variable sized objects. 237*cf6cf0cdSShiva Chen if (hasBP(MF)) { 238*cf6cf0cdSShiva Chen // move BP, SP 239*cf6cf0cdSShiva Chen BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), BPReg) 240*cf6cf0cdSShiva Chen .addReg(SPReg) 241*cf6cf0cdSShiva Chen .addImm(0); 242*cf6cf0cdSShiva Chen } 243cd44aee3SSam Elliott } 24404ddf39bSHsiangkai Wang } 245b014e3deSAlex Bradbury } 2468971842fSAlex Bradbury 2478971842fSAlex Bradbury void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, 248b014e3deSAlex Bradbury MachineBasicBlock &MBB) const { 249b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 250b014e3deSAlex Bradbury const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 251b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 252c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 253b014e3deSAlex Bradbury DebugLoc DL = MBBI->getDebugLoc(); 254fa06e958SLuis Marques Register FPReg = getFPReg(STI); 255fa06e958SLuis Marques Register SPReg = getSPReg(STI); 256b014e3deSAlex Bradbury 257b014e3deSAlex Bradbury // Skip to before the restores of callee-saved registers 258b014e3deSAlex Bradbury // FIXME: assumes exactly one instruction is used to restore each 259b014e3deSAlex Bradbury // callee-saved register. 26061b28edeSAna Pazos auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size()); 261b014e3deSAlex Bradbury 262b014e3deSAlex Bradbury uint64_t StackSize = MFI.getStackSize(); 26304ddf39bSHsiangkai Wang uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize(); 264b014e3deSAlex Bradbury 265b014e3deSAlex Bradbury // Restore the stack pointer using the value of the frame pointer. Only 266b014e3deSAlex Bradbury // necessary if the stack pointer was modified, meaning the stack size is 267b014e3deSAlex Bradbury // unknown. 268b014e3deSAlex Bradbury if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { 2697d6aa1f7SAlex Bradbury assert(hasFP(MF) && "frame pointer should not have been eliminated"); 27004ddf39bSHsiangkai Wang adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, 271b014e3deSAlex Bradbury MachineInstr::FrameDestroy); 272b014e3deSAlex Bradbury } 273b014e3deSAlex Bradbury 274ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 275ff55e2e0SShiva Chen if (FirstSPAdjustAmount) { 276ff55e2e0SShiva Chen uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; 277ff55e2e0SShiva Chen assert(SecondSPAdjustAmount > 0 && 278ff55e2e0SShiva Chen "SecondSPAdjustAmount should be greater than zero"); 279ff55e2e0SShiva Chen 280ff55e2e0SShiva Chen adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, 281ff55e2e0SShiva Chen MachineInstr::FrameDestroy); 28204ddf39bSHsiangkai Wang } 28304ddf39bSHsiangkai Wang 284ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 285ff55e2e0SShiva Chen StackSize = FirstSPAdjustAmount; 286ff55e2e0SShiva Chen 287b014e3deSAlex Bradbury // Deallocate stack 288b014e3deSAlex Bradbury adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); 289b014e3deSAlex Bradbury } 290660bccecSAlex Bradbury 291660bccecSAlex Bradbury int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, 292660bccecSAlex Bradbury int FI, 293660bccecSAlex Bradbury unsigned &FrameReg) const { 294660bccecSAlex Bradbury const MachineFrameInfo &MFI = MF.getFrameInfo(); 295660bccecSAlex Bradbury const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 296c85be0deSAlex Bradbury const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 297660bccecSAlex Bradbury 298660bccecSAlex Bradbury // Callee-saved registers should be referenced relative to the stack 299660bccecSAlex Bradbury // pointer (positive offset), otherwise use the frame pointer (negative 300660bccecSAlex Bradbury // offset). 301660bccecSAlex Bradbury const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 302660bccecSAlex Bradbury int MinCSFI = 0; 303660bccecSAlex Bradbury int MaxCSFI = -1; 304660bccecSAlex Bradbury 305660bccecSAlex Bradbury int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + 306660bccecSAlex Bradbury MFI.getOffsetAdjustment(); 307660bccecSAlex Bradbury 308ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 309ff55e2e0SShiva Chen 310660bccecSAlex Bradbury if (CSI.size()) { 311660bccecSAlex Bradbury MinCSFI = CSI[0].getFrameIdx(); 312660bccecSAlex Bradbury MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 313660bccecSAlex Bradbury } 314660bccecSAlex Bradbury 315660bccecSAlex Bradbury if (FI >= MinCSFI && FI <= MaxCSFI) { 316660bccecSAlex Bradbury FrameReg = RISCV::X2; 317ff55e2e0SShiva Chen 318ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 319ff55e2e0SShiva Chen Offset += FirstSPAdjustAmount; 320ff55e2e0SShiva Chen else 321660bccecSAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 322*cf6cf0cdSShiva Chen } else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { 323cd44aee3SSam Elliott // If the stack was realigned, the frame pointer is set in order to allow 324*cf6cf0cdSShiva Chen // SP to be restored, so we need another base register to record the stack 325*cf6cf0cdSShiva Chen // after realignment. 326*cf6cf0cdSShiva Chen if (hasBP(MF)) 327*cf6cf0cdSShiva Chen FrameReg = RISCVABI::getBPReg(); 328*cf6cf0cdSShiva Chen else 329cd44aee3SSam Elliott FrameReg = RISCV::X2; 330cd44aee3SSam Elliott Offset += MF.getFrameInfo().getStackSize(); 331c85be0deSAlex Bradbury } else { 332c85be0deSAlex Bradbury FrameReg = RI->getFrameRegister(MF); 3337d6aa1f7SAlex Bradbury if (hasFP(MF)) 334c85be0deSAlex Bradbury Offset += RVFI->getVarArgsSaveSize(); 3357d6aa1f7SAlex Bradbury else 3367d6aa1f7SAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 337660bccecSAlex Bradbury } 338660bccecSAlex Bradbury return Offset; 339660bccecSAlex Bradbury } 340b014e3deSAlex Bradbury 341b014e3deSAlex Bradbury void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, 342b014e3deSAlex Bradbury BitVector &SavedRegs, 343b014e3deSAlex Bradbury RegScavenger *RS) const { 344b014e3deSAlex Bradbury TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 3457d6aa1f7SAlex Bradbury // Unconditionally spill RA and FP only if the function uses a frame 3467d6aa1f7SAlex Bradbury // pointer. 3477d6aa1f7SAlex Bradbury if (hasFP(MF)) { 348b014e3deSAlex Bradbury SavedRegs.set(RISCV::X1); 349b014e3deSAlex Bradbury SavedRegs.set(RISCV::X8); 350b014e3deSAlex Bradbury } 351*cf6cf0cdSShiva Chen // Mark BP as used if function has dedicated base pointer. 352*cf6cf0cdSShiva Chen if (hasBP(MF)) 353*cf6cf0cdSShiva Chen SavedRegs.set(RISCVABI::getBPReg()); 3542e4106b7SAna Pazos 3552e4106b7SAna Pazos // If interrupt is enabled and there are calls in the handler, 3562e4106b7SAna Pazos // unconditionally save all Caller-saved registers and 3572e4106b7SAna Pazos // all FP registers, regardless whether they are used. 3582e4106b7SAna Pazos MachineFrameInfo &MFI = MF.getFrameInfo(); 3592e4106b7SAna Pazos 3602e4106b7SAna Pazos if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { 3612e4106b7SAna Pazos 3622e4106b7SAna Pazos static const MCPhysReg CSRegs[] = { RISCV::X1, /* ra */ 3632e4106b7SAna Pazos RISCV::X5, RISCV::X6, RISCV::X7, /* t0-t2 */ 3642e4106b7SAna Pazos RISCV::X10, RISCV::X11, /* a0-a1, a2-a7 */ 3652e4106b7SAna Pazos RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17, 3662e4106b7SAna Pazos RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31, 0 /* t3-t6 */ 3672e4106b7SAna Pazos }; 3682e4106b7SAna Pazos 3692e4106b7SAna Pazos for (unsigned i = 0; CSRegs[i]; ++i) 3702e4106b7SAna Pazos SavedRegs.set(CSRegs[i]); 3712e4106b7SAna Pazos 3722e4106b7SAna Pazos if (MF.getSubtarget<RISCVSubtarget>().hasStdExtD() || 3732e4106b7SAna Pazos MF.getSubtarget<RISCVSubtarget>().hasStdExtF()) { 3742e4106b7SAna Pazos 3752e4106b7SAna Pazos // If interrupt is enabled, this list contains all FP registers. 3762e4106b7SAna Pazos const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs(); 3772e4106b7SAna Pazos 3782e4106b7SAna Pazos for (unsigned i = 0; Regs[i]; ++i) 3792e4106b7SAna Pazos if (RISCV::FPR32RegClass.contains(Regs[i]) || 3802e4106b7SAna Pazos RISCV::FPR64RegClass.contains(Regs[i])) 3812e4106b7SAna Pazos SavedRegs.set(Regs[i]); 3822e4106b7SAna Pazos } 3832e4106b7SAna Pazos } 3847d6aa1f7SAlex Bradbury } 3850715d35eSAlex Bradbury 3860715d35eSAlex Bradbury void RISCVFrameLowering::processFunctionBeforeFrameFinalized( 3870715d35eSAlex Bradbury MachineFunction &MF, RegScavenger *RS) const { 3880715d35eSAlex Bradbury const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 3890715d35eSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 3900715d35eSAlex Bradbury const TargetRegisterClass *RC = &RISCV::GPRRegClass; 3910715d35eSAlex Bradbury // estimateStackSize has been observed to under-estimate the final stack 3920715d35eSAlex Bradbury // size, so give ourselves wiggle-room by checking for stack size 3930715d35eSAlex Bradbury // representable an 11-bit signed field rather than 12-bits. 3940715d35eSAlex Bradbury // FIXME: It may be possible to craft a function with a small stack that 3950715d35eSAlex Bradbury // still needs an emergency spill slot for branch relaxation. This case 3960715d35eSAlex Bradbury // would currently be missed. 3970715d35eSAlex Bradbury if (!isInt<11>(MFI.estimateStackSize(MF))) { 3980715d35eSAlex Bradbury int RegScavFI = MFI.CreateStackObject( 3990715d35eSAlex Bradbury RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); 4000715d35eSAlex Bradbury RS->addScavengingFrameIndex(RegScavFI); 4010715d35eSAlex Bradbury } 4020715d35eSAlex Bradbury } 403cbd498acSShiva Chen 404cbd498acSShiva Chen // Not preserve stack space within prologue for outgoing variables when the 405cbd498acSShiva Chen // function contains variable size objects and let eliminateCallFramePseudoInstr 406cbd498acSShiva Chen // preserve stack space for it. 407cbd498acSShiva Chen bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 408cbd498acSShiva Chen return !MF.getFrameInfo().hasVarSizedObjects(); 409cbd498acSShiva Chen } 410cbd498acSShiva Chen 411cbd498acSShiva Chen // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 412cbd498acSShiva Chen MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( 413cbd498acSShiva Chen MachineFunction &MF, MachineBasicBlock &MBB, 414cbd498acSShiva Chen MachineBasicBlock::iterator MI) const { 415fa06e958SLuis Marques Register SPReg = RISCV::X2; 416cbd498acSShiva Chen DebugLoc DL = MI->getDebugLoc(); 417cbd498acSShiva Chen 418cbd498acSShiva Chen if (!hasReservedCallFrame(MF)) { 419cbd498acSShiva Chen // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 420cbd498acSShiva Chen // ADJCALLSTACKUP must be converted to instructions manipulating the stack 421cbd498acSShiva Chen // pointer. This is necessary when there is a variable length stack 422cbd498acSShiva Chen // allocation (e.g. alloca), which means it's not possible to allocate 423cbd498acSShiva Chen // space for outgoing arguments from within the function prologue. 424cbd498acSShiva Chen int64_t Amount = MI->getOperand(0).getImm(); 425cbd498acSShiva Chen 426cbd498acSShiva Chen if (Amount != 0) { 427cbd498acSShiva Chen // Ensure the stack remains aligned after adjustment. 428cbd498acSShiva Chen Amount = alignSPAdjust(Amount); 429cbd498acSShiva Chen 430cbd498acSShiva Chen if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN) 431cbd498acSShiva Chen Amount = -Amount; 432cbd498acSShiva Chen 433cbd498acSShiva Chen adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 434cbd498acSShiva Chen } 435cbd498acSShiva Chen } 436cbd498acSShiva Chen 437cbd498acSShiva Chen return MBB.erase(MI); 438cbd498acSShiva Chen } 439ff55e2e0SShiva Chen 440ff55e2e0SShiva Chen // We would like to split the SP adjustment to reduce prologue/epilogue 441ff55e2e0SShiva Chen // as following instructions. In this way, the offset of the callee saved 442ff55e2e0SShiva Chen // register could fit in a single store. 443ff55e2e0SShiva Chen // add sp,sp,-2032 444ff55e2e0SShiva Chen // sw ra,2028(sp) 445ff55e2e0SShiva Chen // sw s0,2024(sp) 446ff55e2e0SShiva Chen // sw s1,2020(sp) 447ff55e2e0SShiva Chen // sw s3,2012(sp) 448ff55e2e0SShiva Chen // sw s4,2008(sp) 449ff55e2e0SShiva Chen // add sp,sp,-64 450ff55e2e0SShiva Chen uint64_t 451ff55e2e0SShiva Chen RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { 452ff55e2e0SShiva Chen const MachineFrameInfo &MFI = MF.getFrameInfo(); 453ff55e2e0SShiva Chen const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 454ff55e2e0SShiva Chen uint64_t StackSize = MFI.getStackSize(); 455ff55e2e0SShiva Chen uint64_t StackAlign = getStackAlignment(); 456ff55e2e0SShiva Chen 457ff55e2e0SShiva Chen // FIXME: Disable SplitSPAdjust if save-restore libcall enabled when the patch 458ff55e2e0SShiva Chen // landing. The callee saved registers will be pushed by the 459ff55e2e0SShiva Chen // save-restore libcalls, so we don't have to split the SP adjustment 460ff55e2e0SShiva Chen // in this case. 461ff55e2e0SShiva Chen // 462ff55e2e0SShiva Chen // Return the FirstSPAdjustAmount if the StackSize can not fit in signed 463ff55e2e0SShiva Chen // 12-bit and there exists a callee saved register need to be pushed. 464ff55e2e0SShiva Chen if (!isInt<12>(StackSize) && (CSI.size() > 0)) { 465ff55e2e0SShiva Chen // FirstSPAdjustAmount is choosed as (2048 - StackAlign) 466ff55e2e0SShiva Chen // because 2048 will cause sp = sp + 2048 in epilogue split into 467ff55e2e0SShiva Chen // multi-instructions. The offset smaller than 2048 can fit in signle 468ff55e2e0SShiva Chen // load/store instruction and we have to stick with the stack alignment. 469ff55e2e0SShiva Chen // 2048 is 16-byte alignment. The stack alignment for RV32 and RV64 is 16, 470ff55e2e0SShiva Chen // for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment. 471ff55e2e0SShiva Chen return 2048 - StackAlign; 472ff55e2e0SShiva Chen } 473ff55e2e0SShiva Chen return 0; 474ff55e2e0SShiva Chen } 475