18971842fSAlex Bradbury //===-- RISCVFrameLowering.cpp - RISCV Frame Information ------------------===//
28971842fSAlex Bradbury //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68971842fSAlex Bradbury //
78971842fSAlex Bradbury //===----------------------------------------------------------------------===//
88971842fSAlex Bradbury //
98971842fSAlex Bradbury // This file contains the RISCV implementation of TargetFrameLowering class.
108971842fSAlex Bradbury //
118971842fSAlex Bradbury //===----------------------------------------------------------------------===//
128971842fSAlex Bradbury 
138971842fSAlex Bradbury #include "RISCVFrameLowering.h"
14c85be0deSAlex Bradbury #include "RISCVMachineFunctionInfo.h"
158971842fSAlex Bradbury #include "RISCVSubtarget.h"
168971842fSAlex Bradbury #include "llvm/CodeGen/MachineFrameInfo.h"
178971842fSAlex Bradbury #include "llvm/CodeGen/MachineFunction.h"
188971842fSAlex Bradbury #include "llvm/CodeGen/MachineInstrBuilder.h"
198971842fSAlex Bradbury #include "llvm/CodeGen/MachineRegisterInfo.h"
200715d35eSAlex Bradbury #include "llvm/CodeGen/RegisterScavenging.h"
218971842fSAlex Bradbury 
228971842fSAlex Bradbury using namespace llvm;
238971842fSAlex Bradbury 
247d6aa1f7SAlex Bradbury bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const {
257d6aa1f7SAlex Bradbury   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
267d6aa1f7SAlex Bradbury 
277d6aa1f7SAlex Bradbury   const MachineFrameInfo &MFI = MF.getFrameInfo();
287d6aa1f7SAlex Bradbury   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
297d6aa1f7SAlex Bradbury          RegInfo->needsStackRealignment(MF) || MFI.hasVarSizedObjects() ||
307d6aa1f7SAlex Bradbury          MFI.isFrameAddressTaken();
317d6aa1f7SAlex Bradbury }
328971842fSAlex Bradbury 
33b014e3deSAlex Bradbury // Determines the size of the frame and maximum call frame size.
34b014e3deSAlex Bradbury void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const {
35b014e3deSAlex Bradbury   MachineFrameInfo &MFI = MF.getFrameInfo();
36b014e3deSAlex Bradbury   const RISCVRegisterInfo *RI = STI.getRegisterInfo();
37b014e3deSAlex Bradbury 
38b014e3deSAlex Bradbury   // Get the number of bytes to allocate from the FrameInfo.
39b014e3deSAlex Bradbury   uint64_t FrameSize = MFI.getStackSize();
40b014e3deSAlex Bradbury 
41b014e3deSAlex Bradbury   // Get the alignment.
42b014e3deSAlex Bradbury   uint64_t StackAlign = RI->needsStackRealignment(MF) ? MFI.getMaxAlignment()
43b014e3deSAlex Bradbury                                                       : getStackAlignment();
44b014e3deSAlex Bradbury 
45b014e3deSAlex Bradbury   // Make sure the frame is aligned.
46b014e3deSAlex Bradbury   FrameSize = alignTo(FrameSize, StackAlign);
47b014e3deSAlex Bradbury 
48b014e3deSAlex Bradbury   // Update frame info.
49b014e3deSAlex Bradbury   MFI.setStackSize(FrameSize);
50b014e3deSAlex Bradbury }
51b014e3deSAlex Bradbury 
52b014e3deSAlex Bradbury void RISCVFrameLowering::adjustReg(MachineBasicBlock &MBB,
53b014e3deSAlex Bradbury                                    MachineBasicBlock::iterator MBBI,
54b014e3deSAlex Bradbury                                    const DebugLoc &DL, unsigned DestReg,
55b014e3deSAlex Bradbury                                    unsigned SrcReg, int64_t Val,
56b014e3deSAlex Bradbury                                    MachineInstr::MIFlag Flag) const {
579fea4881SAlex Bradbury   MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
58b014e3deSAlex Bradbury   const RISCVInstrInfo *TII = STI.getInstrInfo();
59b014e3deSAlex Bradbury 
60b014e3deSAlex Bradbury   if (DestReg == SrcReg && Val == 0)
61b014e3deSAlex Bradbury     return;
62b014e3deSAlex Bradbury 
639fea4881SAlex Bradbury   if (isInt<12>(Val)) {
64b014e3deSAlex Bradbury     BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DestReg)
65b014e3deSAlex Bradbury         .addReg(SrcReg)
66b014e3deSAlex Bradbury         .addImm(Val)
67b014e3deSAlex Bradbury         .setMIFlag(Flag);
689fea4881SAlex Bradbury   } else if (isInt<32>(Val)) {
699fea4881SAlex Bradbury     unsigned Opc = RISCV::ADD;
709fea4881SAlex Bradbury     bool isSub = Val < 0;
719fea4881SAlex Bradbury     if (isSub) {
729fea4881SAlex Bradbury       Val = -Val;
739fea4881SAlex Bradbury       Opc = RISCV::SUB;
749fea4881SAlex Bradbury     }
759fea4881SAlex Bradbury 
769fea4881SAlex Bradbury     unsigned ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
779fea4881SAlex Bradbury     TII->movImm32(MBB, MBBI, DL, ScratchReg, Val, Flag);
789fea4881SAlex Bradbury     BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)
799fea4881SAlex Bradbury         .addReg(SrcReg)
809fea4881SAlex Bradbury         .addReg(ScratchReg, RegState::Kill)
819fea4881SAlex Bradbury         .setMIFlag(Flag);
829fea4881SAlex Bradbury   } else {
839fea4881SAlex Bradbury     report_fatal_error("adjustReg cannot yet handle adjustments >32 bits");
849fea4881SAlex Bradbury   }
85b014e3deSAlex Bradbury }
86b014e3deSAlex Bradbury 
87b014e3deSAlex Bradbury // Returns the register used to hold the frame pointer.
88b014e3deSAlex Bradbury static unsigned getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; }
89b014e3deSAlex Bradbury 
90b014e3deSAlex Bradbury // Returns the register used to hold the stack pointer.
91b014e3deSAlex Bradbury static unsigned getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; }
92b014e3deSAlex Bradbury 
938971842fSAlex Bradbury void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
94b014e3deSAlex Bradbury                                       MachineBasicBlock &MBB) const {
95b014e3deSAlex Bradbury   assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
96b014e3deSAlex Bradbury 
97b014e3deSAlex Bradbury   MachineFrameInfo &MFI = MF.getFrameInfo();
98c85be0deSAlex Bradbury   auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
99b014e3deSAlex Bradbury   MachineBasicBlock::iterator MBBI = MBB.begin();
100b014e3deSAlex Bradbury 
101b014e3deSAlex Bradbury   unsigned FPReg = getFPReg(STI);
102b014e3deSAlex Bradbury   unsigned SPReg = getSPReg(STI);
103b014e3deSAlex Bradbury 
104b014e3deSAlex Bradbury   // Debug location must be unknown since the first debug location is used
105b014e3deSAlex Bradbury   // to determine the end of the prologue.
106b014e3deSAlex Bradbury   DebugLoc DL;
107b014e3deSAlex Bradbury 
108b014e3deSAlex Bradbury   // Determine the correct frame layout
109b014e3deSAlex Bradbury   determineFrameLayout(MF);
110b014e3deSAlex Bradbury 
111b014e3deSAlex Bradbury   // FIXME (note copied from Lanai): This appears to be overallocating.  Needs
112b014e3deSAlex Bradbury   // investigation. Get the number of bytes to allocate from the FrameInfo.
113b014e3deSAlex Bradbury   uint64_t StackSize = MFI.getStackSize();
114b014e3deSAlex Bradbury 
115b014e3deSAlex Bradbury   // Early exit if there is no need to allocate on the stack
116b014e3deSAlex Bradbury   if (StackSize == 0 && !MFI.adjustsStack())
117b014e3deSAlex Bradbury     return;
118b014e3deSAlex Bradbury 
119b014e3deSAlex Bradbury   // Allocate space on the stack if necessary.
120b014e3deSAlex Bradbury   adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
121b014e3deSAlex Bradbury 
122b014e3deSAlex Bradbury   // The frame pointer is callee-saved, and code has been generated for us to
123b014e3deSAlex Bradbury   // save it to the stack. We need to skip over the storing of callee-saved
124b014e3deSAlex Bradbury   // registers as the frame pointer must be modified after it has been saved
125b014e3deSAlex Bradbury   // to the stack, not before.
126b014e3deSAlex Bradbury   // FIXME: assumes exactly one instruction is used to save each callee-saved
127b014e3deSAlex Bradbury   // register.
128b014e3deSAlex Bradbury   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
129b014e3deSAlex Bradbury   std::advance(MBBI, CSI.size());
130b014e3deSAlex Bradbury 
131b014e3deSAlex Bradbury   // Generate new FP.
1327d6aa1f7SAlex Bradbury   if (hasFP(MF))
1337d6aa1f7SAlex Bradbury     adjustReg(MBB, MBBI, DL, FPReg, SPReg,
1347d6aa1f7SAlex Bradbury               StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup);
135b014e3deSAlex Bradbury }
1368971842fSAlex Bradbury 
1378971842fSAlex Bradbury void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
138b014e3deSAlex Bradbury                                       MachineBasicBlock &MBB) const {
139b014e3deSAlex Bradbury   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
140b014e3deSAlex Bradbury   const RISCVRegisterInfo *RI = STI.getRegisterInfo();
141b014e3deSAlex Bradbury   MachineFrameInfo &MFI = MF.getFrameInfo();
142c85be0deSAlex Bradbury   auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
143b014e3deSAlex Bradbury   DebugLoc DL = MBBI->getDebugLoc();
144b014e3deSAlex Bradbury   unsigned FPReg = getFPReg(STI);
145b014e3deSAlex Bradbury   unsigned SPReg = getSPReg(STI);
146b014e3deSAlex Bradbury 
147b014e3deSAlex Bradbury   // Skip to before the restores of callee-saved registers
148b014e3deSAlex Bradbury   // FIXME: assumes exactly one instruction is used to restore each
149b014e3deSAlex Bradbury   // callee-saved register.
15061b28edeSAna Pazos   auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size());
151b014e3deSAlex Bradbury 
152b014e3deSAlex Bradbury   uint64_t StackSize = MFI.getStackSize();
153b014e3deSAlex Bradbury 
154b014e3deSAlex Bradbury   // Restore the stack pointer using the value of the frame pointer. Only
155b014e3deSAlex Bradbury   // necessary if the stack pointer was modified, meaning the stack size is
156b014e3deSAlex Bradbury   // unknown.
157b014e3deSAlex Bradbury   if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) {
1587d6aa1f7SAlex Bradbury     assert(hasFP(MF) && "frame pointer should not have been eliminated");
159c85be0deSAlex Bradbury     adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg,
160c85be0deSAlex Bradbury               -StackSize + RVFI->getVarArgsSaveSize(),
161b014e3deSAlex Bradbury               MachineInstr::FrameDestroy);
162b014e3deSAlex Bradbury   }
163b014e3deSAlex Bradbury 
164b014e3deSAlex Bradbury   // Deallocate stack
165b014e3deSAlex Bradbury   adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
166b014e3deSAlex Bradbury }
167660bccecSAlex Bradbury 
168660bccecSAlex Bradbury int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
169660bccecSAlex Bradbury                                                int FI,
170660bccecSAlex Bradbury                                                unsigned &FrameReg) const {
171660bccecSAlex Bradbury   const MachineFrameInfo &MFI = MF.getFrameInfo();
172660bccecSAlex Bradbury   const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
173c85be0deSAlex Bradbury   const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
174660bccecSAlex Bradbury 
175660bccecSAlex Bradbury   // Callee-saved registers should be referenced relative to the stack
176660bccecSAlex Bradbury   // pointer (positive offset), otherwise use the frame pointer (negative
177660bccecSAlex Bradbury   // offset).
178660bccecSAlex Bradbury   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
179660bccecSAlex Bradbury   int MinCSFI = 0;
180660bccecSAlex Bradbury   int MaxCSFI = -1;
181660bccecSAlex Bradbury 
182660bccecSAlex Bradbury   int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
183660bccecSAlex Bradbury                MFI.getOffsetAdjustment();
184660bccecSAlex Bradbury 
185660bccecSAlex Bradbury   if (CSI.size()) {
186660bccecSAlex Bradbury     MinCSFI = CSI[0].getFrameIdx();
187660bccecSAlex Bradbury     MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
188660bccecSAlex Bradbury   }
189660bccecSAlex Bradbury 
190660bccecSAlex Bradbury   if (FI >= MinCSFI && FI <= MaxCSFI) {
191660bccecSAlex Bradbury     FrameReg = RISCV::X2;
192660bccecSAlex Bradbury     Offset += MF.getFrameInfo().getStackSize();
193c85be0deSAlex Bradbury   } else {
194c85be0deSAlex Bradbury     FrameReg = RI->getFrameRegister(MF);
1957d6aa1f7SAlex Bradbury     if (hasFP(MF))
196c85be0deSAlex Bradbury       Offset += RVFI->getVarArgsSaveSize();
1977d6aa1f7SAlex Bradbury     else
1987d6aa1f7SAlex Bradbury       Offset += MF.getFrameInfo().getStackSize();
199660bccecSAlex Bradbury   }
200660bccecSAlex Bradbury   return Offset;
201660bccecSAlex Bradbury }
202b014e3deSAlex Bradbury 
203b014e3deSAlex Bradbury void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
204b014e3deSAlex Bradbury                                               BitVector &SavedRegs,
205b014e3deSAlex Bradbury                                               RegScavenger *RS) const {
206b014e3deSAlex Bradbury   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
2077d6aa1f7SAlex Bradbury   // Unconditionally spill RA and FP only if the function uses a frame
2087d6aa1f7SAlex Bradbury   // pointer.
2097d6aa1f7SAlex Bradbury   if (hasFP(MF)) {
210b014e3deSAlex Bradbury     SavedRegs.set(RISCV::X1);
211b014e3deSAlex Bradbury     SavedRegs.set(RISCV::X8);
212b014e3deSAlex Bradbury   }
2132e4106b7SAna Pazos 
2142e4106b7SAna Pazos   // If interrupt is enabled and there are calls in the handler,
2152e4106b7SAna Pazos   // unconditionally save all Caller-saved registers and
2162e4106b7SAna Pazos   // all FP registers, regardless whether they are used.
2172e4106b7SAna Pazos   MachineFrameInfo &MFI = MF.getFrameInfo();
2182e4106b7SAna Pazos 
2192e4106b7SAna Pazos   if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) {
2202e4106b7SAna Pazos 
2212e4106b7SAna Pazos     static const MCPhysReg CSRegs[] = { RISCV::X1,      /* ra */
2222e4106b7SAna Pazos       RISCV::X5, RISCV::X6, RISCV::X7,                  /* t0-t2 */
2232e4106b7SAna Pazos       RISCV::X10, RISCV::X11,                           /* a0-a1, a2-a7 */
2242e4106b7SAna Pazos       RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17,
2252e4106b7SAna Pazos       RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31, 0 /* t3-t6 */
2262e4106b7SAna Pazos     };
2272e4106b7SAna Pazos 
2282e4106b7SAna Pazos     for (unsigned i = 0; CSRegs[i]; ++i)
2292e4106b7SAna Pazos       SavedRegs.set(CSRegs[i]);
2302e4106b7SAna Pazos 
2312e4106b7SAna Pazos     if (MF.getSubtarget<RISCVSubtarget>().hasStdExtD() ||
2322e4106b7SAna Pazos         MF.getSubtarget<RISCVSubtarget>().hasStdExtF()) {
2332e4106b7SAna Pazos 
2342e4106b7SAna Pazos       // If interrupt is enabled, this list contains all FP registers.
2352e4106b7SAna Pazos       const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs();
2362e4106b7SAna Pazos 
2372e4106b7SAna Pazos       for (unsigned i = 0; Regs[i]; ++i)
2382e4106b7SAna Pazos         if (RISCV::FPR32RegClass.contains(Regs[i]) ||
2392e4106b7SAna Pazos             RISCV::FPR64RegClass.contains(Regs[i]))
2402e4106b7SAna Pazos           SavedRegs.set(Regs[i]);
2412e4106b7SAna Pazos     }
2422e4106b7SAna Pazos   }
2437d6aa1f7SAlex Bradbury }
2440715d35eSAlex Bradbury 
2450715d35eSAlex Bradbury void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
2460715d35eSAlex Bradbury     MachineFunction &MF, RegScavenger *RS) const {
2470715d35eSAlex Bradbury   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
2480715d35eSAlex Bradbury   MachineFrameInfo &MFI = MF.getFrameInfo();
2490715d35eSAlex Bradbury   const TargetRegisterClass *RC = &RISCV::GPRRegClass;
2500715d35eSAlex Bradbury   // estimateStackSize has been observed to under-estimate the final stack
2510715d35eSAlex Bradbury   // size, so give ourselves wiggle-room by checking for stack size
2520715d35eSAlex Bradbury   // representable an 11-bit signed field rather than 12-bits.
2530715d35eSAlex Bradbury   // FIXME: It may be possible to craft a function with a small stack that
2540715d35eSAlex Bradbury   // still needs an emergency spill slot for branch relaxation. This case
2550715d35eSAlex Bradbury   // would currently be missed.
2560715d35eSAlex Bradbury   if (!isInt<11>(MFI.estimateStackSize(MF))) {
2570715d35eSAlex Bradbury     int RegScavFI = MFI.CreateStackObject(
2580715d35eSAlex Bradbury         RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false);
2590715d35eSAlex Bradbury     RS->addScavengingFrameIndex(RegScavFI);
2600715d35eSAlex Bradbury   }
2610715d35eSAlex Bradbury }
262cbd498acSShiva Chen 
263cbd498acSShiva Chen // Not preserve stack space within prologue for outgoing variables when the
264cbd498acSShiva Chen // function contains variable size objects and let eliminateCallFramePseudoInstr
265cbd498acSShiva Chen // preserve stack space for it.
266cbd498acSShiva Chen bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
267cbd498acSShiva Chen   return !MF.getFrameInfo().hasVarSizedObjects();
268cbd498acSShiva Chen }
269cbd498acSShiva Chen 
270cbd498acSShiva Chen // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.
271cbd498acSShiva Chen MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr(
272cbd498acSShiva Chen     MachineFunction &MF, MachineBasicBlock &MBB,
273cbd498acSShiva Chen     MachineBasicBlock::iterator MI) const {
274cbd498acSShiva Chen   unsigned SPReg = RISCV::X2;
275cbd498acSShiva Chen   DebugLoc DL = MI->getDebugLoc();
276cbd498acSShiva Chen 
277cbd498acSShiva Chen   if (!hasReservedCallFrame(MF)) {
278cbd498acSShiva Chen     // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and
279cbd498acSShiva Chen     // ADJCALLSTACKUP must be converted to instructions manipulating the stack
280cbd498acSShiva Chen     // pointer. This is necessary when there is a variable length stack
281cbd498acSShiva Chen     // allocation (e.g. alloca), which means it's not possible to allocate
282cbd498acSShiva Chen     // space for outgoing arguments from within the function prologue.
283cbd498acSShiva Chen     int64_t Amount = MI->getOperand(0).getImm();
284cbd498acSShiva Chen 
285cbd498acSShiva Chen     if (Amount != 0) {
286cbd498acSShiva Chen       // Ensure the stack remains aligned after adjustment.
287cbd498acSShiva Chen       Amount = alignSPAdjust(Amount);
288cbd498acSShiva Chen 
289cbd498acSShiva Chen       if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN)
290cbd498acSShiva Chen         Amount = -Amount;
291cbd498acSShiva Chen 
292cbd498acSShiva Chen       adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
293cbd498acSShiva Chen     }
294cbd498acSShiva Chen   }
295cbd498acSShiva Chen 
296cbd498acSShiva Chen   return MBB.erase(MI);
297cbd498acSShiva Chen }
298