106c3fb27SDimitry Andric //===-- RISCVFrameLowering.cpp - RISC-V Frame Information -----------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 906c3fb27SDimitry Andric // This file contains the RISC-V implementation of TargetFrameLowering class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "RISCVFrameLowering.h" 140b57cec5SDimitry Andric #include "RISCVMachineFunctionInfo.h" 150b57cec5SDimitry Andric #include "RISCVSubtarget.h" 16bdd1243dSDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 22480093f4SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 230b57cec5SDimitry Andric #include "llvm/MC/MCDwarf.h" 24bdd1243dSDimitry Andric #include "llvm/Support/LEB128.h" 250b57cec5SDimitry Andric 2681ad6265SDimitry Andric #include <algorithm> 2781ad6265SDimitry Andric 280b57cec5SDimitry Andric using namespace llvm; 290b57cec5SDimitry Andric 307a6dacacSDimitry Andric static Align getABIStackAlignment(RISCVABI::ABI ABI) { 317a6dacacSDimitry Andric if (ABI == RISCVABI::ABI_ILP32E) 327a6dacacSDimitry Andric return Align(4); 337a6dacacSDimitry Andric if (ABI == RISCVABI::ABI_LP64E) 347a6dacacSDimitry Andric return Align(8); 357a6dacacSDimitry Andric return Align(16); 367a6dacacSDimitry Andric } 377a6dacacSDimitry Andric 387a6dacacSDimitry Andric RISCVFrameLowering::RISCVFrameLowering(const RISCVSubtarget &STI) 39*0fca6ea1SDimitry Andric : TargetFrameLowering( 40*0fca6ea1SDimitry Andric StackGrowsDown, getABIStackAlignment(STI.getTargetABI()), 417a6dacacSDimitry Andric /*LocalAreaOffset=*/0, 42*0fca6ea1SDimitry Andric /*TransientStackAlignment=*/getABIStackAlignment(STI.getTargetABI())), 437a6dacacSDimitry Andric STI(STI) {} 447a6dacacSDimitry Andric 45*0fca6ea1SDimitry Andric // Offsets which need to be scale by XLen representing locations of CSRs which 46*0fca6ea1SDimitry Andric // are given a fixed location by save/restore libcalls or Zcmp Push/Pop. 47*0fca6ea1SDimitry Andric static const std::pair<MCPhysReg, int8_t> FixedCSRFIMap[] = { 48*0fca6ea1SDimitry Andric {/*ra*/ RISCV::X1, -1}, {/*s0*/ RISCV::X8, -2}, 49*0fca6ea1SDimitry Andric {/*s1*/ RISCV::X9, -3}, {/*s2*/ RISCV::X18, -4}, 50*0fca6ea1SDimitry Andric {/*s3*/ RISCV::X19, -5}, {/*s4*/ RISCV::X20, -6}, 51*0fca6ea1SDimitry Andric {/*s5*/ RISCV::X21, -7}, {/*s6*/ RISCV::X22, -8}, 52*0fca6ea1SDimitry Andric {/*s7*/ RISCV::X23, -9}, {/*s8*/ RISCV::X24, -10}, 53*0fca6ea1SDimitry Andric {/*s9*/ RISCV::X25, -11}, {/*s10*/ RISCV::X26, -12}, 54*0fca6ea1SDimitry Andric {/*s11*/ RISCV::X27, -13}}; 5506c3fb27SDimitry Andric 5606c3fb27SDimitry Andric // For now we use x3, a.k.a gp, as pointer to shadow call stack. 5706c3fb27SDimitry Andric // User should not use x3 in their asm. 58e8d8bef9SDimitry Andric static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB, 59e8d8bef9SDimitry Andric MachineBasicBlock::iterator MI, 60e8d8bef9SDimitry Andric const DebugLoc &DL) { 61e8d8bef9SDimitry Andric if (!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) 62e8d8bef9SDimitry Andric return; 63e8d8bef9SDimitry Andric 64e8d8bef9SDimitry Andric const auto &STI = MF.getSubtarget<RISCVSubtarget>(); 6506c3fb27SDimitry Andric const llvm::RISCVRegisterInfo *TRI = STI.getRegisterInfo(); 6606c3fb27SDimitry Andric Register RAReg = TRI->getRARegister(); 67e8d8bef9SDimitry Andric 68e8d8bef9SDimitry Andric // Do not save RA to the SCS if it's not saved to the regular stack, 69e8d8bef9SDimitry Andric // i.e. RA is not at risk of being overwritten. 70e8d8bef9SDimitry Andric std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo(); 71bdd1243dSDimitry Andric if (llvm::none_of( 72bdd1243dSDimitry Andric CSI, [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; })) 73e8d8bef9SDimitry Andric return; 74e8d8bef9SDimitry Andric 75*0fca6ea1SDimitry Andric const RISCVInstrInfo *TII = STI.getInstrInfo(); 76*0fca6ea1SDimitry Andric if (!STI.hasForcedSWShadowStack() && STI.hasStdExtZicfiss()) { 77*0fca6ea1SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::SSPUSH)).addReg(RAReg); 78*0fca6ea1SDimitry Andric return; 79*0fca6ea1SDimitry Andric } 80*0fca6ea1SDimitry Andric 81e8d8bef9SDimitry Andric Register SCSPReg = RISCVABI::getSCSPReg(); 82e8d8bef9SDimitry Andric 83e8d8bef9SDimitry Andric bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); 84e8d8bef9SDimitry Andric int64_t SlotSize = STI.getXLen() / 8; 85e8d8bef9SDimitry Andric // Store return address to shadow call stack 8606c3fb27SDimitry Andric // addi gp, gp, [4|8] 8706c3fb27SDimitry Andric // s[w|d] ra, -[4|8](gp) 88e8d8bef9SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::ADDI)) 89e8d8bef9SDimitry Andric .addReg(SCSPReg, RegState::Define) 90e8d8bef9SDimitry Andric .addReg(SCSPReg) 91fe6060f1SDimitry Andric .addImm(SlotSize) 92fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 9306c3fb27SDimitry Andric BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::SD : RISCV::SW)) 9406c3fb27SDimitry Andric .addReg(RAReg) 9506c3fb27SDimitry Andric .addReg(SCSPReg) 9606c3fb27SDimitry Andric .addImm(-SlotSize) 9706c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 9806c3fb27SDimitry Andric 9906c3fb27SDimitry Andric // Emit a CFI instruction that causes SlotSize to be subtracted from the value 10006c3fb27SDimitry Andric // of the shadow stack pointer when unwinding past this frame. 10106c3fb27SDimitry Andric char DwarfSCSReg = TRI->getDwarfRegNum(SCSPReg, /*IsEH*/ true); 10206c3fb27SDimitry Andric assert(DwarfSCSReg < 32 && "SCS Register should be < 32 (X3)."); 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric char Offset = static_cast<char>(-SlotSize) & 0x7f; 10506c3fb27SDimitry Andric const char CFIInst[] = { 10606c3fb27SDimitry Andric dwarf::DW_CFA_val_expression, 10706c3fb27SDimitry Andric DwarfSCSReg, // register 10806c3fb27SDimitry Andric 2, // length 10906c3fb27SDimitry Andric static_cast<char>(unsigned(dwarf::DW_OP_breg0 + DwarfSCSReg)), 11006c3fb27SDimitry Andric Offset, // addend (sleb128) 11106c3fb27SDimitry Andric }; 11206c3fb27SDimitry Andric 11306c3fb27SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createEscape( 11406c3fb27SDimitry Andric nullptr, StringRef(CFIInst, sizeof(CFIInst)))); 11506c3fb27SDimitry Andric BuildMI(MBB, MI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 11606c3fb27SDimitry Andric .addCFIIndex(CFIIndex) 11706c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 118e8d8bef9SDimitry Andric } 119e8d8bef9SDimitry Andric 120e8d8bef9SDimitry Andric static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB, 121e8d8bef9SDimitry Andric MachineBasicBlock::iterator MI, 122e8d8bef9SDimitry Andric const DebugLoc &DL) { 123e8d8bef9SDimitry Andric if (!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) 124e8d8bef9SDimitry Andric return; 125e8d8bef9SDimitry Andric 126e8d8bef9SDimitry Andric const auto &STI = MF.getSubtarget<RISCVSubtarget>(); 127e8d8bef9SDimitry Andric Register RAReg = STI.getRegisterInfo()->getRARegister(); 128e8d8bef9SDimitry Andric 129e8d8bef9SDimitry Andric // See emitSCSPrologue() above. 130e8d8bef9SDimitry Andric std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo(); 131bdd1243dSDimitry Andric if (llvm::none_of( 132bdd1243dSDimitry Andric CSI, [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; })) 133e8d8bef9SDimitry Andric return; 134e8d8bef9SDimitry Andric 135*0fca6ea1SDimitry Andric const RISCVInstrInfo *TII = STI.getInstrInfo(); 136*0fca6ea1SDimitry Andric if (!STI.hasForcedSWShadowStack() && STI.hasStdExtZicfiss()) { 137*0fca6ea1SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::SSPOPCHK)).addReg(RAReg); 138*0fca6ea1SDimitry Andric return; 139*0fca6ea1SDimitry Andric } 140*0fca6ea1SDimitry Andric 141e8d8bef9SDimitry Andric Register SCSPReg = RISCVABI::getSCSPReg(); 142e8d8bef9SDimitry Andric 143e8d8bef9SDimitry Andric bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); 144e8d8bef9SDimitry Andric int64_t SlotSize = STI.getXLen() / 8; 145e8d8bef9SDimitry Andric // Load return address from shadow call stack 14606c3fb27SDimitry Andric // l[w|d] ra, -[4|8](gp) 14706c3fb27SDimitry Andric // addi gp, gp, -[4|8] 148e8d8bef9SDimitry Andric BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::LD : RISCV::LW)) 149e8d8bef9SDimitry Andric .addReg(RAReg, RegState::Define) 150e8d8bef9SDimitry Andric .addReg(SCSPReg) 151fe6060f1SDimitry Andric .addImm(-SlotSize) 152fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 153e8d8bef9SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::ADDI)) 154e8d8bef9SDimitry Andric .addReg(SCSPReg, RegState::Define) 155e8d8bef9SDimitry Andric .addReg(SCSPReg) 156fe6060f1SDimitry Andric .addImm(-SlotSize) 157fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 15806c3fb27SDimitry Andric // Restore the SCS pointer 15906c3fb27SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore( 16006c3fb27SDimitry Andric nullptr, STI.getRegisterInfo()->getDwarfRegNum(SCSPReg, /*IsEH*/ true))); 16106c3fb27SDimitry Andric BuildMI(MBB, MI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 16206c3fb27SDimitry Andric .addCFIIndex(CFIIndex) 16306c3fb27SDimitry Andric .setMIFlags(MachineInstr::FrameDestroy); 164e8d8bef9SDimitry Andric } 165e8d8bef9SDimitry Andric 1665ffd83dbSDimitry Andric // Get the ID of the libcall used for spilling and restoring callee saved 1675ffd83dbSDimitry Andric // registers. The ID is representative of the number of registers saved or 1685ffd83dbSDimitry Andric // restored by the libcall, except it is zero-indexed - ID 0 corresponds to a 1695ffd83dbSDimitry Andric // single register. 1705ffd83dbSDimitry Andric static int getLibCallID(const MachineFunction &MF, 1715ffd83dbSDimitry Andric const std::vector<CalleeSavedInfo> &CSI) { 1725ffd83dbSDimitry Andric const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 1735ffd83dbSDimitry Andric 1745ffd83dbSDimitry Andric if (CSI.empty() || !RVFI->useSaveRestoreLibCalls(MF)) 1755ffd83dbSDimitry Andric return -1; 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric Register MaxReg = RISCV::NoRegister; 1785ffd83dbSDimitry Andric for (auto &CS : CSI) 179*0fca6ea1SDimitry Andric // assignCalleeSavedSpillSlots assigns negative frame indexes to 1805ffd83dbSDimitry Andric // registers which can be saved by libcall. 1815ffd83dbSDimitry Andric if (CS.getFrameIdx() < 0) 182e8d8bef9SDimitry Andric MaxReg = std::max(MaxReg.id(), CS.getReg().id()); 1835ffd83dbSDimitry Andric 1845ffd83dbSDimitry Andric if (MaxReg == RISCV::NoRegister) 1855ffd83dbSDimitry Andric return -1; 1865ffd83dbSDimitry Andric 1875ffd83dbSDimitry Andric switch (MaxReg) { 1885ffd83dbSDimitry Andric default: 1895ffd83dbSDimitry Andric llvm_unreachable("Something has gone wrong!"); 1905ffd83dbSDimitry Andric case /*s11*/ RISCV::X27: return 12; 1915ffd83dbSDimitry Andric case /*s10*/ RISCV::X26: return 11; 1925ffd83dbSDimitry Andric case /*s9*/ RISCV::X25: return 10; 1935ffd83dbSDimitry Andric case /*s8*/ RISCV::X24: return 9; 1945ffd83dbSDimitry Andric case /*s7*/ RISCV::X23: return 8; 1955ffd83dbSDimitry Andric case /*s6*/ RISCV::X22: return 7; 1965ffd83dbSDimitry Andric case /*s5*/ RISCV::X21: return 6; 1975ffd83dbSDimitry Andric case /*s4*/ RISCV::X20: return 5; 1985ffd83dbSDimitry Andric case /*s3*/ RISCV::X19: return 4; 1995ffd83dbSDimitry Andric case /*s2*/ RISCV::X18: return 3; 2005ffd83dbSDimitry Andric case /*s1*/ RISCV::X9: return 2; 2015ffd83dbSDimitry Andric case /*s0*/ RISCV::X8: return 1; 2025ffd83dbSDimitry Andric case /*ra*/ RISCV::X1: return 0; 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric } 2055ffd83dbSDimitry Andric 2065ffd83dbSDimitry Andric // Get the name of the libcall used for spilling callee saved registers. 2075ffd83dbSDimitry Andric // If this function will not use save/restore libcalls, then return a nullptr. 2085ffd83dbSDimitry Andric static const char * 2095ffd83dbSDimitry Andric getSpillLibCallName(const MachineFunction &MF, 2105ffd83dbSDimitry Andric const std::vector<CalleeSavedInfo> &CSI) { 2115ffd83dbSDimitry Andric static const char *const SpillLibCalls[] = { 2125ffd83dbSDimitry Andric "__riscv_save_0", 2135ffd83dbSDimitry Andric "__riscv_save_1", 2145ffd83dbSDimitry Andric "__riscv_save_2", 2155ffd83dbSDimitry Andric "__riscv_save_3", 2165ffd83dbSDimitry Andric "__riscv_save_4", 2175ffd83dbSDimitry Andric "__riscv_save_5", 2185ffd83dbSDimitry Andric "__riscv_save_6", 2195ffd83dbSDimitry Andric "__riscv_save_7", 2205ffd83dbSDimitry Andric "__riscv_save_8", 2215ffd83dbSDimitry Andric "__riscv_save_9", 2225ffd83dbSDimitry Andric "__riscv_save_10", 2235ffd83dbSDimitry Andric "__riscv_save_11", 2245ffd83dbSDimitry Andric "__riscv_save_12" 2255ffd83dbSDimitry Andric }; 2265ffd83dbSDimitry Andric 2275ffd83dbSDimitry Andric int LibCallID = getLibCallID(MF, CSI); 2285ffd83dbSDimitry Andric if (LibCallID == -1) 2295ffd83dbSDimitry Andric return nullptr; 2305ffd83dbSDimitry Andric return SpillLibCalls[LibCallID]; 2315ffd83dbSDimitry Andric } 2325ffd83dbSDimitry Andric 2335ffd83dbSDimitry Andric // Get the name of the libcall used for restoring callee saved registers. 2345ffd83dbSDimitry Andric // If this function will not use save/restore libcalls, then return a nullptr. 2355ffd83dbSDimitry Andric static const char * 2365ffd83dbSDimitry Andric getRestoreLibCallName(const MachineFunction &MF, 2375ffd83dbSDimitry Andric const std::vector<CalleeSavedInfo> &CSI) { 2385ffd83dbSDimitry Andric static const char *const RestoreLibCalls[] = { 2395ffd83dbSDimitry Andric "__riscv_restore_0", 2405ffd83dbSDimitry Andric "__riscv_restore_1", 2415ffd83dbSDimitry Andric "__riscv_restore_2", 2425ffd83dbSDimitry Andric "__riscv_restore_3", 2435ffd83dbSDimitry Andric "__riscv_restore_4", 2445ffd83dbSDimitry Andric "__riscv_restore_5", 2455ffd83dbSDimitry Andric "__riscv_restore_6", 2465ffd83dbSDimitry Andric "__riscv_restore_7", 2475ffd83dbSDimitry Andric "__riscv_restore_8", 2485ffd83dbSDimitry Andric "__riscv_restore_9", 2495ffd83dbSDimitry Andric "__riscv_restore_10", 2505ffd83dbSDimitry Andric "__riscv_restore_11", 2515ffd83dbSDimitry Andric "__riscv_restore_12" 2525ffd83dbSDimitry Andric }; 2535ffd83dbSDimitry Andric 2545ffd83dbSDimitry Andric int LibCallID = getLibCallID(MF, CSI); 2555ffd83dbSDimitry Andric if (LibCallID == -1) 2565ffd83dbSDimitry Andric return nullptr; 2575ffd83dbSDimitry Andric return RestoreLibCalls[LibCallID]; 2585ffd83dbSDimitry Andric } 2595ffd83dbSDimitry Andric 2605f757f3fSDimitry Andric // Return encoded value and register count for PUSH/POP instruction, 2615f757f3fSDimitry Andric // representing registers to store/load. 2625f757f3fSDimitry Andric static std::pair<unsigned, unsigned> 2635f757f3fSDimitry Andric getPushPopEncodingAndNum(const Register MaxReg) { 26406c3fb27SDimitry Andric switch (MaxReg) { 26506c3fb27SDimitry Andric default: 26606c3fb27SDimitry Andric llvm_unreachable("Unexpected Reg for Push/Pop Inst"); 26706c3fb27SDimitry Andric case RISCV::X27: /*s11*/ 2685f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S11, 13); 26906c3fb27SDimitry Andric case RISCV::X25: /*s9*/ 2705f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S9, 11); 27106c3fb27SDimitry Andric case RISCV::X24: /*s8*/ 2725f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S8, 10); 27306c3fb27SDimitry Andric case RISCV::X23: /*s7*/ 2745f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S7, 9); 27506c3fb27SDimitry Andric case RISCV::X22: /*s6*/ 2765f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S6, 8); 27706c3fb27SDimitry Andric case RISCV::X21: /*s5*/ 2785f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S5, 7); 27906c3fb27SDimitry Andric case RISCV::X20: /*s4*/ 2805f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S4, 6); 28106c3fb27SDimitry Andric case RISCV::X19: /*s3*/ 2825f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S3, 5); 28306c3fb27SDimitry Andric case RISCV::X18: /*s2*/ 2845f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S2, 4); 28506c3fb27SDimitry Andric case RISCV::X9: /*s1*/ 2865f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0_S1, 3); 28706c3fb27SDimitry Andric case RISCV::X8: /*s0*/ 2885f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA_S0, 2); 28906c3fb27SDimitry Andric case RISCV::X1: /*ra*/ 2905f757f3fSDimitry Andric return std::make_pair(llvm::RISCVZC::RLISTENCODE::RA, 1); 29106c3fb27SDimitry Andric } 29206c3fb27SDimitry Andric } 29306c3fb27SDimitry Andric 29406c3fb27SDimitry Andric // Get the max reg of Push/Pop for restoring callee saved registers. 29506c3fb27SDimitry Andric static Register getMaxPushPopReg(const MachineFunction &MF, 2968a4dda33SDimitry Andric const std::vector<CalleeSavedInfo> &CSI) { 29706c3fb27SDimitry Andric Register MaxPushPopReg = RISCV::NoRegister; 29806c3fb27SDimitry Andric for (auto &CS : CSI) { 299*0fca6ea1SDimitry Andric if (llvm::find_if(FixedCSRFIMap, [&](auto P) { 300*0fca6ea1SDimitry Andric return P.first == CS.getReg(); 301*0fca6ea1SDimitry Andric }) != std::end(FixedCSRFIMap)) 3025f757f3fSDimitry Andric MaxPushPopReg = std::max(MaxPushPopReg.id(), CS.getReg().id()); 30306c3fb27SDimitry Andric } 304*0fca6ea1SDimitry Andric assert(MaxPushPopReg != RISCV::X26 && "x26 requires x27 to also be pushed"); 30506c3fb27SDimitry Andric return MaxPushPopReg; 30606c3fb27SDimitry Andric } 30706c3fb27SDimitry Andric 308349cc55cSDimitry Andric // Return true if the specified function should have a dedicated frame 309349cc55cSDimitry Andric // pointer register. This is true if frame pointer elimination is 310349cc55cSDimitry Andric // disabled, if it needs dynamic stack realignment, if the function has 311349cc55cSDimitry Andric // variable sized allocas, or if the frame address is taken. 3120b57cec5SDimitry Andric bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const { 3130b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 3160b57cec5SDimitry Andric return MF.getTarget().Options.DisableFramePointerElim(MF) || 317fe6060f1SDimitry Andric RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || 3180b57cec5SDimitry Andric MFI.isFrameAddressTaken(); 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 321480093f4SDimitry Andric bool RISCVFrameLowering::hasBP(const MachineFunction &MF) const { 322480093f4SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 323480093f4SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 324480093f4SDimitry Andric 3254824e7fdSDimitry Andric // If we do not reserve stack space for outgoing arguments in prologue, 3264824e7fdSDimitry Andric // we will adjust the stack pointer before call instruction. After the 3274824e7fdSDimitry Andric // adjustment, we can not use SP to access the stack objects for the 3284824e7fdSDimitry Andric // arguments. Instead, use BP to access these stack objects. 3294824e7fdSDimitry Andric return (MFI.hasVarSizedObjects() || 33004eeddc0SDimitry Andric (!hasReservedCallFrame(MF) && (!MFI.isMaxCallFrameSizeComputed() || 33104eeddc0SDimitry Andric MFI.getMaxCallFrameSize() != 0))) && 3324824e7fdSDimitry Andric TRI->hasStackRealignment(MF); 333480093f4SDimitry Andric } 334480093f4SDimitry Andric 3350b57cec5SDimitry Andric // Determines the size of the frame and maximum call frame size. 3360b57cec5SDimitry Andric void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { 3370b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 33881ad6265SDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 3410b57cec5SDimitry Andric uint64_t FrameSize = MFI.getStackSize(); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric // Get the alignment. 3445ffd83dbSDimitry Andric Align StackAlign = getStackAlign(); 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric // Make sure the frame is aligned. 3470b57cec5SDimitry Andric FrameSize = alignTo(FrameSize, StackAlign); 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // Update frame info. 3500b57cec5SDimitry Andric MFI.setStackSize(FrameSize); 35181ad6265SDimitry Andric 35281ad6265SDimitry Andric // When using SP or BP to access stack objects, we may require extra padding 35381ad6265SDimitry Andric // to ensure the bottom of the RVV stack is correctly aligned within the main 35481ad6265SDimitry Andric // stack. We calculate this as the amount required to align the scalar local 35581ad6265SDimitry Andric // variable section up to the RVV alignment. 35681ad6265SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 35781ad6265SDimitry Andric if (RVFI->getRVVStackSize() && (!hasFP(MF) || TRI->hasStackRealignment(MF))) { 35881ad6265SDimitry Andric int ScalarLocalVarSize = FrameSize - RVFI->getCalleeSavedStackSize() - 35981ad6265SDimitry Andric RVFI->getVarArgsSaveSize(); 36081ad6265SDimitry Andric if (auto RVVPadding = 36181ad6265SDimitry Andric offsetToAlignment(ScalarLocalVarSize, RVFI->getRVVStackAlign())) 36281ad6265SDimitry Andric RVFI->setRVVPadding(RVVPadding); 36381ad6265SDimitry Andric } 36481ad6265SDimitry Andric } 36581ad6265SDimitry Andric 36681ad6265SDimitry Andric // Returns the stack size including RVV padding (when required), rounded back 36781ad6265SDimitry Andric // up to the required stack alignment. 36881ad6265SDimitry Andric uint64_t RISCVFrameLowering::getStackSizeWithRVVPadding( 36981ad6265SDimitry Andric const MachineFunction &MF) const { 37081ad6265SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 37181ad6265SDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 37281ad6265SDimitry Andric return alignTo(MFI.getStackSize() + RVFI->getRVVPadding(), getStackAlign()); 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric // Returns the register used to hold the frame pointer. 3768bcb0991SDimitry Andric static Register getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; } 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric // Returns the register used to hold the stack pointer. 3798bcb0991SDimitry Andric static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; } 3800b57cec5SDimitry Andric 3815ffd83dbSDimitry Andric static SmallVector<CalleeSavedInfo, 8> 38206c3fb27SDimitry Andric getUnmanagedCSI(const MachineFunction &MF, 383fe6060f1SDimitry Andric const std::vector<CalleeSavedInfo> &CSI) { 384fe6060f1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 3855ffd83dbSDimitry Andric SmallVector<CalleeSavedInfo, 8> NonLibcallCSI; 3865ffd83dbSDimitry Andric 387fe6060f1SDimitry Andric for (auto &CS : CSI) { 388fe6060f1SDimitry Andric int FI = CS.getFrameIdx(); 389fe6060f1SDimitry Andric if (FI >= 0 && MFI.getStackID(FI) == TargetStackID::Default) 3905ffd83dbSDimitry Andric NonLibcallCSI.push_back(CS); 391fe6060f1SDimitry Andric } 3925ffd83dbSDimitry Andric 3935ffd83dbSDimitry Andric return NonLibcallCSI; 3945ffd83dbSDimitry Andric } 3955ffd83dbSDimitry Andric 396*0fca6ea1SDimitry Andric static SmallVector<CalleeSavedInfo, 8> 397*0fca6ea1SDimitry Andric getRVVCalleeSavedInfo(const MachineFunction &MF, 398*0fca6ea1SDimitry Andric const std::vector<CalleeSavedInfo> &CSI) { 399*0fca6ea1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 400*0fca6ea1SDimitry Andric SmallVector<CalleeSavedInfo, 8> RVVCSI; 401*0fca6ea1SDimitry Andric 402*0fca6ea1SDimitry Andric for (auto &CS : CSI) { 403*0fca6ea1SDimitry Andric int FI = CS.getFrameIdx(); 404*0fca6ea1SDimitry Andric if (FI >= 0 && MFI.getStackID(FI) == TargetStackID::ScalableVector) 405*0fca6ea1SDimitry Andric RVVCSI.push_back(CS); 406*0fca6ea1SDimitry Andric } 407*0fca6ea1SDimitry Andric 408*0fca6ea1SDimitry Andric return RVVCSI; 409*0fca6ea1SDimitry Andric } 410*0fca6ea1SDimitry Andric 411fe6060f1SDimitry Andric void RISCVFrameLowering::adjustStackForRVV(MachineFunction &MF, 412fe6060f1SDimitry Andric MachineBasicBlock &MBB, 413fe6060f1SDimitry Andric MachineBasicBlock::iterator MBBI, 414fe6060f1SDimitry Andric const DebugLoc &DL, int64_t Amount, 415fe6060f1SDimitry Andric MachineInstr::MIFlag Flag) const { 416fe6060f1SDimitry Andric assert(Amount != 0 && "Did not need to adjust stack pointer for RVV."); 417fe6060f1SDimitry Andric 418bdd1243dSDimitry Andric const Register SPReg = getSPReg(STI); 419bdd1243dSDimitry Andric 420bdd1243dSDimitry Andric // Optimize compile time offset case 421bdd1243dSDimitry Andric StackOffset Offset = StackOffset::getScalable(Amount); 422*0fca6ea1SDimitry Andric if (auto VLEN = STI.getRealVLen()) { 423bdd1243dSDimitry Andric // 1. Multiply the number of v-slots by the (constant) length of register 424*0fca6ea1SDimitry Andric const int64_t VLENB = *VLEN / 8; 425bdd1243dSDimitry Andric assert(Amount % 8 == 0 && 426bdd1243dSDimitry Andric "Reserve the stack by the multiple of one vector size."); 427bdd1243dSDimitry Andric const int64_t NumOfVReg = Amount / 8; 428bdd1243dSDimitry Andric const int64_t FixedOffset = NumOfVReg * VLENB; 429bdd1243dSDimitry Andric if (!isInt<32>(FixedOffset)) { 430bdd1243dSDimitry Andric report_fatal_error( 431bdd1243dSDimitry Andric "Frame size outside of the signed 32-bit range not supported"); 432fe6060f1SDimitry Andric } 433bdd1243dSDimitry Andric Offset = StackOffset::getFixed(FixedOffset); 434bdd1243dSDimitry Andric } 435bdd1243dSDimitry Andric 436bdd1243dSDimitry Andric const RISCVRegisterInfo &RI = *STI.getRegisterInfo(); 437bdd1243dSDimitry Andric // We must keep the stack pointer aligned through any intermediate 438bdd1243dSDimitry Andric // updates. 439bdd1243dSDimitry Andric RI.adjustReg(MBB, MBBI, DL, SPReg, SPReg, Offset, 440bdd1243dSDimitry Andric Flag, getStackAlign()); 441bdd1243dSDimitry Andric } 442bdd1243dSDimitry Andric 443*0fca6ea1SDimitry Andric static void appendScalableVectorExpression(const TargetRegisterInfo &TRI, 444*0fca6ea1SDimitry Andric SmallVectorImpl<char> &Expr, 445*0fca6ea1SDimitry Andric int FixedOffset, int ScalableOffset, 446*0fca6ea1SDimitry Andric llvm::raw_string_ostream &Comment) { 447*0fca6ea1SDimitry Andric unsigned DwarfVLenB = TRI.getDwarfRegNum(RISCV::VLENB, true); 448*0fca6ea1SDimitry Andric uint8_t Buffer[16]; 449*0fca6ea1SDimitry Andric if (FixedOffset) { 450*0fca6ea1SDimitry Andric Expr.push_back(dwarf::DW_OP_consts); 451*0fca6ea1SDimitry Andric Expr.append(Buffer, Buffer + encodeSLEB128(FixedOffset, Buffer)); 452*0fca6ea1SDimitry Andric Expr.push_back((uint8_t)dwarf::DW_OP_plus); 453*0fca6ea1SDimitry Andric Comment << (FixedOffset < 0 ? " - " : " + ") << std::abs(FixedOffset); 454*0fca6ea1SDimitry Andric } 455*0fca6ea1SDimitry Andric 456*0fca6ea1SDimitry Andric Expr.push_back((uint8_t)dwarf::DW_OP_consts); 457*0fca6ea1SDimitry Andric Expr.append(Buffer, Buffer + encodeSLEB128(ScalableOffset, Buffer)); 458*0fca6ea1SDimitry Andric 459*0fca6ea1SDimitry Andric Expr.push_back((uint8_t)dwarf::DW_OP_bregx); 460*0fca6ea1SDimitry Andric Expr.append(Buffer, Buffer + encodeULEB128(DwarfVLenB, Buffer)); 461*0fca6ea1SDimitry Andric Expr.push_back(0); 462*0fca6ea1SDimitry Andric 463*0fca6ea1SDimitry Andric Expr.push_back((uint8_t)dwarf::DW_OP_mul); 464*0fca6ea1SDimitry Andric Expr.push_back((uint8_t)dwarf::DW_OP_plus); 465*0fca6ea1SDimitry Andric 466*0fca6ea1SDimitry Andric Comment << (ScalableOffset < 0 ? " - " : " + ") << std::abs(ScalableOffset) 467*0fca6ea1SDimitry Andric << " * vlenb"; 468*0fca6ea1SDimitry Andric } 469*0fca6ea1SDimitry Andric 470bdd1243dSDimitry Andric static MCCFIInstruction createDefCFAExpression(const TargetRegisterInfo &TRI, 471bdd1243dSDimitry Andric Register Reg, 472bdd1243dSDimitry Andric uint64_t FixedOffset, 473bdd1243dSDimitry Andric uint64_t ScalableOffset) { 474bdd1243dSDimitry Andric assert(ScalableOffset != 0 && "Did not need to adjust CFA for RVV"); 475bdd1243dSDimitry Andric SmallString<64> Expr; 476bdd1243dSDimitry Andric std::string CommentBuffer; 477bdd1243dSDimitry Andric llvm::raw_string_ostream Comment(CommentBuffer); 478bdd1243dSDimitry Andric // Build up the expression (Reg + FixedOffset + ScalableOffset * VLENB). 479bdd1243dSDimitry Andric unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true); 480bdd1243dSDimitry Andric Expr.push_back((uint8_t)(dwarf::DW_OP_breg0 + DwarfReg)); 481bdd1243dSDimitry Andric Expr.push_back(0); 482bdd1243dSDimitry Andric if (Reg == RISCV::X2) 483bdd1243dSDimitry Andric Comment << "sp"; 484bdd1243dSDimitry Andric else 485bdd1243dSDimitry Andric Comment << printReg(Reg, &TRI); 486bdd1243dSDimitry Andric 487*0fca6ea1SDimitry Andric appendScalableVectorExpression(TRI, Expr, FixedOffset, ScalableOffset, 488*0fca6ea1SDimitry Andric Comment); 489bdd1243dSDimitry Andric 490bdd1243dSDimitry Andric SmallString<64> DefCfaExpr; 491*0fca6ea1SDimitry Andric uint8_t Buffer[16]; 492bdd1243dSDimitry Andric DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression); 493*0fca6ea1SDimitry Andric DefCfaExpr.append(Buffer, Buffer + encodeULEB128(Expr.size(), Buffer)); 494*0fca6ea1SDimitry Andric DefCfaExpr.append(Expr.str()); 495*0fca6ea1SDimitry Andric 496*0fca6ea1SDimitry Andric return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(), SMLoc(), 497*0fca6ea1SDimitry Andric Comment.str()); 498*0fca6ea1SDimitry Andric } 499*0fca6ea1SDimitry Andric 500*0fca6ea1SDimitry Andric static MCCFIInstruction createDefCFAOffset(const TargetRegisterInfo &TRI, 501*0fca6ea1SDimitry Andric Register Reg, uint64_t FixedOffset, 502*0fca6ea1SDimitry Andric uint64_t ScalableOffset) { 503*0fca6ea1SDimitry Andric assert(ScalableOffset != 0 && "Did not need to adjust CFA for RVV"); 504*0fca6ea1SDimitry Andric SmallString<64> Expr; 505*0fca6ea1SDimitry Andric std::string CommentBuffer; 506*0fca6ea1SDimitry Andric llvm::raw_string_ostream Comment(CommentBuffer); 507*0fca6ea1SDimitry Andric Comment << printReg(Reg, &TRI) << " @ cfa"; 508*0fca6ea1SDimitry Andric 509*0fca6ea1SDimitry Andric // Build up the expression (FixedOffset + ScalableOffset * VLENB). 510*0fca6ea1SDimitry Andric appendScalableVectorExpression(TRI, Expr, FixedOffset, ScalableOffset, 511*0fca6ea1SDimitry Andric Comment); 512*0fca6ea1SDimitry Andric 513*0fca6ea1SDimitry Andric SmallString<64> DefCfaExpr; 514*0fca6ea1SDimitry Andric uint8_t Buffer[16]; 515*0fca6ea1SDimitry Andric unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true); 516*0fca6ea1SDimitry Andric DefCfaExpr.push_back(dwarf::DW_CFA_expression); 517*0fca6ea1SDimitry Andric DefCfaExpr.append(Buffer, Buffer + encodeULEB128(DwarfReg, Buffer)); 518*0fca6ea1SDimitry Andric DefCfaExpr.append(Buffer, Buffer + encodeULEB128(Expr.size(), Buffer)); 519bdd1243dSDimitry Andric DefCfaExpr.append(Expr.str()); 520bdd1243dSDimitry Andric 52106c3fb27SDimitry Andric return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(), SMLoc(), 522bdd1243dSDimitry Andric Comment.str()); 523fe6060f1SDimitry Andric } 524fe6060f1SDimitry Andric 5250b57cec5SDimitry Andric void RISCVFrameLowering::emitPrologue(MachineFunction &MF, 5260b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 5270b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 5280b57cec5SDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 5290b57cec5SDimitry Andric const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 5300b57cec5SDimitry Andric const RISCVInstrInfo *TII = STI.getInstrInfo(); 5310b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 5320b57cec5SDimitry Andric 5338bcb0991SDimitry Andric Register FPReg = getFPReg(STI); 5348bcb0991SDimitry Andric Register SPReg = getSPReg(STI); 535480093f4SDimitry Andric Register BPReg = RISCVABI::getBPReg(); 5360b57cec5SDimitry Andric 537e8d8bef9SDimitry Andric // Debug location must be unknown since the first debug location is used 538e8d8bef9SDimitry Andric // to determine the end of the prologue. 539e8d8bef9SDimitry Andric DebugLoc DL; 540e8d8bef9SDimitry Andric 541e8d8bef9SDimitry Andric // All calls are tail calls in GHC calling conv, and functions have no 542e8d8bef9SDimitry Andric // prologue/epilogue. 543e8d8bef9SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC) 544e8d8bef9SDimitry Andric return; 545e8d8bef9SDimitry Andric 546e8d8bef9SDimitry Andric // Emit prologue for shadow call stack. 547e8d8bef9SDimitry Andric emitSCSPrologue(MF, MBB, MBBI, DL); 548e8d8bef9SDimitry Andric 54906c3fb27SDimitry Andric auto FirstFrameSetup = MBBI; 55006c3fb27SDimitry Andric 5515ffd83dbSDimitry Andric // Since spillCalleeSavedRegisters may have inserted a libcall, skip past 5525ffd83dbSDimitry Andric // any instructions marked as FrameSetup 5535ffd83dbSDimitry Andric while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup)) 5545ffd83dbSDimitry Andric ++MBBI; 5555ffd83dbSDimitry Andric 5560b57cec5SDimitry Andric // Determine the correct frame layout 5570b57cec5SDimitry Andric determineFrameLayout(MF); 5580b57cec5SDimitry Andric 5595ffd83dbSDimitry Andric // If libcalls are used to spill and restore callee-saved registers, the frame 5605ffd83dbSDimitry Andric // has two sections; the opaque section managed by the libcalls, and the 5615ffd83dbSDimitry Andric // section managed by MachineFrameInfo which can also hold callee saved 5625ffd83dbSDimitry Andric // registers in fixed stack slots, both of which have negative frame indices. 5635ffd83dbSDimitry Andric // This gets even more complicated when incoming arguments are passed via the 5645ffd83dbSDimitry Andric // stack, as these too have negative frame indices. An example is detailed 5655ffd83dbSDimitry Andric // below: 5665ffd83dbSDimitry Andric // 5675ffd83dbSDimitry Andric // | incoming arg | <- FI[-3] 5685ffd83dbSDimitry Andric // | libcallspill | 5695ffd83dbSDimitry Andric // | calleespill | <- FI[-2] 5705ffd83dbSDimitry Andric // | calleespill | <- FI[-1] 5715ffd83dbSDimitry Andric // | this_frame | <- FI[0] 5725ffd83dbSDimitry Andric // 5735ffd83dbSDimitry Andric // For negative frame indices, the offset from the frame pointer will differ 5745ffd83dbSDimitry Andric // depending on which of these groups the frame index applies to. 5755ffd83dbSDimitry Andric // The following calculates the correct offset knowing the number of callee 5765ffd83dbSDimitry Andric // saved registers spilt by the two methods. 5775ffd83dbSDimitry Andric if (int LibCallRegs = getLibCallID(MF, MFI.getCalleeSavedInfo()) + 1) { 5787a6dacacSDimitry Andric // Calculate the size of the frame managed by the libcall. The stack 5797a6dacacSDimitry Andric // alignment of these libcalls should be the same as how we set it in 5807a6dacacSDimitry Andric // getABIStackAlignment. 5817a6dacacSDimitry Andric unsigned LibCallFrameSize = 5827a6dacacSDimitry Andric alignTo((STI.getXLen() / 8) * LibCallRegs, getStackAlign()); 5835ffd83dbSDimitry Andric RVFI->setLibCallStackSize(LibCallFrameSize); 5845ffd83dbSDimitry Andric } 5855ffd83dbSDimitry Andric 5860b57cec5SDimitry Andric // FIXME (note copied from Lanai): This appears to be overallocating. Needs 5870b57cec5SDimitry Andric // investigation. Get the number of bytes to allocate from the FrameInfo. 588*0fca6ea1SDimitry Andric uint64_t RealStackSize = getStackSizeWithRVVPadding(MF); 589*0fca6ea1SDimitry Andric uint64_t StackSize = RealStackSize - RVFI->getReservedSpillsSize(); 590fe6060f1SDimitry Andric uint64_t RVVStackSize = RVFI->getRVVStackSize(); 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric // Early exit if there is no need to allocate on the stack 593fe6060f1SDimitry Andric if (RealStackSize == 0 && !MFI.adjustsStack() && RVVStackSize == 0) 5940b57cec5SDimitry Andric return; 5950b57cec5SDimitry Andric 596480093f4SDimitry Andric // If the stack pointer has been marked as reserved, then produce an error if 597480093f4SDimitry Andric // the frame requires stack allocation 598480093f4SDimitry Andric if (STI.isRegisterReservedByUser(SPReg)) 599480093f4SDimitry Andric MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ 600480093f4SDimitry Andric MF.getFunction(), "Stack pointer required, but has been reserved."}); 601480093f4SDimitry Andric 6028bcb0991SDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 6038bcb0991SDimitry Andric // Split the SP adjustment to reduce the offsets of callee saved spill. 6045ffd83dbSDimitry Andric if (FirstSPAdjustAmount) { 6058bcb0991SDimitry Andric StackSize = FirstSPAdjustAmount; 6065ffd83dbSDimitry Andric RealStackSize = FirstSPAdjustAmount; 6075ffd83dbSDimitry Andric } 6088bcb0991SDimitry Andric 6095f757f3fSDimitry Andric if (RVFI->isPushable(MF) && FirstFrameSetup != MBB.end() && 6105f757f3fSDimitry Andric FirstFrameSetup->getOpcode() == RISCV::CM_PUSH) { 61106c3fb27SDimitry Andric // Use available stack adjustment in push instruction to allocate additional 612*0fca6ea1SDimitry Andric // stack space. Align the stack size down to a multiple of 16. This is 613*0fca6ea1SDimitry Andric // needed for RVE. 614*0fca6ea1SDimitry Andric // FIXME: Can we increase the stack size to a multiple of 16 instead? 615*0fca6ea1SDimitry Andric uint64_t Spimm = std::min(alignDown(StackSize, 16), (uint64_t)48); 6165f757f3fSDimitry Andric FirstFrameSetup->getOperand(1).setImm(Spimm); 6175f757f3fSDimitry Andric StackSize -= Spimm; 61806c3fb27SDimitry Andric } 61906c3fb27SDimitry Andric 62006c3fb27SDimitry Andric if (StackSize != 0) { 6210b57cec5SDimitry Andric // Allocate space on the stack if necessary. 62206c3fb27SDimitry Andric RI->adjustReg(MBB, MBBI, DL, SPReg, SPReg, 62306c3fb27SDimitry Andric StackOffset::getFixed(-StackSize), MachineInstr::FrameSetup, 62406c3fb27SDimitry Andric getStackAlign()); 62506c3fb27SDimitry Andric } 6260b57cec5SDimitry Andric 6275ffd83dbSDimitry Andric // Emit ".cfi_def_cfa_offset RealStackSize" 6280b57cec5SDimitry Andric unsigned CFIIndex = MF.addFrameInst( 6295ffd83dbSDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize)); 6300b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 631fe6060f1SDimitry Andric .addCFIIndex(CFIIndex) 632fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 6330b57cec5SDimitry Andric 6345ffd83dbSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 6355ffd83dbSDimitry Andric 6360b57cec5SDimitry Andric // The frame pointer is callee-saved, and code has been generated for us to 6370b57cec5SDimitry Andric // save it to the stack. We need to skip over the storing of callee-saved 6380b57cec5SDimitry Andric // registers as the frame pointer must be modified after it has been saved 6390b57cec5SDimitry Andric // to the stack, not before. 6400b57cec5SDimitry Andric // FIXME: assumes exactly one instruction is used to save each callee-saved 6410b57cec5SDimitry Andric // register. 64206c3fb27SDimitry Andric std::advance(MBBI, getUnmanagedCSI(MF, CSI).size()); 6430b57cec5SDimitry Andric 6440b57cec5SDimitry Andric // Iterate over list of callee-saved registers and emit .cfi_offset 6450b57cec5SDimitry Andric // directives. 6460b57cec5SDimitry Andric for (const auto &Entry : CSI) { 6475ffd83dbSDimitry Andric int FrameIdx = Entry.getFrameIdx(); 648*0fca6ea1SDimitry Andric if (FrameIdx >= 0 && 649*0fca6ea1SDimitry Andric MFI.getStackID(FrameIdx) == TargetStackID::ScalableVector) 650*0fca6ea1SDimitry Andric continue; 651*0fca6ea1SDimitry Andric 652*0fca6ea1SDimitry Andric int64_t Offset = MFI.getObjectOffset(FrameIdx); 6538bcb0991SDimitry Andric Register Reg = Entry.getReg(); 6540b57cec5SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 6550b57cec5SDimitry Andric nullptr, RI->getDwarfRegNum(Reg, true), Offset)); 6560b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 657fe6060f1SDimitry Andric .addCFIIndex(CFIIndex) 658fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 6590b57cec5SDimitry Andric } 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric // Generate new FP. 6620b57cec5SDimitry Andric if (hasFP(MF)) { 663480093f4SDimitry Andric if (STI.isRegisterReservedByUser(FPReg)) 664480093f4SDimitry Andric MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ 665480093f4SDimitry Andric MF.getFunction(), "Frame pointer required, but has been reserved."}); 666bdd1243dSDimitry Andric // The frame pointer does need to be reserved from register allocation. 667bdd1243dSDimitry Andric assert(MF.getRegInfo().isReserved(FPReg) && "FP not reserved"); 668480093f4SDimitry Andric 669bdd1243dSDimitry Andric RI->adjustReg(MBB, MBBI, DL, FPReg, SPReg, 670bdd1243dSDimitry Andric StackOffset::getFixed(RealStackSize - RVFI->getVarArgsSaveSize()), 671bdd1243dSDimitry Andric MachineInstr::FrameSetup, getStackAlign()); 6720b57cec5SDimitry Andric 6735ffd83dbSDimitry Andric // Emit ".cfi_def_cfa $fp, RVFI->getVarArgsSaveSize()" 6745ffd83dbSDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( 6755ffd83dbSDimitry Andric nullptr, RI->getDwarfRegNum(FPReg, true), RVFI->getVarArgsSaveSize())); 6760b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 677fe6060f1SDimitry Andric .addCFIIndex(CFIIndex) 678fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 6798bcb0991SDimitry Andric } 6800b57cec5SDimitry Andric 6818bcb0991SDimitry Andric // Emit the second SP adjustment after saving callee saved registers. 6828bcb0991SDimitry Andric if (FirstSPAdjustAmount) { 68381ad6265SDimitry Andric uint64_t SecondSPAdjustAmount = 68481ad6265SDimitry Andric getStackSizeWithRVVPadding(MF) - FirstSPAdjustAmount; 6858bcb0991SDimitry Andric assert(SecondSPAdjustAmount > 0 && 6868bcb0991SDimitry Andric "SecondSPAdjustAmount should be greater than zero"); 687bdd1243dSDimitry Andric RI->adjustReg(MBB, MBBI, DL, SPReg, SPReg, 688bdd1243dSDimitry Andric StackOffset::getFixed(-SecondSPAdjustAmount), 689bdd1243dSDimitry Andric MachineInstr::FrameSetup, getStackAlign()); 690480093f4SDimitry Andric 691480093f4SDimitry Andric // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", 692480093f4SDimitry Andric // don't emit an sp-based .cfi_def_cfa_offset 693480093f4SDimitry Andric if (!hasFP(MF)) { 6948bcb0991SDimitry Andric // Emit ".cfi_def_cfa_offset StackSize" 69581ad6265SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset( 69681ad6265SDimitry Andric nullptr, getStackSizeWithRVVPadding(MF))); 6978bcb0991SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 698fe6060f1SDimitry Andric .addCFIIndex(CFIIndex) 699fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7008bcb0991SDimitry Andric } 701480093f4SDimitry Andric } 7028bcb0991SDimitry Andric 703bdd1243dSDimitry Andric if (RVVStackSize) { 704fe6060f1SDimitry Andric adjustStackForRVV(MF, MBB, MBBI, DL, -RVVStackSize, 705fe6060f1SDimitry Andric MachineInstr::FrameSetup); 706bdd1243dSDimitry Andric if (!hasFP(MF)) { 707bdd1243dSDimitry Andric // Emit .cfi_def_cfa_expression "sp + StackSize + RVVStackSize * vlenb". 708bdd1243dSDimitry Andric unsigned CFIIndex = MF.addFrameInst(createDefCFAExpression( 709bdd1243dSDimitry Andric *RI, SPReg, getStackSizeWithRVVPadding(MF), RVVStackSize / 8)); 710bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 711bdd1243dSDimitry Andric .addCFIIndex(CFIIndex) 712bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 713bdd1243dSDimitry Andric } 714*0fca6ea1SDimitry Andric 715*0fca6ea1SDimitry Andric std::advance(MBBI, getRVVCalleeSavedInfo(MF, CSI).size()); 716*0fca6ea1SDimitry Andric emitCalleeSavedRVVPrologCFI(MBB, MBBI, hasFP(MF)); 717bdd1243dSDimitry Andric } 718fe6060f1SDimitry Andric 7198bcb0991SDimitry Andric if (hasFP(MF)) { 7200b57cec5SDimitry Andric // Realign Stack 7210b57cec5SDimitry Andric const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 722fe6060f1SDimitry Andric if (RI->hasStackRealignment(MF)) { 7235ffd83dbSDimitry Andric Align MaxAlignment = MFI.getMaxAlign(); 7240b57cec5SDimitry Andric 7250b57cec5SDimitry Andric const RISCVInstrInfo *TII = STI.getInstrInfo(); 7265ffd83dbSDimitry Andric if (isInt<12>(-(int)MaxAlignment.value())) { 7270b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) 7280b57cec5SDimitry Andric .addReg(SPReg) 729fe6060f1SDimitry Andric .addImm(-(int)MaxAlignment.value()) 730fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7310b57cec5SDimitry Andric } else { 7325ffd83dbSDimitry Andric unsigned ShiftAmount = Log2(MaxAlignment); 7338bcb0991SDimitry Andric Register VR = 7340b57cec5SDimitry Andric MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); 7350b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR) 7360b57cec5SDimitry Andric .addReg(SPReg) 737fe6060f1SDimitry Andric .addImm(ShiftAmount) 738fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7390b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(RISCV::SLLI), SPReg) 7400b57cec5SDimitry Andric .addReg(VR) 741fe6060f1SDimitry Andric .addImm(ShiftAmount) 742fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 7430b57cec5SDimitry Andric } 744480093f4SDimitry Andric // FP will be used to restore the frame in the epilogue, so we need 745480093f4SDimitry Andric // another base register BP to record SP after re-alignment. SP will 746480093f4SDimitry Andric // track the current stack after allocating variable sized objects. 747480093f4SDimitry Andric if (hasBP(MF)) { 748480093f4SDimitry Andric // move BP, SP 749480093f4SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), BPReg) 750480093f4SDimitry Andric .addReg(SPReg) 751fe6060f1SDimitry Andric .addImm(0) 752fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 753480093f4SDimitry Andric } 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, 7590b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 7600b57cec5SDimitry Andric const RISCVRegisterInfo *RI = STI.getRegisterInfo(); 7610b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 7620b57cec5SDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 7638bcb0991SDimitry Andric Register FPReg = getFPReg(STI); 7648bcb0991SDimitry Andric Register SPReg = getSPReg(STI); 7650b57cec5SDimitry Andric 766e8d8bef9SDimitry Andric // All calls are tail calls in GHC calling conv, and functions have no 767e8d8bef9SDimitry Andric // prologue/epilogue. 768e8d8bef9SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC) 769e8d8bef9SDimitry Andric return; 770e8d8bef9SDimitry Andric 771480093f4SDimitry Andric // Get the insert location for the epilogue. If there were no terminators in 772480093f4SDimitry Andric // the block, get the last instruction. 773480093f4SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.end(); 774480093f4SDimitry Andric DebugLoc DL; 775480093f4SDimitry Andric if (!MBB.empty()) { 776480093f4SDimitry Andric MBBI = MBB.getLastNonDebugInstr(); 77781ad6265SDimitry Andric if (MBBI != MBB.end()) 778480093f4SDimitry Andric DL = MBBI->getDebugLoc(); 779480093f4SDimitry Andric 78081ad6265SDimitry Andric MBBI = MBB.getFirstTerminator(); 7815ffd83dbSDimitry Andric 7825ffd83dbSDimitry Andric // If callee-saved registers are saved via libcall, place stack adjustment 7835ffd83dbSDimitry Andric // before this call. 7845ffd83dbSDimitry Andric while (MBBI != MBB.begin() && 7855ffd83dbSDimitry Andric std::prev(MBBI)->getFlag(MachineInstr::FrameDestroy)) 7865ffd83dbSDimitry Andric --MBBI; 787480093f4SDimitry Andric } 788480093f4SDimitry Andric 78906c3fb27SDimitry Andric const auto &CSI = getUnmanagedCSI(MF, MFI.getCalleeSavedInfo()); 7905ffd83dbSDimitry Andric 791*0fca6ea1SDimitry Andric // Skip to before the restores of scalar callee-saved registers 7920b57cec5SDimitry Andric // FIXME: assumes exactly one instruction is used to restore each 7930b57cec5SDimitry Andric // callee-saved register. 7945ffd83dbSDimitry Andric auto LastFrameDestroy = MBBI; 7955ffd83dbSDimitry Andric if (!CSI.empty()) 7965ffd83dbSDimitry Andric LastFrameDestroy = std::prev(MBBI, CSI.size()); 7970b57cec5SDimitry Andric 798*0fca6ea1SDimitry Andric uint64_t RealStackSize = getStackSizeWithRVVPadding(MF); 799*0fca6ea1SDimitry Andric uint64_t StackSize = RealStackSize - RVFI->getReservedSpillsSize(); 8005ffd83dbSDimitry Andric uint64_t FPOffset = RealStackSize - RVFI->getVarArgsSaveSize(); 801fe6060f1SDimitry Andric uint64_t RVVStackSize = RVFI->getRVVStackSize(); 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric // Restore the stack pointer using the value of the frame pointer. Only 8040b57cec5SDimitry Andric // necessary if the stack pointer was modified, meaning the stack size is 8050b57cec5SDimitry Andric // unknown. 80681ad6265SDimitry Andric // 80781ad6265SDimitry Andric // In order to make sure the stack point is right through the EH region, 80881ad6265SDimitry Andric // we also need to restore stack pointer from the frame pointer if we 80981ad6265SDimitry Andric // don't preserve stack space within prologue/epilogue for outgoing variables, 81081ad6265SDimitry Andric // normally it's just checking the variable sized object is present or not 81181ad6265SDimitry Andric // is enough, but we also don't preserve that at prologue/epilogue when 81281ad6265SDimitry Andric // have vector objects in stack. 81381ad6265SDimitry Andric if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || 81481ad6265SDimitry Andric !hasReservedCallFrame(MF)) { 8150b57cec5SDimitry Andric assert(hasFP(MF) && "frame pointer should not have been eliminated"); 816bdd1243dSDimitry Andric RI->adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, 817bdd1243dSDimitry Andric StackOffset::getFixed(-FPOffset), 818bdd1243dSDimitry Andric MachineInstr::FrameDestroy, getStackAlign()); 819fe6060f1SDimitry Andric } else { 820fe6060f1SDimitry Andric if (RVVStackSize) 821fe6060f1SDimitry Andric adjustStackForRVV(MF, MBB, LastFrameDestroy, DL, RVVStackSize, 822fe6060f1SDimitry Andric MachineInstr::FrameDestroy); 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8258bcb0991SDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 8268bcb0991SDimitry Andric if (FirstSPAdjustAmount) { 82781ad6265SDimitry Andric uint64_t SecondSPAdjustAmount = 82881ad6265SDimitry Andric getStackSizeWithRVVPadding(MF) - FirstSPAdjustAmount; 8298bcb0991SDimitry Andric assert(SecondSPAdjustAmount > 0 && 8308bcb0991SDimitry Andric "SecondSPAdjustAmount should be greater than zero"); 8318bcb0991SDimitry Andric 832bdd1243dSDimitry Andric RI->adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, 833bdd1243dSDimitry Andric StackOffset::getFixed(SecondSPAdjustAmount), 834bdd1243dSDimitry Andric MachineInstr::FrameDestroy, getStackAlign()); 8358bcb0991SDimitry Andric } 8368bcb0991SDimitry Andric 8378bcb0991SDimitry Andric if (FirstSPAdjustAmount) 8388bcb0991SDimitry Andric StackSize = FirstSPAdjustAmount; 8398bcb0991SDimitry Andric 8408a4dda33SDimitry Andric if (RVFI->isPushable(MF) && MBBI != MBB.end() && 8418a4dda33SDimitry Andric MBBI->getOpcode() == RISCV::CM_POP) { 84206c3fb27SDimitry Andric // Use available stack adjustment in pop instruction to deallocate stack 843*0fca6ea1SDimitry Andric // space. Align the stack size down to a multiple of 16. This is needed for 844*0fca6ea1SDimitry Andric // RVE. 845*0fca6ea1SDimitry Andric // FIXME: Can we increase the stack size to a multiple of 16 instead? 846*0fca6ea1SDimitry Andric uint64_t Spimm = std::min(alignDown(StackSize, 16), (uint64_t)48); 8475f757f3fSDimitry Andric MBBI->getOperand(1).setImm(Spimm); 8485f757f3fSDimitry Andric StackSize -= Spimm; 84906c3fb27SDimitry Andric } 85006c3fb27SDimitry Andric 8510b57cec5SDimitry Andric // Deallocate stack 85206c3fb27SDimitry Andric if (StackSize != 0) { 853bdd1243dSDimitry Andric RI->adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackOffset::getFixed(StackSize), 854bdd1243dSDimitry Andric MachineInstr::FrameDestroy, getStackAlign()); 85506c3fb27SDimitry Andric } 856e8d8bef9SDimitry Andric 857e8d8bef9SDimitry Andric // Emit epilogue for shadow call stack. 858e8d8bef9SDimitry Andric emitSCSEpilogue(MF, MBB, MBBI, DL); 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric 861e8d8bef9SDimitry Andric StackOffset 862e8d8bef9SDimitry Andric RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, 8635ffd83dbSDimitry Andric Register &FrameReg) const { 8640b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 8650b57cec5SDimitry Andric const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 8660b57cec5SDimitry Andric const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric // Callee-saved registers should be referenced relative to the stack 8690b57cec5SDimitry Andric // pointer (positive offset), otherwise use the frame pointer (negative 8700b57cec5SDimitry Andric // offset). 87106c3fb27SDimitry Andric const auto &CSI = getUnmanagedCSI(MF, MFI.getCalleeSavedInfo()); 8720b57cec5SDimitry Andric int MinCSFI = 0; 8730b57cec5SDimitry Andric int MaxCSFI = -1; 874fe6060f1SDimitry Andric StackOffset Offset; 875fe6060f1SDimitry Andric auto StackID = MFI.getStackID(FI); 8760b57cec5SDimitry Andric 877fe6060f1SDimitry Andric assert((StackID == TargetStackID::Default || 878fe6060f1SDimitry Andric StackID == TargetStackID::ScalableVector) && 879fe6060f1SDimitry Andric "Unexpected stack ID for the frame object."); 880fe6060f1SDimitry Andric if (StackID == TargetStackID::Default) { 881*0fca6ea1SDimitry Andric assert(getOffsetOfLocalArea() == 0 && "LocalAreaOffset is not 0!"); 882*0fca6ea1SDimitry Andric Offset = StackOffset::getFixed(MFI.getObjectOffset(FI) + 883fe6060f1SDimitry Andric MFI.getOffsetAdjustment()); 884fe6060f1SDimitry Andric } else if (StackID == TargetStackID::ScalableVector) { 885fe6060f1SDimitry Andric Offset = StackOffset::getScalable(MFI.getObjectOffset(FI)); 886fe6060f1SDimitry Andric } 8870b57cec5SDimitry Andric 8888bcb0991SDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 8898bcb0991SDimitry Andric 8900b57cec5SDimitry Andric if (CSI.size()) { 8910b57cec5SDimitry Andric MinCSFI = CSI[0].getFrameIdx(); 8920b57cec5SDimitry Andric MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 8930b57cec5SDimitry Andric } 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric if (FI >= MinCSFI && FI <= MaxCSFI) { 8960b57cec5SDimitry Andric FrameReg = RISCV::X2; 8978bcb0991SDimitry Andric 8988bcb0991SDimitry Andric if (FirstSPAdjustAmount) 899fe6060f1SDimitry Andric Offset += StackOffset::getFixed(FirstSPAdjustAmount); 9008bcb0991SDimitry Andric else 90181ad6265SDimitry Andric Offset += StackOffset::getFixed(getStackSizeWithRVVPadding(MF)); 90281ad6265SDimitry Andric return Offset; 90381ad6265SDimitry Andric } 90481ad6265SDimitry Andric 90581ad6265SDimitry Andric if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { 9060b57cec5SDimitry Andric // If the stack was realigned, the frame pointer is set in order to allow 907480093f4SDimitry Andric // SP to be restored, so we need another base register to record the stack 908480093f4SDimitry Andric // after realignment. 909fe6060f1SDimitry Andric // |--------------------------| -- <-- FP 9103a9a9c0cSDimitry Andric // | callee-allocated save | | <----| 9113a9a9c0cSDimitry Andric // | area for register varargs| | | 9123a9a9c0cSDimitry Andric // |--------------------------| | | 9133a9a9c0cSDimitry Andric // | callee-saved registers | | | 914fe6060f1SDimitry Andric // |--------------------------| -- | 915fe6060f1SDimitry Andric // | realignment (the size of | | | 916fe6060f1SDimitry Andric // | this area is not counted | | | 917fe6060f1SDimitry Andric // | in MFI.getStackSize()) | | | 918fe6060f1SDimitry Andric // |--------------------------| -- |-- MFI.getStackSize() 91981ad6265SDimitry Andric // | RVV alignment padding | | | 92081ad6265SDimitry Andric // | (not counted in | | | 92181ad6265SDimitry Andric // | MFI.getStackSize() but | | | 92281ad6265SDimitry Andric // | counted in | | | 92381ad6265SDimitry Andric // | RVFI.getRVVStackSize()) | | | 92481ad6265SDimitry Andric // |--------------------------| -- | 925fe6060f1SDimitry Andric // | RVV objects | | | 926fe6060f1SDimitry Andric // | (not counted in | | | 927349cc55cSDimitry Andric // | MFI.getStackSize()) | | | 928fe6060f1SDimitry Andric // |--------------------------| -- | 92981ad6265SDimitry Andric // | padding before RVV | | | 930fe6060f1SDimitry Andric // | (not counted in | | | 93181ad6265SDimitry Andric // | MFI.getStackSize() or in | | | 93281ad6265SDimitry Andric // | RVFI.getRVVStackSize()) | | | 933fe6060f1SDimitry Andric // |--------------------------| -- | 934fe6060f1SDimitry Andric // | scalar local variables | | <----' 93581ad6265SDimitry Andric // |--------------------------| -- <-- BP (if var sized objects present) 936fe6060f1SDimitry Andric // | VarSize objects | | 937fe6060f1SDimitry Andric // |--------------------------| -- <-- SP 93881ad6265SDimitry Andric if (hasBP(MF)) { 93981ad6265SDimitry Andric FrameReg = RISCVABI::getBPReg(); 940fe6060f1SDimitry Andric } else { 94181ad6265SDimitry Andric // VarSize objects must be empty in this case! 94281ad6265SDimitry Andric assert(!MFI.hasVarSizedObjects()); 9430b57cec5SDimitry Andric FrameReg = RISCV::X2; 944fe6060f1SDimitry Andric } 9450b57cec5SDimitry Andric } else { 9460b57cec5SDimitry Andric FrameReg = RI->getFrameRegister(MF); 94781ad6265SDimitry Andric } 94881ad6265SDimitry Andric 94981ad6265SDimitry Andric if (FrameReg == getFPReg(STI)) { 950fe6060f1SDimitry Andric Offset += StackOffset::getFixed(RVFI->getVarArgsSaveSize()); 951fe6060f1SDimitry Andric // When using FP to access scalable vector objects, we need to minus 952fe6060f1SDimitry Andric // the frame size. 953fe6060f1SDimitry Andric // 954fe6060f1SDimitry Andric // |--------------------------| -- <-- FP 9553a9a9c0cSDimitry Andric // | callee-allocated save | | 9563a9a9c0cSDimitry Andric // | area for register varargs| | 9573a9a9c0cSDimitry Andric // |--------------------------| | 958fe6060f1SDimitry Andric // | callee-saved registers | | 959fe6060f1SDimitry Andric // |--------------------------| | MFI.getStackSize() 960fe6060f1SDimitry Andric // | scalar local variables | | 961fe6060f1SDimitry Andric // |--------------------------| -- (Offset of RVV objects is from here.) 962fe6060f1SDimitry Andric // | RVV objects | 963fe6060f1SDimitry Andric // |--------------------------| 964fe6060f1SDimitry Andric // | VarSize objects | 965fe6060f1SDimitry Andric // |--------------------------| <-- SP 96681ad6265SDimitry Andric if (MFI.getStackID(FI) == TargetStackID::ScalableVector) { 96781ad6265SDimitry Andric assert(!RI->hasStackRealignment(MF) && 96881ad6265SDimitry Andric "Can't index across variable sized realign"); 96981ad6265SDimitry Andric // We don't expect any extra RVV alignment padding, as the stack size 97081ad6265SDimitry Andric // and RVV object sections should be correct aligned in their own 97181ad6265SDimitry Andric // right. 97281ad6265SDimitry Andric assert(MFI.getStackSize() == getStackSizeWithRVVPadding(MF) && 97381ad6265SDimitry Andric "Inconsistent stack layout"); 974fe6060f1SDimitry Andric Offset -= StackOffset::getFixed(MFI.getStackSize()); 97581ad6265SDimitry Andric } 97681ad6265SDimitry Andric return Offset; 97781ad6265SDimitry Andric } 97881ad6265SDimitry Andric 97981ad6265SDimitry Andric // This case handles indexing off both SP and BP. 98081ad6265SDimitry Andric // If indexing off SP, there must not be any var sized objects 98181ad6265SDimitry Andric assert(FrameReg == RISCVABI::getBPReg() || !MFI.hasVarSizedObjects()); 98281ad6265SDimitry Andric 983fe6060f1SDimitry Andric // When using SP to access frame objects, we need to add RVV stack size. 984fe6060f1SDimitry Andric // 985fe6060f1SDimitry Andric // |--------------------------| -- <-- FP 9863a9a9c0cSDimitry Andric // | callee-allocated save | | <----| 9873a9a9c0cSDimitry Andric // | area for register varargs| | | 9883a9a9c0cSDimitry Andric // |--------------------------| | | 9893a9a9c0cSDimitry Andric // | callee-saved registers | | | 990fe6060f1SDimitry Andric // |--------------------------| -- | 99181ad6265SDimitry Andric // | RVV alignment padding | | | 992fe6060f1SDimitry Andric // | (not counted in | | | 99381ad6265SDimitry Andric // | MFI.getStackSize() but | | | 99481ad6265SDimitry Andric // | counted in | | | 99581ad6265SDimitry Andric // | RVFI.getRVVStackSize()) | | | 996fe6060f1SDimitry Andric // |--------------------------| -- | 997fe6060f1SDimitry Andric // | RVV objects | | |-- MFI.getStackSize() 998fe6060f1SDimitry Andric // | (not counted in | | | 999349cc55cSDimitry Andric // | MFI.getStackSize()) | | | 1000fe6060f1SDimitry Andric // |--------------------------| -- | 100181ad6265SDimitry Andric // | padding before RVV | | | 1002fe6060f1SDimitry Andric // | (not counted in | | | 1003349cc55cSDimitry Andric // | MFI.getStackSize()) | | | 1004fe6060f1SDimitry Andric // |--------------------------| -- | 1005fe6060f1SDimitry Andric // | scalar local variables | | <----' 100681ad6265SDimitry Andric // |--------------------------| -- <-- BP (if var sized objects present) 100781ad6265SDimitry Andric // | VarSize objects | | 1008fe6060f1SDimitry Andric // |--------------------------| -- <-- SP 1009fe6060f1SDimitry Andric // 1010fe6060f1SDimitry Andric // The total amount of padding surrounding RVV objects is described by 1011fe6060f1SDimitry Andric // RVV->getRVVPadding() and it can be zero. It allows us to align the RVV 101281ad6265SDimitry Andric // objects to the required alignment. 1013fe6060f1SDimitry Andric if (MFI.getStackID(FI) == TargetStackID::Default) { 1014fe6060f1SDimitry Andric if (MFI.isFixedObjectIndex(FI)) { 101581ad6265SDimitry Andric assert(!RI->hasStackRealignment(MF) && 101681ad6265SDimitry Andric "Can't index across variable sized realign"); 1017*0fca6ea1SDimitry Andric Offset += StackOffset::get(getStackSizeWithRVVPadding(MF), 1018349cc55cSDimitry Andric RVFI->getRVVStackSize()); 1019fe6060f1SDimitry Andric } else { 1020fe6060f1SDimitry Andric Offset += StackOffset::getFixed(MFI.getStackSize()); 1021fe6060f1SDimitry Andric } 1022fe6060f1SDimitry Andric } else if (MFI.getStackID(FI) == TargetStackID::ScalableVector) { 102381ad6265SDimitry Andric // Ensure the base of the RVV stack is correctly aligned: add on the 102481ad6265SDimitry Andric // alignment padding. 102506c3fb27SDimitry Andric int ScalarLocalVarSize = MFI.getStackSize() - 102606c3fb27SDimitry Andric RVFI->getCalleeSavedStackSize() - 102706c3fb27SDimitry Andric RVFI->getRVPushStackSize() - 102881ad6265SDimitry Andric RVFI->getVarArgsSaveSize() + RVFI->getRVVPadding(); 102981ad6265SDimitry Andric Offset += StackOffset::get(ScalarLocalVarSize, RVFI->getRVVStackSize()); 10305ffd83dbSDimitry Andric } 1031fe6060f1SDimitry Andric return Offset; 10320b57cec5SDimitry Andric } 10330b57cec5SDimitry Andric 10340b57cec5SDimitry Andric void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, 10350b57cec5SDimitry Andric BitVector &SavedRegs, 10360b57cec5SDimitry Andric RegScavenger *RS) const { 10370b57cec5SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 10380b57cec5SDimitry Andric // Unconditionally spill RA and FP only if the function uses a frame 10390b57cec5SDimitry Andric // pointer. 10400b57cec5SDimitry Andric if (hasFP(MF)) { 10410b57cec5SDimitry Andric SavedRegs.set(RISCV::X1); 10420b57cec5SDimitry Andric SavedRegs.set(RISCV::X8); 10430b57cec5SDimitry Andric } 1044480093f4SDimitry Andric // Mark BP as used if function has dedicated base pointer. 1045480093f4SDimitry Andric if (hasBP(MF)) 1046480093f4SDimitry Andric SavedRegs.set(RISCVABI::getBPReg()); 10470b57cec5SDimitry Andric 1048*0fca6ea1SDimitry Andric // When using cm.push/pop we must save X27 if we save X26. 1049*0fca6ea1SDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 1050*0fca6ea1SDimitry Andric if (RVFI->isPushable(MF) && SavedRegs.test(RISCV::X26)) 1051*0fca6ea1SDimitry Andric SavedRegs.set(RISCV::X27); 10520b57cec5SDimitry Andric } 10530b57cec5SDimitry Andric 105481ad6265SDimitry Andric std::pair<int64_t, Align> 1055753f127fSDimitry Andric RISCVFrameLowering::assignRVVStackObjectOffsets(MachineFunction &MF) const { 1056753f127fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 1057fe6060f1SDimitry Andric // Create a buffer of RVV objects to allocate. 1058fe6060f1SDimitry Andric SmallVector<int, 8> ObjectsToAllocate; 1059*0fca6ea1SDimitry Andric auto pushRVVObjects = [&](int FIBegin, int FIEnd) { 1060*0fca6ea1SDimitry Andric for (int I = FIBegin, E = FIEnd; I != E; ++I) { 1061fe6060f1SDimitry Andric unsigned StackID = MFI.getStackID(I); 1062fe6060f1SDimitry Andric if (StackID != TargetStackID::ScalableVector) 1063fe6060f1SDimitry Andric continue; 1064fe6060f1SDimitry Andric if (MFI.isDeadObjectIndex(I)) 1065fe6060f1SDimitry Andric continue; 1066fe6060f1SDimitry Andric 1067fe6060f1SDimitry Andric ObjectsToAllocate.push_back(I); 1068fe6060f1SDimitry Andric } 1069*0fca6ea1SDimitry Andric }; 1070*0fca6ea1SDimitry Andric // First push RVV Callee Saved object, then push RVV stack object 1071*0fca6ea1SDimitry Andric std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo(); 1072*0fca6ea1SDimitry Andric const auto &RVVCSI = getRVVCalleeSavedInfo(MF, CSI); 1073*0fca6ea1SDimitry Andric if (!RVVCSI.empty()) 1074*0fca6ea1SDimitry Andric pushRVVObjects(RVVCSI[0].getFrameIdx(), 1075*0fca6ea1SDimitry Andric RVVCSI[RVVCSI.size() - 1].getFrameIdx() + 1); 1076*0fca6ea1SDimitry Andric pushRVVObjects(0, MFI.getObjectIndexEnd() - RVVCSI.size()); 1077fe6060f1SDimitry Andric 107881ad6265SDimitry Andric // The minimum alignment is 16 bytes. 107981ad6265SDimitry Andric Align RVVStackAlign(16); 1080753f127fSDimitry Andric const auto &ST = MF.getSubtarget<RISCVSubtarget>(); 1081753f127fSDimitry Andric 1082753f127fSDimitry Andric if (!ST.hasVInstructions()) { 1083753f127fSDimitry Andric assert(ObjectsToAllocate.empty() && 1084753f127fSDimitry Andric "Can't allocate scalable-vector objects without V instructions"); 1085753f127fSDimitry Andric return std::make_pair(0, RVVStackAlign); 1086753f127fSDimitry Andric } 1087753f127fSDimitry Andric 1088753f127fSDimitry Andric // Allocate all RVV locals and spills 1089753f127fSDimitry Andric int64_t Offset = 0; 1090fe6060f1SDimitry Andric for (int FI : ObjectsToAllocate) { 1091fe6060f1SDimitry Andric // ObjectSize in bytes. 1092fe6060f1SDimitry Andric int64_t ObjectSize = MFI.getObjectSize(FI); 109381ad6265SDimitry Andric auto ObjectAlign = std::max(Align(8), MFI.getObjectAlign(FI)); 1094fe6060f1SDimitry Andric // If the data type is the fractional vector type, reserve one vector 1095fe6060f1SDimitry Andric // register for it. 1096fe6060f1SDimitry Andric if (ObjectSize < 8) 1097fe6060f1SDimitry Andric ObjectSize = 8; 109881ad6265SDimitry Andric Offset = alignTo(Offset + ObjectSize, ObjectAlign); 1099fe6060f1SDimitry Andric MFI.setObjectOffset(FI, -Offset); 110081ad6265SDimitry Andric // Update the maximum alignment of the RVV stack section 110181ad6265SDimitry Andric RVVStackAlign = std::max(RVVStackAlign, ObjectAlign); 1102fe6060f1SDimitry Andric } 1103fe6060f1SDimitry Andric 110481ad6265SDimitry Andric // Ensure the alignment of the RVV stack. Since we want the most-aligned 110581ad6265SDimitry Andric // object right at the bottom (i.e., any padding at the top of the frame), 110681ad6265SDimitry Andric // readjust all RVV objects down by the alignment padding. 110781ad6265SDimitry Andric uint64_t StackSize = Offset; 110881ad6265SDimitry Andric if (auto AlignmentPadding = offsetToAlignment(StackSize, RVVStackAlign)) { 110981ad6265SDimitry Andric StackSize += AlignmentPadding; 111081ad6265SDimitry Andric for (int FI : ObjectsToAllocate) 111181ad6265SDimitry Andric MFI.setObjectOffset(FI, MFI.getObjectOffset(FI) - AlignmentPadding); 1112fe6060f1SDimitry Andric } 1113fe6060f1SDimitry Andric 111481ad6265SDimitry Andric return std::make_pair(StackSize, RVVStackAlign); 111581ad6265SDimitry Andric } 111681ad6265SDimitry Andric 111781ad6265SDimitry Andric static unsigned getScavSlotsNumForRVV(MachineFunction &MF) { 111881ad6265SDimitry Andric // For RVV spill, scalable stack offsets computing requires up to two scratch 111981ad6265SDimitry Andric // registers 112081ad6265SDimitry Andric static constexpr unsigned ScavSlotsNumRVVSpillScalableObject = 2; 112181ad6265SDimitry Andric 112281ad6265SDimitry Andric // For RVV spill, non-scalable stack offsets computing requires up to one 112381ad6265SDimitry Andric // scratch register. 112481ad6265SDimitry Andric static constexpr unsigned ScavSlotsNumRVVSpillNonScalableObject = 1; 112581ad6265SDimitry Andric 112681ad6265SDimitry Andric // ADDI instruction's destination register can be used for computing 112781ad6265SDimitry Andric // offsets. So Scalable stack offsets require up to one scratch register. 112881ad6265SDimitry Andric static constexpr unsigned ScavSlotsADDIScalableObject = 1; 112981ad6265SDimitry Andric 113081ad6265SDimitry Andric static constexpr unsigned MaxScavSlotsNumKnown = 113181ad6265SDimitry Andric std::max({ScavSlotsADDIScalableObject, ScavSlotsNumRVVSpillScalableObject, 113281ad6265SDimitry Andric ScavSlotsNumRVVSpillNonScalableObject}); 113381ad6265SDimitry Andric 113481ad6265SDimitry Andric unsigned MaxScavSlotsNum = 0; 1135349cc55cSDimitry Andric if (!MF.getSubtarget<RISCVSubtarget>().hasVInstructions()) 1136fe6060f1SDimitry Andric return false; 113781ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) 113881ad6265SDimitry Andric for (const MachineInstr &MI : MBB) { 113981ad6265SDimitry Andric bool IsRVVSpill = RISCV::isRVVSpill(MI); 114081ad6265SDimitry Andric for (auto &MO : MI.operands()) { 114181ad6265SDimitry Andric if (!MO.isFI()) 114281ad6265SDimitry Andric continue; 114381ad6265SDimitry Andric bool IsScalableVectorID = MF.getFrameInfo().getStackID(MO.getIndex()) == 114481ad6265SDimitry Andric TargetStackID::ScalableVector; 114581ad6265SDimitry Andric if (IsRVVSpill) { 114681ad6265SDimitry Andric MaxScavSlotsNum = std::max( 114781ad6265SDimitry Andric MaxScavSlotsNum, IsScalableVectorID 114881ad6265SDimitry Andric ? ScavSlotsNumRVVSpillScalableObject 114981ad6265SDimitry Andric : ScavSlotsNumRVVSpillNonScalableObject); 115081ad6265SDimitry Andric } else if (MI.getOpcode() == RISCV::ADDI && IsScalableVectorID) { 115181ad6265SDimitry Andric MaxScavSlotsNum = 115281ad6265SDimitry Andric std::max(MaxScavSlotsNum, ScavSlotsADDIScalableObject); 115381ad6265SDimitry Andric } 115481ad6265SDimitry Andric } 115581ad6265SDimitry Andric if (MaxScavSlotsNum == MaxScavSlotsNumKnown) 115681ad6265SDimitry Andric return MaxScavSlotsNumKnown; 115781ad6265SDimitry Andric } 115881ad6265SDimitry Andric return MaxScavSlotsNum; 1159fe6060f1SDimitry Andric } 1160fe6060f1SDimitry Andric 1161fe6060f1SDimitry Andric static bool hasRVVFrameObject(const MachineFunction &MF) { 116204eeddc0SDimitry Andric // Originally, the function will scan all the stack objects to check whether 116304eeddc0SDimitry Andric // if there is any scalable vector object on the stack or not. However, it 116404eeddc0SDimitry Andric // causes errors in the register allocator. In issue 53016, it returns false 116504eeddc0SDimitry Andric // before RA because there is no RVV stack objects. After RA, it returns true 116604eeddc0SDimitry Andric // because there are spilling slots for RVV values during RA. It will not 116704eeddc0SDimitry Andric // reserve BP during register allocation and generate BP access in the PEI 116804eeddc0SDimitry Andric // pass due to the inconsistent behavior of the function. 116904eeddc0SDimitry Andric // 117004eeddc0SDimitry Andric // The function is changed to use hasVInstructions() as the return value. It 117104eeddc0SDimitry Andric // is not precise, but it can make the register allocation correct. 117204eeddc0SDimitry Andric // 117304eeddc0SDimitry Andric // FIXME: Find a better way to make the decision or revisit the solution in 117404eeddc0SDimitry Andric // D103622. 117504eeddc0SDimitry Andric // 117604eeddc0SDimitry Andric // Refer to https://github.com/llvm/llvm-project/issues/53016. 117704eeddc0SDimitry Andric return MF.getSubtarget<RISCVSubtarget>().hasVInstructions(); 1178fe6060f1SDimitry Andric } 1179fe6060f1SDimitry Andric 1180bdd1243dSDimitry Andric static unsigned estimateFunctionSizeInBytes(const MachineFunction &MF, 1181bdd1243dSDimitry Andric const RISCVInstrInfo &TII) { 1182bdd1243dSDimitry Andric unsigned FnSize = 0; 1183bdd1243dSDimitry Andric for (auto &MBB : MF) { 1184bdd1243dSDimitry Andric for (auto &MI : MBB) { 1185bdd1243dSDimitry Andric // Far branches over 20-bit offset will be relaxed in branch relaxation 1186bdd1243dSDimitry Andric // pass. In the worst case, conditional branches will be relaxed into 1187bdd1243dSDimitry Andric // the following instruction sequence. Unconditional branches are 1188bdd1243dSDimitry Andric // relaxed in the same way, with the exception that there is no first 1189bdd1243dSDimitry Andric // branch instruction. 1190bdd1243dSDimitry Andric // 1191bdd1243dSDimitry Andric // foo 1192bdd1243dSDimitry Andric // bne t5, t6, .rev_cond # `TII->getInstSizeInBytes(MI)` bytes 1193bdd1243dSDimitry Andric // sd s11, 0(sp) # 4 bytes, or 2 bytes in RVC 1194bdd1243dSDimitry Andric // jump .restore, s11 # 8 bytes 1195bdd1243dSDimitry Andric // .rev_cond 1196bdd1243dSDimitry Andric // bar 1197bdd1243dSDimitry Andric // j .dest_bb # 4 bytes, or 2 bytes in RVC 1198bdd1243dSDimitry Andric // .restore: 1199bdd1243dSDimitry Andric // ld s11, 0(sp) # 4 bytes, or 2 bytes in RVC 1200bdd1243dSDimitry Andric // .dest: 1201bdd1243dSDimitry Andric // baz 1202bdd1243dSDimitry Andric if (MI.isConditionalBranch()) 1203bdd1243dSDimitry Andric FnSize += TII.getInstSizeInBytes(MI); 1204bdd1243dSDimitry Andric if (MI.isConditionalBranch() || MI.isUnconditionalBranch()) { 1205*0fca6ea1SDimitry Andric if (MF.getSubtarget<RISCVSubtarget>().hasStdExtCOrZca()) 1206bdd1243dSDimitry Andric FnSize += 2 + 8 + 2 + 2; 1207bdd1243dSDimitry Andric else 1208bdd1243dSDimitry Andric FnSize += 4 + 8 + 4 + 4; 1209bdd1243dSDimitry Andric continue; 1210bdd1243dSDimitry Andric } 1211bdd1243dSDimitry Andric 1212bdd1243dSDimitry Andric FnSize += TII.getInstSizeInBytes(MI); 1213bdd1243dSDimitry Andric } 1214bdd1243dSDimitry Andric } 1215bdd1243dSDimitry Andric return FnSize; 1216bdd1243dSDimitry Andric } 1217bdd1243dSDimitry Andric 1218bdd1243dSDimitry Andric void RISCVFrameLowering::processFunctionBeforeFrameFinalized( 1219bdd1243dSDimitry Andric MachineFunction &MF, RegScavenger *RS) const { 1220bdd1243dSDimitry Andric const RISCVRegisterInfo *RegInfo = 1221bdd1243dSDimitry Andric MF.getSubtarget<RISCVSubtarget>().getRegisterInfo(); 1222bdd1243dSDimitry Andric const RISCVInstrInfo *TII = MF.getSubtarget<RISCVSubtarget>().getInstrInfo(); 1223bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 1224bdd1243dSDimitry Andric const TargetRegisterClass *RC = &RISCV::GPRRegClass; 1225bdd1243dSDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 1226bdd1243dSDimitry Andric 1227bdd1243dSDimitry Andric int64_t RVVStackSize; 1228bdd1243dSDimitry Andric Align RVVStackAlign; 1229bdd1243dSDimitry Andric std::tie(RVVStackSize, RVVStackAlign) = assignRVVStackObjectOffsets(MF); 1230bdd1243dSDimitry Andric 1231bdd1243dSDimitry Andric RVFI->setRVVStackSize(RVVStackSize); 1232bdd1243dSDimitry Andric RVFI->setRVVStackAlign(RVVStackAlign); 1233bdd1243dSDimitry Andric 1234bdd1243dSDimitry Andric if (hasRVVFrameObject(MF)) { 1235bdd1243dSDimitry Andric // Ensure the entire stack is aligned to at least the RVV requirement: some 1236bdd1243dSDimitry Andric // scalable-vector object alignments are not considered by the 1237bdd1243dSDimitry Andric // target-independent code. 1238bdd1243dSDimitry Andric MFI.ensureMaxAlignment(RVVStackAlign); 1239bdd1243dSDimitry Andric } 1240bdd1243dSDimitry Andric 1241bdd1243dSDimitry Andric unsigned ScavSlotsNum = 0; 1242bdd1243dSDimitry Andric 1243bdd1243dSDimitry Andric // estimateStackSize has been observed to under-estimate the final stack 1244bdd1243dSDimitry Andric // size, so give ourselves wiggle-room by checking for stack size 1245bdd1243dSDimitry Andric // representable an 11-bit signed field rather than 12-bits. 1246bdd1243dSDimitry Andric if (!isInt<11>(MFI.estimateStackSize(MF))) 1247bdd1243dSDimitry Andric ScavSlotsNum = 1; 1248bdd1243dSDimitry Andric 1249bdd1243dSDimitry Andric // Far branches over 20-bit offset require a spill slot for scratch register. 1250bdd1243dSDimitry Andric bool IsLargeFunction = !isInt<20>(estimateFunctionSizeInBytes(MF, *TII)); 1251bdd1243dSDimitry Andric if (IsLargeFunction) 1252bdd1243dSDimitry Andric ScavSlotsNum = std::max(ScavSlotsNum, 1u); 1253bdd1243dSDimitry Andric 1254bdd1243dSDimitry Andric // RVV loads & stores have no capacity to hold the immediate address offsets 1255bdd1243dSDimitry Andric // so we must always reserve an emergency spill slot if the MachineFunction 1256bdd1243dSDimitry Andric // contains any RVV spills. 1257bdd1243dSDimitry Andric ScavSlotsNum = std::max(ScavSlotsNum, getScavSlotsNumForRVV(MF)); 1258bdd1243dSDimitry Andric 1259bdd1243dSDimitry Andric for (unsigned I = 0; I < ScavSlotsNum; I++) { 1260bdd1243dSDimitry Andric int FI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC), 1261bdd1243dSDimitry Andric RegInfo->getSpillAlign(*RC), false); 1262bdd1243dSDimitry Andric RS->addScavengingFrameIndex(FI); 1263bdd1243dSDimitry Andric 1264bdd1243dSDimitry Andric if (IsLargeFunction && RVFI->getBranchRelaxationScratchFrameIndex() == -1) 1265bdd1243dSDimitry Andric RVFI->setBranchRelaxationScratchFrameIndex(FI); 1266bdd1243dSDimitry Andric } 1267bdd1243dSDimitry Andric 1268*0fca6ea1SDimitry Andric unsigned Size = RVFI->getReservedSpillsSize(); 1269bdd1243dSDimitry Andric for (const auto &Info : MFI.getCalleeSavedInfo()) { 1270bdd1243dSDimitry Andric int FrameIdx = Info.getFrameIdx(); 1271*0fca6ea1SDimitry Andric if (FrameIdx < 0 || MFI.getStackID(FrameIdx) != TargetStackID::Default) 1272bdd1243dSDimitry Andric continue; 1273bdd1243dSDimitry Andric 1274bdd1243dSDimitry Andric Size += MFI.getObjectSize(FrameIdx); 1275bdd1243dSDimitry Andric } 1276bdd1243dSDimitry Andric RVFI->setCalleeSavedStackSize(Size); 1277bdd1243dSDimitry Andric } 1278bdd1243dSDimitry Andric 12790b57cec5SDimitry Andric // Not preserve stack space within prologue for outgoing variables when the 1280fe6060f1SDimitry Andric // function contains variable size objects or there are vector objects accessed 1281fe6060f1SDimitry Andric // by the frame pointer. 1282fe6060f1SDimitry Andric // Let eliminateCallFramePseudoInstr preserve stack space for it. 12830b57cec5SDimitry Andric bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 1284fe6060f1SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects() && 1285fe6060f1SDimitry Andric !(hasFP(MF) && hasRVVFrameObject(MF)); 12860b57cec5SDimitry Andric } 12870b57cec5SDimitry Andric 12880b57cec5SDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 12890b57cec5SDimitry Andric MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( 12900b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 12910b57cec5SDimitry Andric MachineBasicBlock::iterator MI) const { 12928bcb0991SDimitry Andric Register SPReg = RISCV::X2; 12930b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 12940b57cec5SDimitry Andric 12950b57cec5SDimitry Andric if (!hasReservedCallFrame(MF)) { 12960b57cec5SDimitry Andric // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 12970b57cec5SDimitry Andric // ADJCALLSTACKUP must be converted to instructions manipulating the stack 12980b57cec5SDimitry Andric // pointer. This is necessary when there is a variable length stack 12990b57cec5SDimitry Andric // allocation (e.g. alloca), which means it's not possible to allocate 13000b57cec5SDimitry Andric // space for outgoing arguments from within the function prologue. 13010b57cec5SDimitry Andric int64_t Amount = MI->getOperand(0).getImm(); 13020b57cec5SDimitry Andric 13030b57cec5SDimitry Andric if (Amount != 0) { 13040b57cec5SDimitry Andric // Ensure the stack remains aligned after adjustment. 13050b57cec5SDimitry Andric Amount = alignSPAdjust(Amount); 13060b57cec5SDimitry Andric 13070b57cec5SDimitry Andric if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN) 13080b57cec5SDimitry Andric Amount = -Amount; 13090b57cec5SDimitry Andric 1310bdd1243dSDimitry Andric const RISCVRegisterInfo &RI = *STI.getRegisterInfo(); 1311bdd1243dSDimitry Andric RI.adjustReg(MBB, MI, DL, SPReg, SPReg, StackOffset::getFixed(Amount), 1312bdd1243dSDimitry Andric MachineInstr::NoFlags, getStackAlign()); 13130b57cec5SDimitry Andric } 13140b57cec5SDimitry Andric } 13150b57cec5SDimitry Andric 13160b57cec5SDimitry Andric return MBB.erase(MI); 13170b57cec5SDimitry Andric } 13188bcb0991SDimitry Andric 13198bcb0991SDimitry Andric // We would like to split the SP adjustment to reduce prologue/epilogue 13208bcb0991SDimitry Andric // as following instructions. In this way, the offset of the callee saved 13215f757f3fSDimitry Andric // register could fit in a single store. Supposed that the first sp adjust 13225f757f3fSDimitry Andric // amount is 2032. 13238bcb0991SDimitry Andric // add sp,sp,-2032 13248bcb0991SDimitry Andric // sw ra,2028(sp) 13258bcb0991SDimitry Andric // sw s0,2024(sp) 13268bcb0991SDimitry Andric // sw s1,2020(sp) 13278bcb0991SDimitry Andric // sw s3,2012(sp) 13288bcb0991SDimitry Andric // sw s4,2008(sp) 13298bcb0991SDimitry Andric // add sp,sp,-64 13308bcb0991SDimitry Andric uint64_t 13318bcb0991SDimitry Andric RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { 13325ffd83dbSDimitry Andric const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 13338bcb0991SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 13348bcb0991SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 133581ad6265SDimitry Andric uint64_t StackSize = getStackSizeWithRVVPadding(MF); 13368bcb0991SDimitry Andric 133781ad6265SDimitry Andric // Disable SplitSPAdjust if save-restore libcall is used. The callee-saved 13385ffd83dbSDimitry Andric // registers will be pushed by the save-restore libcalls, so we don't have to 13395ffd83dbSDimitry Andric // split the SP adjustment in this case. 13405f757f3fSDimitry Andric if (RVFI->getReservedSpillsSize()) 13415ffd83dbSDimitry Andric return 0; 13425ffd83dbSDimitry Andric 134381ad6265SDimitry Andric // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed 134481ad6265SDimitry Andric // 12-bit and there exists a callee-saved register needing to be pushed. 13458bcb0991SDimitry Andric if (!isInt<12>(StackSize) && (CSI.size() > 0)) { 13465f757f3fSDimitry Andric // FirstSPAdjustAmount is chosen at most as (2048 - StackAlign) because 13475f757f3fSDimitry Andric // 2048 will cause sp = sp + 2048 in the epilogue to be split into multiple 134881ad6265SDimitry Andric // instructions. Offsets smaller than 2048 can fit in a single load/store 134981ad6265SDimitry Andric // instruction, and we have to stick with the stack alignment. 2048 has 135081ad6265SDimitry Andric // 16-byte alignment. The stack alignment for RV32 and RV64 is 16 and for 135181ad6265SDimitry Andric // RV32E it is 4. So (2048 - StackAlign) will satisfy the stack alignment. 13525f757f3fSDimitry Andric const uint64_t StackAlign = getStackAlign().value(); 13535f757f3fSDimitry Andric 13545f757f3fSDimitry Andric // Amount of (2048 - StackAlign) will prevent callee saved and restored 13555f757f3fSDimitry Andric // instructions be compressed, so try to adjust the amount to the largest 13565f757f3fSDimitry Andric // offset that stack compression instructions accept when target supports 13575f757f3fSDimitry Andric // compression instructions. 13585f757f3fSDimitry Andric if (STI.hasStdExtCOrZca()) { 13595f757f3fSDimitry Andric // The compression extensions may support the following instructions: 13605f757f3fSDimitry Andric // riscv32: c.lwsp rd, offset[7:2] => 2^(6 + 2) 13615f757f3fSDimitry Andric // c.swsp rs2, offset[7:2] => 2^(6 + 2) 13625f757f3fSDimitry Andric // c.flwsp rd, offset[7:2] => 2^(6 + 2) 13635f757f3fSDimitry Andric // c.fswsp rs2, offset[7:2] => 2^(6 + 2) 13645f757f3fSDimitry Andric // riscv64: c.ldsp rd, offset[8:3] => 2^(6 + 3) 13655f757f3fSDimitry Andric // c.sdsp rs2, offset[8:3] => 2^(6 + 3) 13665f757f3fSDimitry Andric // c.fldsp rd, offset[8:3] => 2^(6 + 3) 13675f757f3fSDimitry Andric // c.fsdsp rs2, offset[8:3] => 2^(6 + 3) 13685f757f3fSDimitry Andric const uint64_t RVCompressLen = STI.getXLen() * 8; 13695f757f3fSDimitry Andric // Compared with amount (2048 - StackAlign), StackSize needs to 13705f757f3fSDimitry Andric // satisfy the following conditions to avoid using more instructions 13715f757f3fSDimitry Andric // to adjust the sp after adjusting the amount, such as 13725f757f3fSDimitry Andric // StackSize meets the condition (StackSize <= 2048 + RVCompressLen), 13735f757f3fSDimitry Andric // case1: Amount is 2048 - StackAlign: use addi + addi to adjust sp. 13745f757f3fSDimitry Andric // case2: Amount is RVCompressLen: use addi + addi to adjust sp. 13755f757f3fSDimitry Andric auto CanCompress = [&](uint64_t CompressLen) -> bool { 13765f757f3fSDimitry Andric if (StackSize <= 2047 + CompressLen || 13775f757f3fSDimitry Andric (StackSize > 2048 * 2 - StackAlign && 13785f757f3fSDimitry Andric StackSize <= 2047 * 2 + CompressLen) || 13795f757f3fSDimitry Andric StackSize > 2048 * 3 - StackAlign) 13805f757f3fSDimitry Andric return true; 13815f757f3fSDimitry Andric 13825f757f3fSDimitry Andric return false; 13835f757f3fSDimitry Andric }; 13845f757f3fSDimitry Andric // In the epilogue, addi sp, sp, 496 is used to recover the sp and it 13855f757f3fSDimitry Andric // can be compressed(C.ADDI16SP, offset can be [-512, 496]), but 13865f757f3fSDimitry Andric // addi sp, sp, 512 can not be compressed. So try to use 496 first. 13875f757f3fSDimitry Andric const uint64_t ADDI16SPCompressLen = 496; 13885f757f3fSDimitry Andric if (STI.is64Bit() && CanCompress(ADDI16SPCompressLen)) 13895f757f3fSDimitry Andric return ADDI16SPCompressLen; 13905f757f3fSDimitry Andric if (CanCompress(RVCompressLen)) 13915f757f3fSDimitry Andric return RVCompressLen; 13925f757f3fSDimitry Andric } 13935f757f3fSDimitry Andric return 2048 - StackAlign; 13948bcb0991SDimitry Andric } 13958bcb0991SDimitry Andric return 0; 13968bcb0991SDimitry Andric } 13975ffd83dbSDimitry Andric 1398*0fca6ea1SDimitry Andric bool RISCVFrameLowering::assignCalleeSavedSpillSlots( 1399*0fca6ea1SDimitry Andric MachineFunction &MF, const TargetRegisterInfo *TRI, 1400*0fca6ea1SDimitry Andric std::vector<CalleeSavedInfo> &CSI, unsigned &MinCSFrameIndex, 1401*0fca6ea1SDimitry Andric unsigned &MaxCSFrameIndex) const { 1402*0fca6ea1SDimitry Andric // Early exit if no callee saved registers are modified! 1403*0fca6ea1SDimitry Andric if (CSI.empty()) 1404*0fca6ea1SDimitry Andric return true; 1405*0fca6ea1SDimitry Andric 1406*0fca6ea1SDimitry Andric auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 1407*0fca6ea1SDimitry Andric 1408*0fca6ea1SDimitry Andric if (RVFI->isPushable(MF)) { 1409*0fca6ea1SDimitry Andric // Determine how many GPRs we need to push and save it to RVFI. 1410*0fca6ea1SDimitry Andric Register MaxReg = getMaxPushPopReg(MF, CSI); 1411*0fca6ea1SDimitry Andric if (MaxReg != RISCV::NoRegister) { 1412*0fca6ea1SDimitry Andric auto [RegEnc, PushedRegNum] = getPushPopEncodingAndNum(MaxReg); 1413*0fca6ea1SDimitry Andric RVFI->setRVPushRegs(PushedRegNum); 1414*0fca6ea1SDimitry Andric RVFI->setRVPushStackSize(alignTo((STI.getXLen() / 8) * PushedRegNum, 16)); 1415*0fca6ea1SDimitry Andric 1416*0fca6ea1SDimitry Andric // Use encoded number to represent registers to spill. 1417*0fca6ea1SDimitry Andric RVFI->setRVPushRlist(RegEnc); 1418*0fca6ea1SDimitry Andric } 1419*0fca6ea1SDimitry Andric } 1420*0fca6ea1SDimitry Andric 1421*0fca6ea1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 1422*0fca6ea1SDimitry Andric const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 1423*0fca6ea1SDimitry Andric 1424*0fca6ea1SDimitry Andric for (auto &CS : CSI) { 1425*0fca6ea1SDimitry Andric unsigned Reg = CS.getReg(); 1426*0fca6ea1SDimitry Andric const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg); 1427*0fca6ea1SDimitry Andric unsigned Size = RegInfo->getSpillSize(*RC); 1428*0fca6ea1SDimitry Andric 1429*0fca6ea1SDimitry Andric // This might need a fixed stack slot. 1430*0fca6ea1SDimitry Andric if (RVFI->useSaveRestoreLibCalls(MF) || RVFI->isPushable(MF)) { 1431*0fca6ea1SDimitry Andric const auto *FII = llvm::find_if( 1432*0fca6ea1SDimitry Andric FixedCSRFIMap, [&](auto P) { return P.first == CS.getReg(); }); 1433*0fca6ea1SDimitry Andric if (FII != std::end(FixedCSRFIMap)) { 1434*0fca6ea1SDimitry Andric int64_t Offset; 1435*0fca6ea1SDimitry Andric if (RVFI->isPushable(MF)) 1436*0fca6ea1SDimitry Andric Offset = -((FII->second + RVFI->getRVPushRegs() + 1) * (int64_t)Size); 1437*0fca6ea1SDimitry Andric else 1438*0fca6ea1SDimitry Andric Offset = FII->second * (int64_t)Size; 1439*0fca6ea1SDimitry Andric 1440*0fca6ea1SDimitry Andric int FrameIdx = MFI.CreateFixedSpillStackObject(Size, Offset); 1441*0fca6ea1SDimitry Andric assert(FrameIdx < 0); 1442*0fca6ea1SDimitry Andric CS.setFrameIdx(FrameIdx); 1443*0fca6ea1SDimitry Andric continue; 1444*0fca6ea1SDimitry Andric } 1445*0fca6ea1SDimitry Andric } 1446*0fca6ea1SDimitry Andric 1447*0fca6ea1SDimitry Andric // Not a fixed slot. 1448*0fca6ea1SDimitry Andric Align Alignment = RegInfo->getSpillAlign(*RC); 1449*0fca6ea1SDimitry Andric // We may not be able to satisfy the desired alignment specification of 1450*0fca6ea1SDimitry Andric // the TargetRegisterClass if the stack alignment is smaller. Use the 1451*0fca6ea1SDimitry Andric // min. 1452*0fca6ea1SDimitry Andric Alignment = std::min(Alignment, getStackAlign()); 1453*0fca6ea1SDimitry Andric int FrameIdx = MFI.CreateStackObject(Size, Alignment, true); 1454*0fca6ea1SDimitry Andric if ((unsigned)FrameIdx < MinCSFrameIndex) 1455*0fca6ea1SDimitry Andric MinCSFrameIndex = FrameIdx; 1456*0fca6ea1SDimitry Andric if ((unsigned)FrameIdx > MaxCSFrameIndex) 1457*0fca6ea1SDimitry Andric MaxCSFrameIndex = FrameIdx; 1458*0fca6ea1SDimitry Andric CS.setFrameIdx(FrameIdx); 1459*0fca6ea1SDimitry Andric } 1460*0fca6ea1SDimitry Andric 1461*0fca6ea1SDimitry Andric // Allocate a fixed object that covers the full push or libcall size. 1462*0fca6ea1SDimitry Andric if (RVFI->isPushable(MF)) { 1463*0fca6ea1SDimitry Andric if (int64_t PushSize = RVFI->getRVPushStackSize()) 1464*0fca6ea1SDimitry Andric MFI.CreateFixedSpillStackObject(PushSize, -PushSize); 1465*0fca6ea1SDimitry Andric } else if (int LibCallRegs = getLibCallID(MF, CSI) + 1) { 1466*0fca6ea1SDimitry Andric int64_t LibCallFrameSize = 1467*0fca6ea1SDimitry Andric alignTo((STI.getXLen() / 8) * LibCallRegs, getStackAlign()); 1468*0fca6ea1SDimitry Andric MFI.CreateFixedSpillStackObject(LibCallFrameSize, -LibCallFrameSize); 1469*0fca6ea1SDimitry Andric } 1470*0fca6ea1SDimitry Andric 1471*0fca6ea1SDimitry Andric return true; 1472*0fca6ea1SDimitry Andric } 1473*0fca6ea1SDimitry Andric 14745ffd83dbSDimitry Andric bool RISCVFrameLowering::spillCalleeSavedRegisters( 14755ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 14765ffd83dbSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 14775ffd83dbSDimitry Andric if (CSI.empty()) 14785ffd83dbSDimitry Andric return true; 14795ffd83dbSDimitry Andric 14805ffd83dbSDimitry Andric MachineFunction *MF = MBB.getParent(); 14815ffd83dbSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 14825ffd83dbSDimitry Andric DebugLoc DL; 14835ffd83dbSDimitry Andric if (MI != MBB.end() && !MI->isDebugInstr()) 14845ffd83dbSDimitry Andric DL = MI->getDebugLoc(); 14855ffd83dbSDimitry Andric 148606c3fb27SDimitry Andric // Emit CM.PUSH with base SPimm & evaluate Push stack 148706c3fb27SDimitry Andric RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>(); 148806c3fb27SDimitry Andric if (RVFI->isPushable(*MF)) { 1489*0fca6ea1SDimitry Andric unsigned PushedRegNum = RVFI->getRVPushRegs(); 1490*0fca6ea1SDimitry Andric if (PushedRegNum > 0) { 149106c3fb27SDimitry Andric // Use encoded number to represent registers to spill. 1492*0fca6ea1SDimitry Andric int RegEnc = RVFI->getRVPushRlist(); 149306c3fb27SDimitry Andric MachineInstrBuilder PushBuilder = 149406c3fb27SDimitry Andric BuildMI(MBB, MI, DL, TII.get(RISCV::CM_PUSH)) 149506c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 149606c3fb27SDimitry Andric PushBuilder.addImm((int64_t)RegEnc); 149706c3fb27SDimitry Andric PushBuilder.addImm(0); 149806c3fb27SDimitry Andric 14998a4dda33SDimitry Andric for (unsigned i = 0; i < PushedRegNum; i++) 1500*0fca6ea1SDimitry Andric PushBuilder.addUse(FixedCSRFIMap[i].first, RegState::Implicit); 150106c3fb27SDimitry Andric } 150206c3fb27SDimitry Andric } else if (const char *SpillLibCall = getSpillLibCallName(*MF, CSI)) { 15035ffd83dbSDimitry Andric // Add spill libcall via non-callee-saved register t0. 15045ffd83dbSDimitry Andric BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoCALLReg), RISCV::X5) 15055ffd83dbSDimitry Andric .addExternalSymbol(SpillLibCall, RISCVII::MO_CALL) 15065ffd83dbSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 15075ffd83dbSDimitry Andric 15085ffd83dbSDimitry Andric // Add registers spilled in libcall as liveins. 15095ffd83dbSDimitry Andric for (auto &CS : CSI) 15105ffd83dbSDimitry Andric MBB.addLiveIn(CS.getReg()); 15115ffd83dbSDimitry Andric } 15125ffd83dbSDimitry Andric 151306c3fb27SDimitry Andric // Manually spill values not spilled by libcall & Push/Pop. 151406c3fb27SDimitry Andric const auto &UnmanagedCSI = getUnmanagedCSI(*MF, CSI); 1515*0fca6ea1SDimitry Andric const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI); 1516*0fca6ea1SDimitry Andric 1517*0fca6ea1SDimitry Andric auto storeRegToStackSlot = [&](decltype(UnmanagedCSI) CSInfo) { 1518*0fca6ea1SDimitry Andric for (auto &CS : CSInfo) { 15195ffd83dbSDimitry Andric // Insert the spill to the stack frame. 15205ffd83dbSDimitry Andric Register Reg = CS.getReg(); 15215ffd83dbSDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 1522*0fca6ea1SDimitry Andric TII.storeRegToStackSlot(MBB, MI, Reg, !MBB.isLiveIn(Reg), 1523*0fca6ea1SDimitry Andric CS.getFrameIdx(), RC, TRI, Register()); 15245ffd83dbSDimitry Andric } 1525*0fca6ea1SDimitry Andric }; 1526*0fca6ea1SDimitry Andric storeRegToStackSlot(UnmanagedCSI); 1527*0fca6ea1SDimitry Andric storeRegToStackSlot(RVVCSI); 15285ffd83dbSDimitry Andric 15295ffd83dbSDimitry Andric return true; 15305ffd83dbSDimitry Andric } 15315ffd83dbSDimitry Andric 1532*0fca6ea1SDimitry Andric void RISCVFrameLowering::emitCalleeSavedRVVPrologCFI( 1533*0fca6ea1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, bool HasFP) const { 1534*0fca6ea1SDimitry Andric MachineFunction *MF = MBB.getParent(); 1535*0fca6ea1SDimitry Andric const MachineFrameInfo &MFI = MF->getFrameInfo(); 1536*0fca6ea1SDimitry Andric RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>(); 1537*0fca6ea1SDimitry Andric const TargetInstrInfo &TII = *STI.getInstrInfo(); 1538*0fca6ea1SDimitry Andric DebugLoc DL = MBB.findDebugLoc(MI); 1539*0fca6ea1SDimitry Andric 1540*0fca6ea1SDimitry Andric const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, MFI.getCalleeSavedInfo()); 1541*0fca6ea1SDimitry Andric if (RVVCSI.empty()) 1542*0fca6ea1SDimitry Andric return; 1543*0fca6ea1SDimitry Andric 1544*0fca6ea1SDimitry Andric uint64_t FixedSize = getStackSizeWithRVVPadding(*MF); 1545*0fca6ea1SDimitry Andric if (!HasFP) { 1546*0fca6ea1SDimitry Andric uint64_t ScalarLocalVarSize = 1547*0fca6ea1SDimitry Andric MFI.getStackSize() - RVFI->getCalleeSavedStackSize() - 1548*0fca6ea1SDimitry Andric RVFI->getRVPushStackSize() - RVFI->getVarArgsSaveSize() + 1549*0fca6ea1SDimitry Andric RVFI->getRVVPadding(); 1550*0fca6ea1SDimitry Andric FixedSize -= ScalarLocalVarSize; 1551*0fca6ea1SDimitry Andric } 1552*0fca6ea1SDimitry Andric 1553*0fca6ea1SDimitry Andric for (auto &CS : RVVCSI) { 1554*0fca6ea1SDimitry Andric // Insert the spill to the stack frame. 1555*0fca6ea1SDimitry Andric int FI = CS.getFrameIdx(); 1556*0fca6ea1SDimitry Andric if (FI >= 0 && MFI.getStackID(FI) == TargetStackID::ScalableVector) { 1557*0fca6ea1SDimitry Andric unsigned CFIIndex = MF->addFrameInst( 1558*0fca6ea1SDimitry Andric createDefCFAOffset(*STI.getRegisterInfo(), CS.getReg(), -FixedSize, 1559*0fca6ea1SDimitry Andric MFI.getObjectOffset(FI) / 8)); 1560*0fca6ea1SDimitry Andric BuildMI(MBB, MI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) 1561*0fca6ea1SDimitry Andric .addCFIIndex(CFIIndex) 1562*0fca6ea1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 1563*0fca6ea1SDimitry Andric } 1564*0fca6ea1SDimitry Andric } 1565*0fca6ea1SDimitry Andric } 1566*0fca6ea1SDimitry Andric 15675ffd83dbSDimitry Andric bool RISCVFrameLowering::restoreCalleeSavedRegisters( 15685ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 15695ffd83dbSDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 15705ffd83dbSDimitry Andric if (CSI.empty()) 15715ffd83dbSDimitry Andric return true; 15725ffd83dbSDimitry Andric 15735ffd83dbSDimitry Andric MachineFunction *MF = MBB.getParent(); 15745ffd83dbSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 15755ffd83dbSDimitry Andric DebugLoc DL; 15765ffd83dbSDimitry Andric if (MI != MBB.end() && !MI->isDebugInstr()) 15775ffd83dbSDimitry Andric DL = MI->getDebugLoc(); 15785ffd83dbSDimitry Andric 157906c3fb27SDimitry Andric // Manually restore values not restored by libcall & Push/Pop. 1580*0fca6ea1SDimitry Andric // Reverse the restore order in epilog. In addition, the return 1581*0fca6ea1SDimitry Andric // address will be restored first in the epilogue. It increases 1582*0fca6ea1SDimitry Andric // the opportunity to avoid the load-to-use data hazard between 1583*0fca6ea1SDimitry Andric // loading RA and return by RA. loadRegFromStackSlot can insert 1584*0fca6ea1SDimitry Andric // multiple instructions. 158506c3fb27SDimitry Andric const auto &UnmanagedCSI = getUnmanagedCSI(*MF, CSI); 1586*0fca6ea1SDimitry Andric const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI); 1587*0fca6ea1SDimitry Andric 1588*0fca6ea1SDimitry Andric auto loadRegFromStackSlot = [&](decltype(UnmanagedCSI) CSInfo) { 1589*0fca6ea1SDimitry Andric for (auto &CS : CSInfo) { 15905ffd83dbSDimitry Andric Register Reg = CS.getReg(); 15915ffd83dbSDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 1592bdd1243dSDimitry Andric TII.loadRegFromStackSlot(MBB, MI, Reg, CS.getFrameIdx(), RC, TRI, 1593bdd1243dSDimitry Andric Register()); 1594*0fca6ea1SDimitry Andric assert(MI != MBB.begin() && 1595*0fca6ea1SDimitry Andric "loadRegFromStackSlot didn't insert any code!"); 15965ffd83dbSDimitry Andric } 1597*0fca6ea1SDimitry Andric }; 1598*0fca6ea1SDimitry Andric loadRegFromStackSlot(RVVCSI); 1599*0fca6ea1SDimitry Andric loadRegFromStackSlot(UnmanagedCSI); 16005ffd83dbSDimitry Andric 160106c3fb27SDimitry Andric RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>(); 160206c3fb27SDimitry Andric if (RVFI->isPushable(*MF)) { 160306c3fb27SDimitry Andric int RegEnc = RVFI->getRVPushRlist(); 160406c3fb27SDimitry Andric if (RegEnc != llvm::RISCVZC::RLISTENCODE::INVALID_RLIST) { 160506c3fb27SDimitry Andric MachineInstrBuilder PopBuilder = 160606c3fb27SDimitry Andric BuildMI(MBB, MI, DL, TII.get(RISCV::CM_POP)) 160706c3fb27SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 160806c3fb27SDimitry Andric // Use encoded number to represent registers to restore. 160906c3fb27SDimitry Andric PopBuilder.addImm(RegEnc); 161006c3fb27SDimitry Andric PopBuilder.addImm(0); 161106c3fb27SDimitry Andric 161206c3fb27SDimitry Andric for (unsigned i = 0; i < RVFI->getRVPushRegs(); i++) 1613*0fca6ea1SDimitry Andric PopBuilder.addDef(FixedCSRFIMap[i].first, RegState::ImplicitDefine); 161406c3fb27SDimitry Andric } 161506c3fb27SDimitry Andric } else { 16165ffd83dbSDimitry Andric const char *RestoreLibCall = getRestoreLibCallName(*MF, CSI); 16175ffd83dbSDimitry Andric if (RestoreLibCall) { 16185ffd83dbSDimitry Andric // Add restore libcall via tail call. 16195ffd83dbSDimitry Andric MachineBasicBlock::iterator NewMI = 16205ffd83dbSDimitry Andric BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoTAIL)) 16215ffd83dbSDimitry Andric .addExternalSymbol(RestoreLibCall, RISCVII::MO_CALL) 16225ffd83dbSDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 16235ffd83dbSDimitry Andric 16245ffd83dbSDimitry Andric // Remove trailing returns, since the terminator is now a tail call to the 16255ffd83dbSDimitry Andric // restore function. 16265ffd83dbSDimitry Andric if (MI != MBB.end() && MI->getOpcode() == RISCV::PseudoRET) { 16275ffd83dbSDimitry Andric NewMI->copyImplicitOps(*MF, *MI); 16285ffd83dbSDimitry Andric MI->eraseFromParent(); 16295ffd83dbSDimitry Andric } 16305ffd83dbSDimitry Andric } 163106c3fb27SDimitry Andric } 16325ffd83dbSDimitry Andric return true; 16335ffd83dbSDimitry Andric } 16345ffd83dbSDimitry Andric 163581ad6265SDimitry Andric bool RISCVFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const { 163681ad6265SDimitry Andric // Keep the conventional code flow when not optimizing. 163781ad6265SDimitry Andric if (MF.getFunction().hasOptNone()) 163881ad6265SDimitry Andric return false; 163981ad6265SDimitry Andric 164081ad6265SDimitry Andric return true; 164181ad6265SDimitry Andric } 164281ad6265SDimitry Andric 16435ffd83dbSDimitry Andric bool RISCVFrameLowering::canUseAsPrologue(const MachineBasicBlock &MBB) const { 16445ffd83dbSDimitry Andric MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB); 16455ffd83dbSDimitry Andric const MachineFunction *MF = MBB.getParent(); 16465ffd83dbSDimitry Andric const auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>(); 16475ffd83dbSDimitry Andric 16485ffd83dbSDimitry Andric if (!RVFI->useSaveRestoreLibCalls(*MF)) 16495ffd83dbSDimitry Andric return true; 16505ffd83dbSDimitry Andric 16515ffd83dbSDimitry Andric // Inserting a call to a __riscv_save libcall requires the use of the register 16525ffd83dbSDimitry Andric // t0 (X5) to hold the return address. Therefore if this register is already 16535ffd83dbSDimitry Andric // used we can't insert the call. 16545ffd83dbSDimitry Andric 16555ffd83dbSDimitry Andric RegScavenger RS; 16565ffd83dbSDimitry Andric RS.enterBasicBlock(*TmpMBB); 16575ffd83dbSDimitry Andric return !RS.isRegUsed(RISCV::X5); 16585ffd83dbSDimitry Andric } 16595ffd83dbSDimitry Andric 16605ffd83dbSDimitry Andric bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const { 16615ffd83dbSDimitry Andric const MachineFunction *MF = MBB.getParent(); 16625ffd83dbSDimitry Andric MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB); 16635ffd83dbSDimitry Andric const auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>(); 16645ffd83dbSDimitry Andric 16655ffd83dbSDimitry Andric if (!RVFI->useSaveRestoreLibCalls(*MF)) 16665ffd83dbSDimitry Andric return true; 16675ffd83dbSDimitry Andric 16685ffd83dbSDimitry Andric // Using the __riscv_restore libcalls to restore CSRs requires a tail call. 16695ffd83dbSDimitry Andric // This means if we still need to continue executing code within this function 16705ffd83dbSDimitry Andric // the restore cannot take place in this basic block. 16715ffd83dbSDimitry Andric 16725ffd83dbSDimitry Andric if (MBB.succ_size() > 1) 16735ffd83dbSDimitry Andric return false; 16745ffd83dbSDimitry Andric 16755ffd83dbSDimitry Andric MachineBasicBlock *SuccMBB = 16765ffd83dbSDimitry Andric MBB.succ_empty() ? TmpMBB->getFallThrough() : *MBB.succ_begin(); 16775ffd83dbSDimitry Andric 16785ffd83dbSDimitry Andric // Doing a tail call should be safe if there are no successors, because either 16795ffd83dbSDimitry Andric // we have a returning block or the end of the block is unreachable, so the 16805ffd83dbSDimitry Andric // restore will be eliminated regardless. 16815ffd83dbSDimitry Andric if (!SuccMBB) 16825ffd83dbSDimitry Andric return true; 16835ffd83dbSDimitry Andric 16845ffd83dbSDimitry Andric // The successor can only contain a return, since we would effectively be 16855ffd83dbSDimitry Andric // replacing the successor with our own tail return at the end of our block. 16865ffd83dbSDimitry Andric return SuccMBB->isReturnBlock() && SuccMBB->size() == 1; 16875ffd83dbSDimitry Andric } 1688fe6060f1SDimitry Andric 1689fe6060f1SDimitry Andric bool RISCVFrameLowering::isSupportedStackID(TargetStackID::Value ID) const { 1690fe6060f1SDimitry Andric switch (ID) { 1691fe6060f1SDimitry Andric case TargetStackID::Default: 1692fe6060f1SDimitry Andric case TargetStackID::ScalableVector: 1693fe6060f1SDimitry Andric return true; 1694fe6060f1SDimitry Andric case TargetStackID::NoAlloc: 1695fe6060f1SDimitry Andric case TargetStackID::SGPRSpill: 1696fe6060f1SDimitry Andric case TargetStackID::WasmLocal: 1697fe6060f1SDimitry Andric return false; 1698fe6060f1SDimitry Andric } 1699fe6060f1SDimitry Andric llvm_unreachable("Invalid TargetStackID::Value"); 1700fe6060f1SDimitry Andric } 1701fe6060f1SDimitry Andric 1702fe6060f1SDimitry Andric TargetStackID::Value RISCVFrameLowering::getStackIDForScalableVectors() const { 1703fe6060f1SDimitry Andric return TargetStackID::ScalableVector; 1704fe6060f1SDimitry Andric } 1705