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 35b014e3deSAlex Bradbury // Determines the size of the frame and maximum call frame size. 36b014e3deSAlex Bradbury void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { 37b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 38b014e3deSAlex Bradbury const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 39b014e3deSAlex Bradbury 40b014e3deSAlex Bradbury // Get the number of bytes to allocate from the FrameInfo. 41b014e3deSAlex Bradbury uint64_t FrameSize = MFI.getStackSize(); 42b014e3deSAlex Bradbury 43b014e3deSAlex Bradbury // Get the alignment. 44cd44aee3SSam Elliott unsigned StackAlign = getStackAlignment(); 45cd44aee3SSam Elliott if (RI->needsStackRealignment(MF)) { 46cd44aee3SSam Elliott unsigned MaxStackAlign = std::max(StackAlign, MFI.getMaxAlignment()); 47cd44aee3SSam Elliott FrameSize += (MaxStackAlign - StackAlign); 48cd44aee3SSam Elliott StackAlign = MaxStackAlign; 49cd44aee3SSam Elliott } 50cd44aee3SSam Elliott 51cd44aee3SSam Elliott // Set Max Call Frame Size 52cd44aee3SSam Elliott uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign); 53cd44aee3SSam Elliott MFI.setMaxCallFrameSize(MaxCallSize); 54b014e3deSAlex Bradbury 55b014e3deSAlex Bradbury // Make sure the frame is aligned. 56b014e3deSAlex Bradbury FrameSize = alignTo(FrameSize, StackAlign); 57b014e3deSAlex Bradbury 58b014e3deSAlex Bradbury // Update frame info. 59b014e3deSAlex Bradbury MFI.setStackSize(FrameSize); 60b014e3deSAlex Bradbury } 61b014e3deSAlex Bradbury 62b014e3deSAlex Bradbury void RISCVFrameLowering::adjustReg(MachineBasicBlock &MBB, 63b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI, 64fa06e958SLuis Marques const DebugLoc &DL, Register DestReg, 65fa06e958SLuis Marques Register SrcReg, int64_t Val, 66b014e3deSAlex Bradbury MachineInstr::MIFlag Flag) const { 679fea4881SAlex Bradbury MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); 68b014e3deSAlex Bradbury const RISCVInstrInfo *TII = STI.getInstrInfo(); 69b014e3deSAlex Bradbury 70b014e3deSAlex Bradbury if (DestReg == SrcReg && Val == 0) 71b014e3deSAlex Bradbury return; 72b014e3deSAlex Bradbury 739fea4881SAlex Bradbury if (isInt<12>(Val)) { 74b014e3deSAlex Bradbury BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DestReg) 75b014e3deSAlex Bradbury .addReg(SrcReg) 76b014e3deSAlex Bradbury .addImm(Val) 77b014e3deSAlex Bradbury .setMIFlag(Flag); 78a49a16ddSShiva Chen } else { 799fea4881SAlex Bradbury unsigned Opc = RISCV::ADD; 809fea4881SAlex Bradbury bool isSub = Val < 0; 819fea4881SAlex Bradbury if (isSub) { 829fea4881SAlex Bradbury Val = -Val; 839fea4881SAlex Bradbury Opc = RISCV::SUB; 849fea4881SAlex Bradbury } 859fea4881SAlex Bradbury 863836874dSDaniel Sanders Register ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 87a49a16ddSShiva Chen TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag); 889fea4881SAlex Bradbury BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) 899fea4881SAlex Bradbury .addReg(SrcReg) 909fea4881SAlex Bradbury .addReg(ScratchReg, RegState::Kill) 919fea4881SAlex Bradbury .setMIFlag(Flag); 929fea4881SAlex Bradbury } 93b014e3deSAlex Bradbury } 94b014e3deSAlex Bradbury 95b014e3deSAlex Bradbury // Returns the register used to hold the frame pointer. 96fa06e958SLuis Marques static Register getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; } 97b014e3deSAlex Bradbury 98b014e3deSAlex Bradbury // Returns the register used to hold the stack pointer. 99fa06e958SLuis Marques static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; } 100b014e3deSAlex Bradbury 1018971842fSAlex Bradbury void RISCVFrameLowering::emitPrologue(MachineFunction &MF, 102b014e3deSAlex Bradbury MachineBasicBlock &MBB) const { 103b014e3deSAlex Bradbury assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); 104b014e3deSAlex Bradbury 105b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 106c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 10704ddf39bSHsiangkai Wang const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 10804ddf39bSHsiangkai Wang const RISCVInstrInfo *TII = STI.getInstrInfo(); 109b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI = MBB.begin(); 110b014e3deSAlex Bradbury 111cd44aee3SSam Elliott if (RI->needsStackRealignment(MF) && MFI.hasVarSizedObjects()) { 112cd44aee3SSam Elliott report_fatal_error( 113cd44aee3SSam Elliott "RISC-V backend can't currently handle functions that need stack " 114cd44aee3SSam Elliott "realignment and have variable sized objects"); 115cd44aee3SSam Elliott } 116cd44aee3SSam Elliott 117fa06e958SLuis Marques Register FPReg = getFPReg(STI); 118fa06e958SLuis Marques Register SPReg = getSPReg(STI); 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 18404ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa $fp, 0" 18504ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( 18604ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(FPReg, true), 0)); 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); 198ff55e2e0SShiva Chen // Emit ".cfi_def_cfa_offset StackSize" 199ff55e2e0SShiva Chen unsigned CFIIndex = MF.addFrameInst( 200ff55e2e0SShiva Chen MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); 201ff55e2e0SShiva Chen BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 202ff55e2e0SShiva Chen .addCFIIndex(CFIIndex); 203ff55e2e0SShiva Chen } 204ff55e2e0SShiva Chen 205ff55e2e0SShiva Chen if (hasFP(MF)) { 206cd44aee3SSam Elliott // Realign Stack 207cd44aee3SSam Elliott const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 208cd44aee3SSam Elliott if (RI->needsStackRealignment(MF)) { 209cd44aee3SSam Elliott unsigned MaxAlignment = MFI.getMaxAlignment(); 210cd44aee3SSam Elliott 211cd44aee3SSam Elliott const RISCVInstrInfo *TII = STI.getInstrInfo(); 212cd44aee3SSam Elliott if (isInt<12>(-(int)MaxAlignment)) { 213cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) 214cd44aee3SSam Elliott .addReg(SPReg) 215cd44aee3SSam Elliott .addImm(-(int)MaxAlignment); 216cd44aee3SSam Elliott } else { 217cd44aee3SSam Elliott unsigned ShiftAmount = countTrailingZeros(MaxAlignment); 218fa06e958SLuis Marques Register VR = 219cd44aee3SSam Elliott MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); 220cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR) 221cd44aee3SSam Elliott .addReg(SPReg) 222cd44aee3SSam Elliott .addImm(ShiftAmount); 223cd44aee3SSam Elliott BuildMI(MBB, MBBI, DL, TII->get(RISCV::SLLI), SPReg) 224cd44aee3SSam Elliott .addReg(VR) 225cd44aee3SSam Elliott .addImm(ShiftAmount); 226cd44aee3SSam Elliott } 227cd44aee3SSam Elliott } 22804ddf39bSHsiangkai Wang } 229b014e3deSAlex Bradbury } 2308971842fSAlex Bradbury 231*be0fead7SLuís Marques // FIXME Fix emission of .cfi_restore and .cfi_def_cfa CFI directives that can 232*be0fead7SLuís Marques // incorrectly affect subsequent basic blocks. 2338971842fSAlex Bradbury void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, 234b014e3deSAlex Bradbury MachineBasicBlock &MBB) const { 235b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 236b014e3deSAlex Bradbury const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 237b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 238c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 239b014e3deSAlex Bradbury DebugLoc DL = MBBI->getDebugLoc(); 24004ddf39bSHsiangkai Wang const RISCVInstrInfo *TII = STI.getInstrInfo(); 241fa06e958SLuis Marques Register FPReg = getFPReg(STI); 242fa06e958SLuis Marques Register SPReg = getSPReg(STI); 243b014e3deSAlex Bradbury 244b014e3deSAlex Bradbury // Skip to before the restores of callee-saved registers 245b014e3deSAlex Bradbury // FIXME: assumes exactly one instruction is used to restore each 246b014e3deSAlex Bradbury // callee-saved register. 24761b28edeSAna Pazos auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size()); 248b014e3deSAlex Bradbury 249b014e3deSAlex Bradbury uint64_t StackSize = MFI.getStackSize(); 25004ddf39bSHsiangkai Wang uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize(); 251b014e3deSAlex Bradbury 252b014e3deSAlex Bradbury // Restore the stack pointer using the value of the frame pointer. Only 253b014e3deSAlex Bradbury // necessary if the stack pointer was modified, meaning the stack size is 254b014e3deSAlex Bradbury // unknown. 255b014e3deSAlex Bradbury if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { 2567d6aa1f7SAlex Bradbury assert(hasFP(MF) && "frame pointer should not have been eliminated"); 25704ddf39bSHsiangkai Wang adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, 258b014e3deSAlex Bradbury MachineInstr::FrameDestroy); 259b014e3deSAlex Bradbury } 260b014e3deSAlex Bradbury 261ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 262ff55e2e0SShiva Chen if (FirstSPAdjustAmount) { 263ff55e2e0SShiva Chen uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; 264ff55e2e0SShiva Chen assert(SecondSPAdjustAmount > 0 && 265ff55e2e0SShiva Chen "SecondSPAdjustAmount should be greater than zero"); 266ff55e2e0SShiva Chen 267ff55e2e0SShiva Chen adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, 268ff55e2e0SShiva Chen MachineInstr::FrameDestroy); 269ff55e2e0SShiva Chen 270ff55e2e0SShiva Chen // Emit ".cfi_def_cfa_offset FirstSPAdjustAmount" 271ff55e2e0SShiva Chen unsigned CFIIndex = 272ff55e2e0SShiva Chen MF.addFrameInst( 273ff55e2e0SShiva Chen MCCFIInstruction::createDefCfaOffset(nullptr, 274ff55e2e0SShiva Chen -FirstSPAdjustAmount)); 275ff55e2e0SShiva Chen BuildMI(MBB, LastFrameDestroy, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 276ff55e2e0SShiva Chen .addCFIIndex(CFIIndex); 277ff55e2e0SShiva Chen } 278ff55e2e0SShiva Chen 27904ddf39bSHsiangkai Wang if (hasFP(MF)) { 28004ddf39bSHsiangkai Wang // To find the instruction restoring FP from stack. 28104ddf39bSHsiangkai Wang for (auto &I = LastFrameDestroy; I != MBBI; ++I) { 28204ddf39bSHsiangkai Wang if (I->mayLoad() && I->getOperand(0).isReg()) { 2833836874dSDaniel Sanders Register DestReg = I->getOperand(0).getReg(); 28404ddf39bSHsiangkai Wang if (DestReg == FPReg) { 28504ddf39bSHsiangkai Wang // If there is frame pointer, after restoring $fp registers, we 28604ddf39bSHsiangkai Wang // need adjust CFA to ($sp - FPOffset). 28704ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa $sp, -FPOffset" 28804ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( 28904ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(SPReg, true), -FPOffset)); 29004ddf39bSHsiangkai Wang BuildMI(MBB, std::next(I), DL, 29104ddf39bSHsiangkai Wang TII->get(TargetOpcode::CFI_INSTRUCTION)) 29204ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 29304ddf39bSHsiangkai Wang break; 29404ddf39bSHsiangkai Wang } 29504ddf39bSHsiangkai Wang } 29604ddf39bSHsiangkai Wang } 29704ddf39bSHsiangkai Wang } 29804ddf39bSHsiangkai Wang 29904ddf39bSHsiangkai Wang // Add CFI directives for callee-saved registers. 30004ddf39bSHsiangkai Wang const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 30104ddf39bSHsiangkai Wang // Iterate over list of callee-saved registers and emit .cfi_restore 30204ddf39bSHsiangkai Wang // directives. 30304ddf39bSHsiangkai Wang for (const auto &Entry : CSI) { 304fa06e958SLuis Marques Register Reg = Entry.getReg(); 30504ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore( 30604ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(Reg, true))); 30704ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 30804ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 30904ddf39bSHsiangkai Wang } 31004ddf39bSHsiangkai Wang 311ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 312ff55e2e0SShiva Chen StackSize = FirstSPAdjustAmount; 313ff55e2e0SShiva Chen 314b014e3deSAlex Bradbury // Deallocate stack 315b014e3deSAlex Bradbury adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); 31604ddf39bSHsiangkai Wang 31704ddf39bSHsiangkai Wang // After restoring $sp, we need to adjust CFA to $(sp + 0) 31804ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa_offset 0" 31904ddf39bSHsiangkai Wang unsigned CFIIndex = 32004ddf39bSHsiangkai Wang MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0)); 32104ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 32204ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 323b014e3deSAlex Bradbury } 324660bccecSAlex Bradbury 325660bccecSAlex Bradbury int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, 326660bccecSAlex Bradbury int FI, 327660bccecSAlex Bradbury unsigned &FrameReg) const { 328660bccecSAlex Bradbury const MachineFrameInfo &MFI = MF.getFrameInfo(); 329660bccecSAlex Bradbury const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 330c85be0deSAlex Bradbury const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 331660bccecSAlex Bradbury 332660bccecSAlex Bradbury // Callee-saved registers should be referenced relative to the stack 333660bccecSAlex Bradbury // pointer (positive offset), otherwise use the frame pointer (negative 334660bccecSAlex Bradbury // offset). 335660bccecSAlex Bradbury const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 336660bccecSAlex Bradbury int MinCSFI = 0; 337660bccecSAlex Bradbury int MaxCSFI = -1; 338660bccecSAlex Bradbury 339660bccecSAlex Bradbury int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + 340660bccecSAlex Bradbury MFI.getOffsetAdjustment(); 341660bccecSAlex Bradbury 342ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 343ff55e2e0SShiva Chen 344660bccecSAlex Bradbury if (CSI.size()) { 345660bccecSAlex Bradbury MinCSFI = CSI[0].getFrameIdx(); 346660bccecSAlex Bradbury MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 347660bccecSAlex Bradbury } 348660bccecSAlex Bradbury 349660bccecSAlex Bradbury if (FI >= MinCSFI && FI <= MaxCSFI) { 350660bccecSAlex Bradbury FrameReg = RISCV::X2; 351ff55e2e0SShiva Chen 352ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 353ff55e2e0SShiva Chen Offset += FirstSPAdjustAmount; 354ff55e2e0SShiva Chen else 355660bccecSAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 356cd44aee3SSam Elliott } else if (RI->needsStackRealignment(MF)) { 357cd44aee3SSam Elliott assert(!MFI.hasVarSizedObjects() && 358cd44aee3SSam Elliott "Unexpected combination of stack realignment and varsized objects"); 359cd44aee3SSam Elliott // If the stack was realigned, the frame pointer is set in order to allow 360cd44aee3SSam Elliott // SP to be restored, but we still access stack objects using SP. 361cd44aee3SSam Elliott FrameReg = RISCV::X2; 362cd44aee3SSam Elliott Offset += MF.getFrameInfo().getStackSize(); 363c85be0deSAlex Bradbury } else { 364c85be0deSAlex Bradbury FrameReg = RI->getFrameRegister(MF); 3657d6aa1f7SAlex Bradbury if (hasFP(MF)) 366c85be0deSAlex Bradbury Offset += RVFI->getVarArgsSaveSize(); 3677d6aa1f7SAlex Bradbury else 3687d6aa1f7SAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 369660bccecSAlex Bradbury } 370660bccecSAlex Bradbury return Offset; 371660bccecSAlex Bradbury } 372b014e3deSAlex Bradbury 373b014e3deSAlex Bradbury void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, 374b014e3deSAlex Bradbury BitVector &SavedRegs, 375b014e3deSAlex Bradbury RegScavenger *RS) const { 376b014e3deSAlex Bradbury TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 3777d6aa1f7SAlex Bradbury // Unconditionally spill RA and FP only if the function uses a frame 3787d6aa1f7SAlex Bradbury // pointer. 3797d6aa1f7SAlex Bradbury if (hasFP(MF)) { 380b014e3deSAlex Bradbury SavedRegs.set(RISCV::X1); 381b014e3deSAlex Bradbury SavedRegs.set(RISCV::X8); 382b014e3deSAlex Bradbury } 3832e4106b7SAna Pazos 3842e4106b7SAna Pazos // If interrupt is enabled and there are calls in the handler, 3852e4106b7SAna Pazos // unconditionally save all Caller-saved registers and 3862e4106b7SAna Pazos // all FP registers, regardless whether they are used. 3872e4106b7SAna Pazos MachineFrameInfo &MFI = MF.getFrameInfo(); 3882e4106b7SAna Pazos 3892e4106b7SAna Pazos if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { 3902e4106b7SAna Pazos 3912e4106b7SAna Pazos static const MCPhysReg CSRegs[] = { RISCV::X1, /* ra */ 3922e4106b7SAna Pazos RISCV::X5, RISCV::X6, RISCV::X7, /* t0-t2 */ 3932e4106b7SAna Pazos RISCV::X10, RISCV::X11, /* a0-a1, a2-a7 */ 3942e4106b7SAna Pazos RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17, 3952e4106b7SAna Pazos RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31, 0 /* t3-t6 */ 3962e4106b7SAna Pazos }; 3972e4106b7SAna Pazos 3982e4106b7SAna Pazos for (unsigned i = 0; CSRegs[i]; ++i) 3992e4106b7SAna Pazos SavedRegs.set(CSRegs[i]); 4002e4106b7SAna Pazos 4012e4106b7SAna Pazos if (MF.getSubtarget<RISCVSubtarget>().hasStdExtD() || 4022e4106b7SAna Pazos MF.getSubtarget<RISCVSubtarget>().hasStdExtF()) { 4032e4106b7SAna Pazos 4042e4106b7SAna Pazos // If interrupt is enabled, this list contains all FP registers. 4052e4106b7SAna Pazos const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs(); 4062e4106b7SAna Pazos 4072e4106b7SAna Pazos for (unsigned i = 0; Regs[i]; ++i) 4082e4106b7SAna Pazos if (RISCV::FPR32RegClass.contains(Regs[i]) || 4092e4106b7SAna Pazos RISCV::FPR64RegClass.contains(Regs[i])) 4102e4106b7SAna Pazos SavedRegs.set(Regs[i]); 4112e4106b7SAna Pazos } 4122e4106b7SAna Pazos } 4137d6aa1f7SAlex Bradbury } 4140715d35eSAlex Bradbury 4150715d35eSAlex Bradbury void RISCVFrameLowering::processFunctionBeforeFrameFinalized( 4160715d35eSAlex Bradbury MachineFunction &MF, RegScavenger *RS) const { 4170715d35eSAlex Bradbury const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 4180715d35eSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 4190715d35eSAlex Bradbury const TargetRegisterClass *RC = &RISCV::GPRRegClass; 4200715d35eSAlex Bradbury // estimateStackSize has been observed to under-estimate the final stack 4210715d35eSAlex Bradbury // size, so give ourselves wiggle-room by checking for stack size 4220715d35eSAlex Bradbury // representable an 11-bit signed field rather than 12-bits. 4230715d35eSAlex Bradbury // FIXME: It may be possible to craft a function with a small stack that 4240715d35eSAlex Bradbury // still needs an emergency spill slot for branch relaxation. This case 4250715d35eSAlex Bradbury // would currently be missed. 4260715d35eSAlex Bradbury if (!isInt<11>(MFI.estimateStackSize(MF))) { 4270715d35eSAlex Bradbury int RegScavFI = MFI.CreateStackObject( 4280715d35eSAlex Bradbury RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); 4290715d35eSAlex Bradbury RS->addScavengingFrameIndex(RegScavFI); 4300715d35eSAlex Bradbury } 4310715d35eSAlex Bradbury } 432cbd498acSShiva Chen 433cbd498acSShiva Chen // Not preserve stack space within prologue for outgoing variables when the 434cbd498acSShiva Chen // function contains variable size objects and let eliminateCallFramePseudoInstr 435cbd498acSShiva Chen // preserve stack space for it. 436cbd498acSShiva Chen bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 437cbd498acSShiva Chen return !MF.getFrameInfo().hasVarSizedObjects(); 438cbd498acSShiva Chen } 439cbd498acSShiva Chen 440cbd498acSShiva Chen // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 441cbd498acSShiva Chen MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( 442cbd498acSShiva Chen MachineFunction &MF, MachineBasicBlock &MBB, 443cbd498acSShiva Chen MachineBasicBlock::iterator MI) const { 444fa06e958SLuis Marques Register SPReg = RISCV::X2; 445cbd498acSShiva Chen DebugLoc DL = MI->getDebugLoc(); 446cbd498acSShiva Chen 447cbd498acSShiva Chen if (!hasReservedCallFrame(MF)) { 448cbd498acSShiva Chen // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 449cbd498acSShiva Chen // ADJCALLSTACKUP must be converted to instructions manipulating the stack 450cbd498acSShiva Chen // pointer. This is necessary when there is a variable length stack 451cbd498acSShiva Chen // allocation (e.g. alloca), which means it's not possible to allocate 452cbd498acSShiva Chen // space for outgoing arguments from within the function prologue. 453cbd498acSShiva Chen int64_t Amount = MI->getOperand(0).getImm(); 454cbd498acSShiva Chen 455cbd498acSShiva Chen if (Amount != 0) { 456cbd498acSShiva Chen // Ensure the stack remains aligned after adjustment. 457cbd498acSShiva Chen Amount = alignSPAdjust(Amount); 458cbd498acSShiva Chen 459cbd498acSShiva Chen if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN) 460cbd498acSShiva Chen Amount = -Amount; 461cbd498acSShiva Chen 462cbd498acSShiva Chen adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 463cbd498acSShiva Chen } 464cbd498acSShiva Chen } 465cbd498acSShiva Chen 466cbd498acSShiva Chen return MBB.erase(MI); 467cbd498acSShiva Chen } 468ff55e2e0SShiva Chen 469ff55e2e0SShiva Chen // We would like to split the SP adjustment to reduce prologue/epilogue 470ff55e2e0SShiva Chen // as following instructions. In this way, the offset of the callee saved 471ff55e2e0SShiva Chen // register could fit in a single store. 472ff55e2e0SShiva Chen // add sp,sp,-2032 473ff55e2e0SShiva Chen // sw ra,2028(sp) 474ff55e2e0SShiva Chen // sw s0,2024(sp) 475ff55e2e0SShiva Chen // sw s1,2020(sp) 476ff55e2e0SShiva Chen // sw s3,2012(sp) 477ff55e2e0SShiva Chen // sw s4,2008(sp) 478ff55e2e0SShiva Chen // add sp,sp,-64 479ff55e2e0SShiva Chen uint64_t 480ff55e2e0SShiva Chen RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { 481ff55e2e0SShiva Chen const MachineFrameInfo &MFI = MF.getFrameInfo(); 482ff55e2e0SShiva Chen const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 483ff55e2e0SShiva Chen uint64_t StackSize = MFI.getStackSize(); 484ff55e2e0SShiva Chen uint64_t StackAlign = getStackAlignment(); 485ff55e2e0SShiva Chen 486ff55e2e0SShiva Chen // FIXME: Disable SplitSPAdjust if save-restore libcall enabled when the patch 487ff55e2e0SShiva Chen // landing. The callee saved registers will be pushed by the 488ff55e2e0SShiva Chen // save-restore libcalls, so we don't have to split the SP adjustment 489ff55e2e0SShiva Chen // in this case. 490ff55e2e0SShiva Chen // 491ff55e2e0SShiva Chen // Return the FirstSPAdjustAmount if the StackSize can not fit in signed 492ff55e2e0SShiva Chen // 12-bit and there exists a callee saved register need to be pushed. 493ff55e2e0SShiva Chen if (!isInt<12>(StackSize) && (CSI.size() > 0)) { 494ff55e2e0SShiva Chen // FirstSPAdjustAmount is choosed as (2048 - StackAlign) 495ff55e2e0SShiva Chen // because 2048 will cause sp = sp + 2048 in epilogue split into 496ff55e2e0SShiva Chen // multi-instructions. The offset smaller than 2048 can fit in signle 497ff55e2e0SShiva Chen // load/store instruction and we have to stick with the stack alignment. 498ff55e2e0SShiva Chen // 2048 is 16-byte alignment. The stack alignment for RV32 and RV64 is 16, 499ff55e2e0SShiva Chen // for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment. 500ff55e2e0SShiva Chen return 2048 - StackAlign; 501ff55e2e0SShiva Chen } 502ff55e2e0SShiva Chen return 0; 503ff55e2e0SShiva Chen } 504