xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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