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); 198*1c737f54SLuís Marques 199*1c737f54SLuís Marques // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", 200*1c737f54SLuís Marques // don't emit an sp-based .cfi_def_cfa_offset 201*1c737f54SLuí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 } 208*1c737f54SLuí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 } 232cd44aee3SSam Elliott } 23304ddf39bSHsiangkai Wang } 234b014e3deSAlex Bradbury } 2358971842fSAlex Bradbury 236be0fead7SLuís Marques // FIXME Fix emission of .cfi_restore and .cfi_def_cfa CFI directives that can 237be0fead7SLuís Marques // incorrectly affect subsequent basic blocks. 2388971842fSAlex Bradbury void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, 239b014e3deSAlex Bradbury MachineBasicBlock &MBB) const { 240b014e3deSAlex Bradbury MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 241b014e3deSAlex Bradbury const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 242b014e3deSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 243c85be0deSAlex Bradbury auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 244b014e3deSAlex Bradbury DebugLoc DL = MBBI->getDebugLoc(); 24504ddf39bSHsiangkai Wang const RISCVInstrInfo *TII = STI.getInstrInfo(); 246fa06e958SLuis Marques Register FPReg = getFPReg(STI); 247fa06e958SLuis Marques Register SPReg = getSPReg(STI); 248b014e3deSAlex Bradbury 249b014e3deSAlex Bradbury // Skip to before the restores of callee-saved registers 250b014e3deSAlex Bradbury // FIXME: assumes exactly one instruction is used to restore each 251b014e3deSAlex Bradbury // callee-saved register. 25261b28edeSAna Pazos auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size()); 253b014e3deSAlex Bradbury 254b014e3deSAlex Bradbury uint64_t StackSize = MFI.getStackSize(); 25504ddf39bSHsiangkai Wang uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize(); 256b014e3deSAlex Bradbury 257b014e3deSAlex Bradbury // Restore the stack pointer using the value of the frame pointer. Only 258b014e3deSAlex Bradbury // necessary if the stack pointer was modified, meaning the stack size is 259b014e3deSAlex Bradbury // unknown. 260b014e3deSAlex Bradbury if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { 2617d6aa1f7SAlex Bradbury assert(hasFP(MF) && "frame pointer should not have been eliminated"); 26204ddf39bSHsiangkai Wang adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, 263b014e3deSAlex Bradbury MachineInstr::FrameDestroy); 264b014e3deSAlex Bradbury } 265b014e3deSAlex Bradbury 266ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 267ff55e2e0SShiva Chen if (FirstSPAdjustAmount) { 268ff55e2e0SShiva Chen uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; 269ff55e2e0SShiva Chen assert(SecondSPAdjustAmount > 0 && 270ff55e2e0SShiva Chen "SecondSPAdjustAmount should be greater than zero"); 271ff55e2e0SShiva Chen 272ff55e2e0SShiva Chen adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, 273ff55e2e0SShiva Chen MachineInstr::FrameDestroy); 274ff55e2e0SShiva Chen 275*1c737f54SLuís Marques // Emit ".cfi_def_cfa_offset FirstSPAdjustAmount" if using an sp-based CFA 276*1c737f54SLuís Marques if (!hasFP(MF)) { 277*1c737f54SLuís Marques unsigned CFIIndex = MF.addFrameInst( 278*1c737f54SLuís Marques MCCFIInstruction::createDefCfaOffset(nullptr, -FirstSPAdjustAmount)); 279*1c737f54SLuís Marques BuildMI(MBB, LastFrameDestroy, DL, 280*1c737f54SLuís Marques TII->get(TargetOpcode::CFI_INSTRUCTION)) 281ff55e2e0SShiva Chen .addCFIIndex(CFIIndex); 282ff55e2e0SShiva Chen } 283*1c737f54SLuís Marques } 284ff55e2e0SShiva Chen 28504ddf39bSHsiangkai Wang if (hasFP(MF)) { 28604ddf39bSHsiangkai Wang // To find the instruction restoring FP from stack. 28704ddf39bSHsiangkai Wang for (auto &I = LastFrameDestroy; I != MBBI; ++I) { 28804ddf39bSHsiangkai Wang if (I->mayLoad() && I->getOperand(0).isReg()) { 2893836874dSDaniel Sanders Register DestReg = I->getOperand(0).getReg(); 29004ddf39bSHsiangkai Wang if (DestReg == FPReg) { 29104ddf39bSHsiangkai Wang // If there is frame pointer, after restoring $fp registers, we 292*1c737f54SLuís Marques // need adjust CFA back to the correct sp-based offset. 293*1c737f54SLuís Marques // Emit ".cfi_def_cfa $sp, CFAOffset" 294*1c737f54SLuís Marques uint64_t CFAOffset = 295*1c737f54SLuís Marques FirstSPAdjustAmount 296*1c737f54SLuís Marques ? -FirstSPAdjustAmount + RVFI->getVarArgsSaveSize() 297*1c737f54SLuís Marques : -FPOffset; 29804ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( 299*1c737f54SLuís Marques nullptr, RI->getDwarfRegNum(SPReg, true), CFAOffset)); 30004ddf39bSHsiangkai Wang BuildMI(MBB, std::next(I), DL, 30104ddf39bSHsiangkai Wang TII->get(TargetOpcode::CFI_INSTRUCTION)) 30204ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 30304ddf39bSHsiangkai Wang break; 30404ddf39bSHsiangkai Wang } 30504ddf39bSHsiangkai Wang } 30604ddf39bSHsiangkai Wang } 30704ddf39bSHsiangkai Wang } 30804ddf39bSHsiangkai Wang 30904ddf39bSHsiangkai Wang // Add CFI directives for callee-saved registers. 31004ddf39bSHsiangkai Wang const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 31104ddf39bSHsiangkai Wang // Iterate over list of callee-saved registers and emit .cfi_restore 31204ddf39bSHsiangkai Wang // directives. 31304ddf39bSHsiangkai Wang for (const auto &Entry : CSI) { 314fa06e958SLuis Marques Register Reg = Entry.getReg(); 31504ddf39bSHsiangkai Wang unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore( 31604ddf39bSHsiangkai Wang nullptr, RI->getDwarfRegNum(Reg, true))); 31704ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 31804ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 31904ddf39bSHsiangkai Wang } 32004ddf39bSHsiangkai Wang 321ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 322ff55e2e0SShiva Chen StackSize = FirstSPAdjustAmount; 323ff55e2e0SShiva Chen 324b014e3deSAlex Bradbury // Deallocate stack 325b014e3deSAlex Bradbury adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); 32604ddf39bSHsiangkai Wang 32704ddf39bSHsiangkai Wang // After restoring $sp, we need to adjust CFA to $(sp + 0) 32804ddf39bSHsiangkai Wang // Emit ".cfi_def_cfa_offset 0" 32904ddf39bSHsiangkai Wang unsigned CFIIndex = 33004ddf39bSHsiangkai Wang MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0)); 33104ddf39bSHsiangkai Wang BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 33204ddf39bSHsiangkai Wang .addCFIIndex(CFIIndex); 333b014e3deSAlex Bradbury } 334660bccecSAlex Bradbury 335660bccecSAlex Bradbury int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, 336660bccecSAlex Bradbury int FI, 337660bccecSAlex Bradbury unsigned &FrameReg) const { 338660bccecSAlex Bradbury const MachineFrameInfo &MFI = MF.getFrameInfo(); 339660bccecSAlex Bradbury const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 340c85be0deSAlex Bradbury const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 341660bccecSAlex Bradbury 342660bccecSAlex Bradbury // Callee-saved registers should be referenced relative to the stack 343660bccecSAlex Bradbury // pointer (positive offset), otherwise use the frame pointer (negative 344660bccecSAlex Bradbury // offset). 345660bccecSAlex Bradbury const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 346660bccecSAlex Bradbury int MinCSFI = 0; 347660bccecSAlex Bradbury int MaxCSFI = -1; 348660bccecSAlex Bradbury 349660bccecSAlex Bradbury int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + 350660bccecSAlex Bradbury MFI.getOffsetAdjustment(); 351660bccecSAlex Bradbury 352ff55e2e0SShiva Chen uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 353ff55e2e0SShiva Chen 354660bccecSAlex Bradbury if (CSI.size()) { 355660bccecSAlex Bradbury MinCSFI = CSI[0].getFrameIdx(); 356660bccecSAlex Bradbury MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 357660bccecSAlex Bradbury } 358660bccecSAlex Bradbury 359660bccecSAlex Bradbury if (FI >= MinCSFI && FI <= MaxCSFI) { 360660bccecSAlex Bradbury FrameReg = RISCV::X2; 361ff55e2e0SShiva Chen 362ff55e2e0SShiva Chen if (FirstSPAdjustAmount) 363ff55e2e0SShiva Chen Offset += FirstSPAdjustAmount; 364ff55e2e0SShiva Chen else 365660bccecSAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 366cd44aee3SSam Elliott } else if (RI->needsStackRealignment(MF)) { 367cd44aee3SSam Elliott assert(!MFI.hasVarSizedObjects() && 368cd44aee3SSam Elliott "Unexpected combination of stack realignment and varsized objects"); 369cd44aee3SSam Elliott // If the stack was realigned, the frame pointer is set in order to allow 370cd44aee3SSam Elliott // SP to be restored, but we still access stack objects using SP. 371cd44aee3SSam Elliott FrameReg = RISCV::X2; 372cd44aee3SSam Elliott Offset += MF.getFrameInfo().getStackSize(); 373c85be0deSAlex Bradbury } else { 374c85be0deSAlex Bradbury FrameReg = RI->getFrameRegister(MF); 3757d6aa1f7SAlex Bradbury if (hasFP(MF)) 376c85be0deSAlex Bradbury Offset += RVFI->getVarArgsSaveSize(); 3777d6aa1f7SAlex Bradbury else 3787d6aa1f7SAlex Bradbury Offset += MF.getFrameInfo().getStackSize(); 379660bccecSAlex Bradbury } 380660bccecSAlex Bradbury return Offset; 381660bccecSAlex Bradbury } 382b014e3deSAlex Bradbury 383b014e3deSAlex Bradbury void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, 384b014e3deSAlex Bradbury BitVector &SavedRegs, 385b014e3deSAlex Bradbury RegScavenger *RS) const { 386b014e3deSAlex Bradbury TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 3877d6aa1f7SAlex Bradbury // Unconditionally spill RA and FP only if the function uses a frame 3887d6aa1f7SAlex Bradbury // pointer. 3897d6aa1f7SAlex Bradbury if (hasFP(MF)) { 390b014e3deSAlex Bradbury SavedRegs.set(RISCV::X1); 391b014e3deSAlex Bradbury SavedRegs.set(RISCV::X8); 392b014e3deSAlex Bradbury } 3932e4106b7SAna Pazos 3942e4106b7SAna Pazos // If interrupt is enabled and there are calls in the handler, 3952e4106b7SAna Pazos // unconditionally save all Caller-saved registers and 3962e4106b7SAna Pazos // all FP registers, regardless whether they are used. 3972e4106b7SAna Pazos MachineFrameInfo &MFI = MF.getFrameInfo(); 3982e4106b7SAna Pazos 3992e4106b7SAna Pazos if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { 4002e4106b7SAna Pazos 4012e4106b7SAna Pazos static const MCPhysReg CSRegs[] = { RISCV::X1, /* ra */ 4022e4106b7SAna Pazos RISCV::X5, RISCV::X6, RISCV::X7, /* t0-t2 */ 4032e4106b7SAna Pazos RISCV::X10, RISCV::X11, /* a0-a1, a2-a7 */ 4042e4106b7SAna Pazos RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17, 4052e4106b7SAna Pazos RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31, 0 /* t3-t6 */ 4062e4106b7SAna Pazos }; 4072e4106b7SAna Pazos 4082e4106b7SAna Pazos for (unsigned i = 0; CSRegs[i]; ++i) 4092e4106b7SAna Pazos SavedRegs.set(CSRegs[i]); 4102e4106b7SAna Pazos 4112e4106b7SAna Pazos if (MF.getSubtarget<RISCVSubtarget>().hasStdExtD() || 4122e4106b7SAna Pazos MF.getSubtarget<RISCVSubtarget>().hasStdExtF()) { 4132e4106b7SAna Pazos 4142e4106b7SAna Pazos // If interrupt is enabled, this list contains all FP registers. 4152e4106b7SAna Pazos const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs(); 4162e4106b7SAna Pazos 4172e4106b7SAna Pazos for (unsigned i = 0; Regs[i]; ++i) 4182e4106b7SAna Pazos if (RISCV::FPR32RegClass.contains(Regs[i]) || 4192e4106b7SAna Pazos RISCV::FPR64RegClass.contains(Regs[i])) 4202e4106b7SAna Pazos SavedRegs.set(Regs[i]); 4212e4106b7SAna Pazos } 4222e4106b7SAna Pazos } 4237d6aa1f7SAlex Bradbury } 4240715d35eSAlex Bradbury 4250715d35eSAlex Bradbury void RISCVFrameLowering::processFunctionBeforeFrameFinalized( 4260715d35eSAlex Bradbury MachineFunction &MF, RegScavenger *RS) const { 4270715d35eSAlex Bradbury const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 4280715d35eSAlex Bradbury MachineFrameInfo &MFI = MF.getFrameInfo(); 4290715d35eSAlex Bradbury const TargetRegisterClass *RC = &RISCV::GPRRegClass; 4300715d35eSAlex Bradbury // estimateStackSize has been observed to under-estimate the final stack 4310715d35eSAlex Bradbury // size, so give ourselves wiggle-room by checking for stack size 4320715d35eSAlex Bradbury // representable an 11-bit signed field rather than 12-bits. 4330715d35eSAlex Bradbury // FIXME: It may be possible to craft a function with a small stack that 4340715d35eSAlex Bradbury // still needs an emergency spill slot for branch relaxation. This case 4350715d35eSAlex Bradbury // would currently be missed. 4360715d35eSAlex Bradbury if (!isInt<11>(MFI.estimateStackSize(MF))) { 4370715d35eSAlex Bradbury int RegScavFI = MFI.CreateStackObject( 4380715d35eSAlex Bradbury RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); 4390715d35eSAlex Bradbury RS->addScavengingFrameIndex(RegScavFI); 4400715d35eSAlex Bradbury } 4410715d35eSAlex Bradbury } 442cbd498acSShiva Chen 443cbd498acSShiva Chen // Not preserve stack space within prologue for outgoing variables when the 444cbd498acSShiva Chen // function contains variable size objects and let eliminateCallFramePseudoInstr 445cbd498acSShiva Chen // preserve stack space for it. 446cbd498acSShiva Chen bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 447cbd498acSShiva Chen return !MF.getFrameInfo().hasVarSizedObjects(); 448cbd498acSShiva Chen } 449cbd498acSShiva Chen 450cbd498acSShiva Chen // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 451cbd498acSShiva Chen MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( 452cbd498acSShiva Chen MachineFunction &MF, MachineBasicBlock &MBB, 453cbd498acSShiva Chen MachineBasicBlock::iterator MI) const { 454fa06e958SLuis Marques Register SPReg = RISCV::X2; 455cbd498acSShiva Chen DebugLoc DL = MI->getDebugLoc(); 456cbd498acSShiva Chen 457cbd498acSShiva Chen if (!hasReservedCallFrame(MF)) { 458cbd498acSShiva Chen // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 459cbd498acSShiva Chen // ADJCALLSTACKUP must be converted to instructions manipulating the stack 460cbd498acSShiva Chen // pointer. This is necessary when there is a variable length stack 461cbd498acSShiva Chen // allocation (e.g. alloca), which means it's not possible to allocate 462cbd498acSShiva Chen // space for outgoing arguments from within the function prologue. 463cbd498acSShiva Chen int64_t Amount = MI->getOperand(0).getImm(); 464cbd498acSShiva Chen 465cbd498acSShiva Chen if (Amount != 0) { 466cbd498acSShiva Chen // Ensure the stack remains aligned after adjustment. 467cbd498acSShiva Chen Amount = alignSPAdjust(Amount); 468cbd498acSShiva Chen 469cbd498acSShiva Chen if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN) 470cbd498acSShiva Chen Amount = -Amount; 471cbd498acSShiva Chen 472cbd498acSShiva Chen adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 473cbd498acSShiva Chen } 474cbd498acSShiva Chen } 475cbd498acSShiva Chen 476cbd498acSShiva Chen return MBB.erase(MI); 477cbd498acSShiva Chen } 478ff55e2e0SShiva Chen 479ff55e2e0SShiva Chen // We would like to split the SP adjustment to reduce prologue/epilogue 480ff55e2e0SShiva Chen // as following instructions. In this way, the offset of the callee saved 481ff55e2e0SShiva Chen // register could fit in a single store. 482ff55e2e0SShiva Chen // add sp,sp,-2032 483ff55e2e0SShiva Chen // sw ra,2028(sp) 484ff55e2e0SShiva Chen // sw s0,2024(sp) 485ff55e2e0SShiva Chen // sw s1,2020(sp) 486ff55e2e0SShiva Chen // sw s3,2012(sp) 487ff55e2e0SShiva Chen // sw s4,2008(sp) 488ff55e2e0SShiva Chen // add sp,sp,-64 489ff55e2e0SShiva Chen uint64_t 490ff55e2e0SShiva Chen RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { 491ff55e2e0SShiva Chen const MachineFrameInfo &MFI = MF.getFrameInfo(); 492ff55e2e0SShiva Chen const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 493ff55e2e0SShiva Chen uint64_t StackSize = MFI.getStackSize(); 494ff55e2e0SShiva Chen uint64_t StackAlign = getStackAlignment(); 495ff55e2e0SShiva Chen 496ff55e2e0SShiva Chen // FIXME: Disable SplitSPAdjust if save-restore libcall enabled when the patch 497ff55e2e0SShiva Chen // landing. The callee saved registers will be pushed by the 498ff55e2e0SShiva Chen // save-restore libcalls, so we don't have to split the SP adjustment 499ff55e2e0SShiva Chen // in this case. 500ff55e2e0SShiva Chen // 501ff55e2e0SShiva Chen // Return the FirstSPAdjustAmount if the StackSize can not fit in signed 502ff55e2e0SShiva Chen // 12-bit and there exists a callee saved register need to be pushed. 503ff55e2e0SShiva Chen if (!isInt<12>(StackSize) && (CSI.size() > 0)) { 504ff55e2e0SShiva Chen // FirstSPAdjustAmount is choosed as (2048 - StackAlign) 505ff55e2e0SShiva Chen // because 2048 will cause sp = sp + 2048 in epilogue split into 506ff55e2e0SShiva Chen // multi-instructions. The offset smaller than 2048 can fit in signle 507ff55e2e0SShiva Chen // load/store instruction and we have to stick with the stack alignment. 508ff55e2e0SShiva Chen // 2048 is 16-byte alignment. The stack alignment for RV32 and RV64 is 16, 509ff55e2e0SShiva Chen // for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment. 510ff55e2e0SShiva Chen return 2048 - StackAlign; 511ff55e2e0SShiva Chen } 512ff55e2e0SShiva Chen return 0; 513ff55e2e0SShiva Chen } 514