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 35cf6cf0cdSShiva Chen bool RISCVFrameLowering::hasBP(const MachineFunction &MF) const { 36cf6cf0cdSShiva Chen const MachineFrameInfo &MFI = MF.getFrameInfo(); 37cf6cf0cdSShiva Chen const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 38cf6cf0cdSShiva Chen 39cf6cf0cdSShiva Chen return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF); 40cf6cf0cdSShiva Chen } 41cf6cf0cdSShiva 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 MachineFrameInfo &MFI = MF.getFrameInfo(); 111c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 11204ddf39bSHsiangkai Wang const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 11304ddf39bSHsiangkai Wang const RISCVInstrInfo *TII = STI.getInstrInfo(); 114b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI = MBB.begin(); 115b014e3deSAlex Bradbury 116fa06e958SLuis Marques Register FPReg = getFPReg(STI); 117fa06e958SLuis Marques Register SPReg = getSPReg(STI); 118cf6cf0cdSShiva Chen Register BPReg = RISCVABI::getBPReg(); 119b014e3deSAlex Bradbury 120b014e3deSAlex Bradbury // Debug location must be unknown since the first debug location is used 121b014e3deSAlex Bradbury // to determine the end of the prologue. 122b014e3deSAlex Bradbury DebugLoc DL; 123b014e3deSAlex Bradbury 124b014e3deSAlex Bradbury // Determine the correct frame layout 125b014e3deSAlex Bradbury determineFrameLayout(MF); 126b014e3deSAlex Bradbury 127b014e3deSAlex Bradbury // FIXME (note copied from Lanai): This appears to be overallocating. Needs 128b014e3deSAlex Bradbury // investigation. Get the number of bytes to allocate from the FrameInfo. 129b014e3deSAlex Bradbury uint64_t StackSize = MFI.getStackSize(); 130b014e3deSAlex Bradbury 131b014e3deSAlex Bradbury // Early exit if there is no need to allocate on the stack 132b014e3deSAlex Bradbury if (StackSize == 0 && !MFI.adjustsStack()) 133b014e3deSAlex Bradbury return; 134b014e3deSAlex Bradbury 135aed9d6d6SSimon Cook // If the stack pointer has been marked as reserved, then produce an error if 136aed9d6d6SSimon Cook // the frame requires stack allocation 137aed9d6d6SSimon Cook if (STI.isRegisterReservedByUser(SPReg)) 138aed9d6d6SSimon Cook MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ 139aed9d6d6SSimon Cook MF.getFunction(), "Stack pointer required, but has been reserved."}); 140aed9d6d6SSimon Cook 141ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 142ff55e2e0SShiva Chen // Split the SP adjustment to reduce the offsets of callee saved spill. 143ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 144ff55e2e0SShiva Chen StackSize = FirstSPAdjustAmount; 145ff55e2e0SShiva Chen 146b014e3deSAlex Bradbury // Allocate space on the stack if necessary. 147b014e3deSAlex Bradbury adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); 148b014e3deSAlex Bradbury 14904ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa_offset StackSize" 15004ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst( 15104ddf39bSHsiangkai Wang MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); 15204ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 15304ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 15404ddf39bSHsiangkai Wang 155b014e3deSAlex Bradbury // The frame pointer is callee-saved, and code has been generated for us to 156b014e3deSAlex Bradbury // save it to the stack. We need to skip over the storing of callee-saved 157b014e3deSAlex Bradbury // registers as the frame pointer must be modified after it has been saved 158b014e3deSAlex Bradbury // to the stack, not before. 159b014e3deSAlex Bradbury // FIXME: assumes exactly one instruction is used to save each callee-saved 160b014e3deSAlex Bradbury // register. 161b014e3deSAlex Bradbury const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 162b014e3deSAlex Bradbury std::advance(MBBI, CSI.size()); 163b014e3deSAlex Bradbury 16404ddf39bSHsiangkai Wang // Iterate over list of callee-saved registers and emit .cfi_offset 16504ddf39bSHsiangkai Wang // directives. 16604ddf39bSHsiangkai Wang for (const auto &Entry : CSI) { 16704ddf39bSHsiangkai Wang int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); 168fa06e958SLuis Marques Register Reg = Entry.getReg(); 16904ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 17004ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(Reg, true), Offset)); 17104ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 17204ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 17304ddf39bSHsiangkai Wang } 17404ddf39bSHsiangkai Wang 175b014e3deSAlex Bradbury // Generate new FP. 17604ddf39bSHsiangkai Wang if (hasFP(MF)) { 177aed9d6d6SSimon Cook if (STI.isRegisterReservedByUser(FPReg)) 178aed9d6d6SSimon Cook MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ 179aed9d6d6SSimon Cook MF.getFunction(), "Frame pointer required, but has been reserved."}); 180aed9d6d6SSimon Cook 1817d6aa1f7SAlex Bradbury adjustReg(MBB, MBBI, DL, FPReg, SPReg, 1827d6aa1f7SAlex Bradbury StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); 18304ddf39bSHsiangkai Wang 184*64f41720SShiva Chen // Emit ".cfi_def_cfa $fp, -RVFI->getVarArgsSaveSize()" 18504ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( 186*64f41720SShiva Chen nullptr, RI->getDwarfRegNum(FPReg, true), -RVFI->getVarArgsSaveSize())); 18704ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 18804ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 189ff55e2e0SShiva Chen } 190cd44aee3SSam Elliott 191ff55e2e0SShiva Chen // Emit the second SP adjustment after saving callee saved registers. 192ff55e2e0SShiva Chen if (FirstSPAdjustAmount) { 193ff55e2e0SShiva Chen uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; 194ff55e2e0SShiva Chen assert(SecondSPAdjustAmount > 0 && 195ff55e2e0SShiva Chen "SecondSPAdjustAmount should be greater than zero"); 196ff55e2e0SShiva Chen adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, 197ff55e2e0SShiva Chen MachineInstr::FrameSetup); 1981c737f54SLuís Marques 1991c737f54SLuís Marques // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", 2001c737f54SLuís Marques // don't emit an sp-based .cfi_def_cfa_offset 2011c737f54SLuís Marques if (!hasFP(MF)) { 202ff55e2e0SShiva Chen // Emit ".cfi_def_cfa_offset StackSize" 203ff55e2e0SShiva Chen unsigned CFIIndex = MF.addFrameInst( 204ff55e2e0SShiva Chen MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); 205ff55e2e0SShiva Chen BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 206ff55e2e0SShiva Chen .addCFIIndex(CFIIndex); 207ff55e2e0SShiva Chen } 2081c737f54SLuís Marques } 209ff55e2e0SShiva Chen 210ff55e2e0SShiva Chen if (hasFP(MF)) { 211cd44aee3SSam Elliott // Realign Stack 212cd44aee3SSam Elliott const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 213cd44aee3SSam Elliott if (RI->needsStackRealignment(MF)) { 214cd44aee3SSam Elliott unsigned MaxAlignment = MFI.getMaxAlignment(); 215cd44aee3SSam Elliott 216cd44aee3SSam Elliott const RISCVInstrInfo *TII = STI.getInstrInfo(); 217cd44aee3SSam Elliott if (isInt<12>(-(int)MaxAlignment)) { 218cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) 219cd44aee3SSam Elliott .addReg(SPReg) 220cd44aee3SSam Elliott .addImm(-(int)MaxAlignment); 221cd44aee3SSam Elliott } else { 222cd44aee3SSam Elliott unsigned ShiftAmount = countTrailingZeros(MaxAlignment); 223fa06e958SLuis Marques Register VR = 224cd44aee3SSam Elliott MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); 225cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR) 226cd44aee3SSam Elliott .addReg(SPReg) 227cd44aee3SSam Elliott .addImm(ShiftAmount); 228cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::SLLI), SPReg) 229cd44aee3SSam Elliott .addReg(VR) 230cd44aee3SSam Elliott .addImm(ShiftAmount); 231cd44aee3SSam Elliott } 232cf6cf0cdSShiva Chen // FP will be used to restore the frame in the epilogue, so we need 233cf6cf0cdSShiva Chen // another base register BP to record SP after re-alignment. SP will 234cf6cf0cdSShiva Chen // track the current stack after allocating variable sized objects. 235cf6cf0cdSShiva Chen if (hasBP(MF)) { 236cf6cf0cdSShiva Chen // move BP, SP 237cf6cf0cdSShiva Chen BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), BPReg) 238cf6cf0cdSShiva Chen .addReg(SPReg) 239cf6cf0cdSShiva Chen .addImm(0); 240cf6cf0cdSShiva Chen } 241cd44aee3SSam Elliott } 24204ddf39bSHsiangkai Wang } 243b014e3deSAlex Bradbury } 2448971842fSAlex Bradbury 2458971842fSAlex Bradbury void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, 246b014e3deSAlex Bradbury MachineBasicBlock &MBB) const { 247b014e3deSAlex Bradbury const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 248b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 249c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 250fa06e958SLuis Marques Register FPReg = getFPReg(STI); 251fa06e958SLuis Marques Register SPReg = getSPReg(STI); 252b014e3deSAlex Bradbury 253cd800f3bSlewis-revill // Get the insert location for the epilogue. If there were no terminators in 254cd800f3bSlewis-revill // the block, get the last instruction. 255cd800f3bSlewis-revill MachineBasicBlock::iterator MBBI = MBB.end(); 256cd800f3bSlewis-revill DebugLoc DL; 257cd800f3bSlewis-revill if (!MBB.empty()) { 258cd800f3bSlewis-revill MBBI = MBB.getFirstTerminator(); 259cd800f3bSlewis-revill if (MBBI == MBB.end()) 260cd800f3bSlewis-revill MBBI = MBB.getLastNonDebugInstr(); 261cd800f3bSlewis-revill DL = MBBI->getDebugLoc(); 262cd800f3bSlewis-revill 263cd800f3bSlewis-revill // If this is not a terminator, the actual insert location should be after the 264cd800f3bSlewis-revill // last instruction. 265cd800f3bSlewis-revill if (!MBBI->isTerminator()) 266cd800f3bSlewis-revill MBBI = std::next(MBBI); 267cd800f3bSlewis-revill } 268cd800f3bSlewis-revill 269b014e3deSAlex Bradbury // Skip to before the restores of callee-saved registers 270b014e3deSAlex Bradbury // FIXME: assumes exactly one instruction is used to restore each 271b014e3deSAlex Bradbury // callee-saved register. 27261b28edeSAna Pazos auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size()); 273b014e3deSAlex Bradbury 274b014e3deSAlex Bradbury uint64_t StackSize = MFI.getStackSize(); 27504ddf39bSHsiangkai Wang uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize(); 276b014e3deSAlex Bradbury 277b014e3deSAlex Bradbury // Restore the stack pointer using the value of the frame pointer. Only 278b014e3deSAlex Bradbury // necessary if the stack pointer was modified, meaning the stack size is 279b014e3deSAlex Bradbury // unknown. 280b014e3deSAlex Bradbury if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { 2817d6aa1f7SAlex Bradbury assert(hasFP(MF) && "frame pointer should not have been eliminated"); 28204ddf39bSHsiangkai Wang adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, 283b014e3deSAlex Bradbury MachineInstr::FrameDestroy); 284b014e3deSAlex Bradbury } 285b014e3deSAlex Bradbury 286ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 287ff55e2e0SShiva Chen if (FirstSPAdjustAmount) { 288ff55e2e0SShiva Chen uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; 289ff55e2e0SShiva Chen assert(SecondSPAdjustAmount > 0 && 290ff55e2e0SShiva Chen "SecondSPAdjustAmount should be greater than zero"); 291ff55e2e0SShiva Chen 292ff55e2e0SShiva Chen adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, 293ff55e2e0SShiva Chen MachineInstr::FrameDestroy); 29404ddf39bSHsiangkai Wang } 29504ddf39bSHsiangkai Wang 296ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 297ff55e2e0SShiva Chen StackSize = FirstSPAdjustAmount; 298ff55e2e0SShiva Chen 299b014e3deSAlex Bradbury // Deallocate stack 300b014e3deSAlex Bradbury adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); 301b014e3deSAlex Bradbury } 302660bccecSAlex Bradbury 303660bccecSAlex Bradbury int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, 304660bccecSAlex Bradbury int FI, 305660bccecSAlex Bradbury unsigned &FrameReg) const { 306660bccecSAlex Bradbury const MachineFrameInfo &MFI = MF.getFrameInfo(); 307660bccecSAlex Bradbury const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 308c85be0deSAlex Bradbury const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 309660bccecSAlex Bradbury 310660bccecSAlex Bradbury // Callee-saved registers should be referenced relative to the stack 311660bccecSAlex Bradbury // pointer (positive offset), otherwise use the frame pointer (negative 312660bccecSAlex Bradbury // offset). 313660bccecSAlex Bradbury const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 314660bccecSAlex Bradbury int MinCSFI = 0; 315660bccecSAlex Bradbury int MaxCSFI = -1; 316660bccecSAlex Bradbury 317660bccecSAlex Bradbury int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + 318660bccecSAlex Bradbury MFI.getOffsetAdjustment(); 319660bccecSAlex Bradbury 320ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 321ff55e2e0SShiva Chen 322660bccecSAlex Bradbury if (CSI.size()) { 323660bccecSAlex Bradbury MinCSFI = CSI[0].getFrameIdx(); 324660bccecSAlex Bradbury MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 325660bccecSAlex Bradbury } 326660bccecSAlex Bradbury 327660bccecSAlex Bradbury if (FI >= MinCSFI && FI <= MaxCSFI) { 328660bccecSAlex Bradbury FrameReg = RISCV::X2; 329ff55e2e0SShiva Chen 330ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 331ff55e2e0SShiva Chen Offset += FirstSPAdjustAmount; 332ff55e2e0SShiva Chen else 333660bccecSAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 334cf6cf0cdSShiva Chen } else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { 335cd44aee3SSam Elliott // If the stack was realigned, the frame pointer is set in order to allow 336cf6cf0cdSShiva Chen // SP to be restored, so we need another base register to record the stack 337cf6cf0cdSShiva Chen // after realignment. 338cf6cf0cdSShiva Chen if (hasBP(MF)) 339cf6cf0cdSShiva Chen FrameReg = RISCVABI::getBPReg(); 340cf6cf0cdSShiva Chen else 341cd44aee3SSam Elliott FrameReg = RISCV::X2; 342cd44aee3SSam Elliott Offset += MF.getFrameInfo().getStackSize(); 343c85be0deSAlex Bradbury } else { 344c85be0deSAlex Bradbury FrameReg = RI->getFrameRegister(MF); 3457d6aa1f7SAlex Bradbury if (hasFP(MF)) 346c85be0deSAlex Bradbury Offset += RVFI->getVarArgsSaveSize(); 3477d6aa1f7SAlex Bradbury else 3487d6aa1f7SAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 349660bccecSAlex Bradbury } 350660bccecSAlex Bradbury return Offset; 351660bccecSAlex Bradbury } 352b014e3deSAlex Bradbury 353b014e3deSAlex Bradbury void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, 354b014e3deSAlex Bradbury BitVector &SavedRegs, 355b014e3deSAlex Bradbury RegScavenger *RS) const { 356b014e3deSAlex Bradbury TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 3577d6aa1f7SAlex Bradbury // Unconditionally spill RA and FP only if the function uses a frame 3587d6aa1f7SAlex Bradbury // pointer. 3597d6aa1f7SAlex Bradbury if (hasFP(MF)) { 360b014e3deSAlex Bradbury SavedRegs.set(RISCV::X1); 361b014e3deSAlex Bradbury SavedRegs.set(RISCV::X8); 362b014e3deSAlex Bradbury } 363cf6cf0cdSShiva Chen // Mark BP as used if function has dedicated base pointer. 364cf6cf0cdSShiva Chen if (hasBP(MF)) 365cf6cf0cdSShiva Chen SavedRegs.set(RISCVABI::getBPReg()); 3662e4106b7SAna Pazos 3672e4106b7SAna Pazos // If interrupt is enabled and there are calls in the handler, 3682e4106b7SAna Pazos // unconditionally save all Caller-saved registers and 3692e4106b7SAna Pazos // all FP registers, regardless whether they are used. 3702e4106b7SAna Pazos MachineFrameInfo &MFI = MF.getFrameInfo(); 3712e4106b7SAna Pazos 3722e4106b7SAna Pazos if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { 3732e4106b7SAna Pazos 3742e4106b7SAna Pazos static const MCPhysReg CSRegs[] = { RISCV::X1, /* ra */ 3752e4106b7SAna Pazos RISCV::X5, RISCV::X6, RISCV::X7, /* t0-t2 */ 3762e4106b7SAna Pazos RISCV::X10, RISCV::X11, /* a0-a1, a2-a7 */ 3772e4106b7SAna Pazos RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17, 3782e4106b7SAna Pazos RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31, 0 /* t3-t6 */ 3792e4106b7SAna Pazos }; 3802e4106b7SAna Pazos 3812e4106b7SAna Pazos for (unsigned i = 0; CSRegs[i]; ++i) 3822e4106b7SAna Pazos SavedRegs.set(CSRegs[i]); 3832e4106b7SAna Pazos 3842e4106b7SAna Pazos if (MF.getSubtarget<RISCVSubtarget>().hasStdExtD() || 3852e4106b7SAna Pazos MF.getSubtarget<RISCVSubtarget>().hasStdExtF()) { 3862e4106b7SAna Pazos 3872e4106b7SAna Pazos // If interrupt is enabled, this list contains all FP registers. 3882e4106b7SAna Pazos const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs(); 3892e4106b7SAna Pazos 3902e4106b7SAna Pazos for (unsigned i = 0; Regs[i]; ++i) 3912e4106b7SAna Pazos if (RISCV::FPR32RegClass.contains(Regs[i]) || 3922e4106b7SAna Pazos RISCV::FPR64RegClass.contains(Regs[i])) 3932e4106b7SAna Pazos SavedRegs.set(Regs[i]); 3942e4106b7SAna Pazos } 3952e4106b7SAna Pazos } 3967d6aa1f7SAlex Bradbury } 3970715d35eSAlex Bradbury 3980715d35eSAlex Bradbury void RISCVFrameLowering::processFunctionBeforeFrameFinalized( 3990715d35eSAlex Bradbury MachineFunction &MF, RegScavenger *RS) const { 4000715d35eSAlex Bradbury const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 4010715d35eSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 4020715d35eSAlex Bradbury const TargetRegisterClass *RC = &RISCV::GPRRegClass; 4030715d35eSAlex Bradbury // estimateStackSize has been observed to under-estimate the final stack 4040715d35eSAlex Bradbury // size, so give ourselves wiggle-room by checking for stack size 4050715d35eSAlex Bradbury // representable an 11-bit signed field rather than 12-bits. 4060715d35eSAlex Bradbury // FIXME: It may be possible to craft a function with a small stack that 4070715d35eSAlex Bradbury // still needs an emergency spill slot for branch relaxation. This case 4080715d35eSAlex Bradbury // would currently be missed. 4090715d35eSAlex Bradbury if (!isInt<11>(MFI.estimateStackSize(MF))) { 4100715d35eSAlex Bradbury int RegScavFI = MFI.CreateStackObject( 4110715d35eSAlex Bradbury RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); 4120715d35eSAlex Bradbury RS->addScavengingFrameIndex(RegScavFI); 4130715d35eSAlex Bradbury } 4140715d35eSAlex Bradbury } 415cbd498acSShiva Chen 416cbd498acSShiva Chen // Not preserve stack space within prologue for outgoing variables when the 417cbd498acSShiva Chen // function contains variable size objects and let eliminateCallFramePseudoInstr 418cbd498acSShiva Chen // preserve stack space for it. 419cbd498acSShiva Chen bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 420cbd498acSShiva Chen return !MF.getFrameInfo().hasVarSizedObjects(); 421cbd498acSShiva Chen } 422cbd498acSShiva Chen 423cbd498acSShiva Chen // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 424cbd498acSShiva Chen MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( 425cbd498acSShiva Chen MachineFunction &MF, MachineBasicBlock &MBB, 426cbd498acSShiva Chen MachineBasicBlock::iterator MI) const { 427fa06e958SLuis Marques Register SPReg = RISCV::X2; 428cbd498acSShiva Chen DebugLoc DL = MI->getDebugLoc(); 429cbd498acSShiva Chen 430cbd498acSShiva Chen if (!hasReservedCallFrame(MF)) { 431cbd498acSShiva Chen // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 432cbd498acSShiva Chen // ADJCALLSTACKUP must be converted to instructions manipulating the stack 433cbd498acSShiva Chen // pointer. This is necessary when there is a variable length stack 434cbd498acSShiva Chen // allocation (e.g. alloca), which means it's not possible to allocate 435cbd498acSShiva Chen // space for outgoing arguments from within the function prologue. 436cbd498acSShiva Chen int64_t Amount = MI->getOperand(0).getImm(); 437cbd498acSShiva Chen 438cbd498acSShiva Chen if (Amount != 0) { 439cbd498acSShiva Chen // Ensure the stack remains aligned after adjustment. 440cbd498acSShiva Chen Amount = alignSPAdjust(Amount); 441cbd498acSShiva Chen 442cbd498acSShiva Chen if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN) 443cbd498acSShiva Chen Amount = -Amount; 444cbd498acSShiva Chen 445cbd498acSShiva Chen adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 446cbd498acSShiva Chen } 447cbd498acSShiva Chen } 448cbd498acSShiva Chen 449cbd498acSShiva Chen return MBB.erase(MI); 450cbd498acSShiva Chen } 451ff55e2e0SShiva Chen 452ff55e2e0SShiva Chen // We would like to split the SP adjustment to reduce prologue/epilogue 453ff55e2e0SShiva Chen // as following instructions. In this way, the offset of the callee saved 454ff55e2e0SShiva Chen // register could fit in a single store. 455ff55e2e0SShiva Chen // add sp,sp,-2032 456ff55e2e0SShiva Chen // sw ra,2028(sp) 457ff55e2e0SShiva Chen // sw s0,2024(sp) 458ff55e2e0SShiva Chen // sw s1,2020(sp) 459ff55e2e0SShiva Chen // sw s3,2012(sp) 460ff55e2e0SShiva Chen // sw s4,2008(sp) 461ff55e2e0SShiva Chen // add sp,sp,-64 462ff55e2e0SShiva Chen uint64_t 463ff55e2e0SShiva Chen RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { 464ff55e2e0SShiva Chen const MachineFrameInfo &MFI = MF.getFrameInfo(); 465ff55e2e0SShiva Chen const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 466ff55e2e0SShiva Chen uint64_t StackSize = MFI.getStackSize(); 467ff55e2e0SShiva Chen uint64_t StackAlign = getStackAlignment(); 468ff55e2e0SShiva Chen 469ff55e2e0SShiva Chen // FIXME: Disable SplitSPAdjust if save-restore libcall enabled when the patch 470ff55e2e0SShiva Chen // landing. The callee saved registers will be pushed by the 471ff55e2e0SShiva Chen // save-restore libcalls, so we don't have to split the SP adjustment 472ff55e2e0SShiva Chen // in this case. 473ff55e2e0SShiva Chen // 474ff55e2e0SShiva Chen // Return the FirstSPAdjustAmount if the StackSize can not fit in signed 475ff55e2e0SShiva Chen // 12-bit and there exists a callee saved register need to be pushed. 476ff55e2e0SShiva Chen if (!isInt<12>(StackSize) && (CSI.size() > 0)) { 477ff55e2e0SShiva Chen // FirstSPAdjustAmount is choosed as (2048 - StackAlign) 478ff55e2e0SShiva Chen // because 2048 will cause sp = sp + 2048 in epilogue split into 479ff55e2e0SShiva Chen // multi-instructions. The offset smaller than 2048 can fit in signle 480ff55e2e0SShiva Chen // load/store instruction and we have to stick with the stack alignment. 481ff55e2e0SShiva Chen // 2048 is 16-byte alignment. The stack alignment for RV32 and RV64 is 16, 482ff55e2e0SShiva Chen // for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment. 483ff55e2e0SShiva Chen return 2048 - StackAlign; 484ff55e2e0SShiva Chen } 485ff55e2e0SShiva Chen return 0; 486ff55e2e0SShiva Chen } 487