xref: /llvm-project/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (revision 1a935d7a17519e9b75d12c3caf9a54a3405a0af3)
133388ae8SLu Weining //===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==//
233388ae8SLu Weining //
333388ae8SLu Weining // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
433388ae8SLu Weining // See https://llvm.org/LICENSE.txt for license information.
533388ae8SLu Weining // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633388ae8SLu Weining //
733388ae8SLu Weining //===----------------------------------------------------------------------===//
833388ae8SLu Weining //
933388ae8SLu Weining // This file contains the LoongArch implementation of TargetFrameLowering class.
1033388ae8SLu Weining //
1133388ae8SLu Weining //===----------------------------------------------------------------------===//
1233388ae8SLu Weining 
1333388ae8SLu Weining #include "LoongArchFrameLowering.h"
14c2d1d9f9Swanglei #include "LoongArchMachineFunctionInfo.h"
1533388ae8SLu Weining #include "LoongArchSubtarget.h"
16c2d1d9f9Swanglei #include "MCTargetDesc/LoongArchBaseInfo.h"
170e4378c5Swanglei #include "MCTargetDesc/LoongArchMCTargetDesc.h"
1833388ae8SLu Weining #include "llvm/CodeGen/MachineFrameInfo.h"
1933388ae8SLu Weining #include "llvm/CodeGen/MachineFunction.h"
2033388ae8SLu Weining #include "llvm/CodeGen/MachineInstrBuilder.h"
2133388ae8SLu Weining #include "llvm/CodeGen/MachineRegisterInfo.h"
2233388ae8SLu Weining #include "llvm/CodeGen/RegisterScavenging.h"
2333388ae8SLu Weining #include "llvm/IR/DiagnosticInfo.h"
2433388ae8SLu Weining #include "llvm/MC/MCDwarf.h"
2533388ae8SLu Weining 
2633388ae8SLu Weining using namespace llvm;
2733388ae8SLu Weining 
2833388ae8SLu Weining #define DEBUG_TYPE "loongarch-frame-lowering"
2933388ae8SLu Weining 
3033388ae8SLu Weining // Return true if the specified function should have a dedicated frame
3133388ae8SLu Weining // pointer register.  This is true if frame pointer elimination is
3233388ae8SLu Weining // disabled, if it needs dynamic stack realignment, if the function has
3333388ae8SLu Weining // variable sized allocas, or if the frame address is taken.
34ad4a582fSAlex Rønne Petersen bool LoongArchFrameLowering::hasFPImpl(const MachineFunction &MF) const {
3533388ae8SLu Weining   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
3633388ae8SLu Weining 
3733388ae8SLu Weining   const MachineFrameInfo &MFI = MF.getFrameInfo();
3833388ae8SLu Weining   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
3933388ae8SLu Weining          RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
4033388ae8SLu Weining          MFI.isFrameAddressTaken();
4133388ae8SLu Weining }
4233388ae8SLu Weining 
4333388ae8SLu Weining bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {
4433388ae8SLu Weining   const MachineFrameInfo &MFI = MF.getFrameInfo();
4533388ae8SLu Weining   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
4633388ae8SLu Weining 
4733388ae8SLu Weining   return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);
4833388ae8SLu Weining }
4933388ae8SLu Weining 
50c2d1d9f9Swanglei void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,
51c2d1d9f9Swanglei                                        MachineBasicBlock::iterator MBBI,
52c2d1d9f9Swanglei                                        const DebugLoc &DL, Register DestReg,
53c2d1d9f9Swanglei                                        Register SrcReg, int64_t Val,
54c2d1d9f9Swanglei                                        MachineInstr::MIFlag Flag) const {
55c2d1d9f9Swanglei   const LoongArchInstrInfo *TII = STI.getInstrInfo();
56c2d1d9f9Swanglei   bool IsLA64 = STI.is64Bit();
57c2a44b59SWANG Xuerui   unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
58c2d1d9f9Swanglei 
59c2d1d9f9Swanglei   if (DestReg == SrcReg && Val == 0)
60c2d1d9f9Swanglei     return;
61c2d1d9f9Swanglei 
62c2d1d9f9Swanglei   if (isInt<12>(Val)) {
63c2d1d9f9Swanglei     // addi.w/d $DstReg, $SrcReg, Val
64c2a44b59SWANG Xuerui     BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
65c2d1d9f9Swanglei         .addReg(SrcReg)
66c2d1d9f9Swanglei         .addImm(Val)
67c2d1d9f9Swanglei         .setMIFlag(Flag);
68c2d1d9f9Swanglei     return;
69c2d1d9f9Swanglei   }
70c2d1d9f9Swanglei 
71c2a44b59SWANG Xuerui   // Try to split the offset across two ADDIs. We need to keep the stack pointer
72c2a44b59SWANG Xuerui   // aligned after each ADDI. We need to determine the maximum value we can put
73c2a44b59SWANG Xuerui   // in each ADDI. In the negative direction, we can use -2048 which is always
74c2a44b59SWANG Xuerui   // sufficiently aligned. In the positive direction, we need to find the
75c2a44b59SWANG Xuerui   // largest 12-bit immediate that is aligned. Exclude -4096 since it can be
76c2a44b59SWANG Xuerui   // created with LU12I.W.
77c2a44b59SWANG Xuerui   assert(getStackAlign().value() < 2048 && "Stack alignment too large");
78c2a44b59SWANG Xuerui   int64_t MaxPosAdjStep = 2048 - getStackAlign().value();
79c2a44b59SWANG Xuerui   if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) {
80c2a44b59SWANG Xuerui     int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep;
81c2a44b59SWANG Xuerui     Val -= FirstAdj;
82c2a44b59SWANG Xuerui     BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
83c2a44b59SWANG Xuerui         .addReg(SrcReg)
84c2a44b59SWANG Xuerui         .addImm(FirstAdj)
85c2a44b59SWANG Xuerui         .setMIFlag(Flag);
86c2a44b59SWANG Xuerui     BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
87c2a44b59SWANG Xuerui         .addReg(DestReg, RegState::Kill)
88c2a44b59SWANG Xuerui         .addImm(Val)
89c2a44b59SWANG Xuerui         .setMIFlag(Flag);
90c2a44b59SWANG Xuerui     return;
91c2a44b59SWANG Xuerui   }
92c2a44b59SWANG Xuerui 
93c2a44b59SWANG Xuerui   unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
94c2a44b59SWANG Xuerui   if (Val < 0) {
95c2a44b59SWANG Xuerui     Val = -Val;
96c2a44b59SWANG Xuerui     Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W;
97c2a44b59SWANG Xuerui   }
98c2a44b59SWANG Xuerui 
99c2a44b59SWANG Xuerui   MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
100c2a44b59SWANG Xuerui   Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
101c2a44b59SWANG Xuerui   TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag);
102c2a44b59SWANG Xuerui   BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)
103c2a44b59SWANG Xuerui       .addReg(SrcReg)
104c2a44b59SWANG Xuerui       .addReg(ScratchReg, RegState::Kill)
105c2a44b59SWANG Xuerui       .setMIFlag(Flag);
106c2d1d9f9Swanglei }
107c2d1d9f9Swanglei 
108c2d1d9f9Swanglei // Determine the size of the frame and maximum call frame size.
109c2d1d9f9Swanglei void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {
110c2d1d9f9Swanglei   MachineFrameInfo &MFI = MF.getFrameInfo();
111c2d1d9f9Swanglei 
112c2d1d9f9Swanglei   // Get the number of bytes to allocate from the FrameInfo.
113c2d1d9f9Swanglei   uint64_t FrameSize = MFI.getStackSize();
114c2d1d9f9Swanglei 
115c2d1d9f9Swanglei   // Make sure the frame is aligned.
116c2d1d9f9Swanglei   FrameSize = alignTo(FrameSize, getStackAlign());
117c2d1d9f9Swanglei 
118c2d1d9f9Swanglei   // Update frame info.
119c2d1d9f9Swanglei   MFI.setStackSize(FrameSize);
120c2d1d9f9Swanglei }
121c2d1d9f9Swanglei 
12203d07e18SXiaodong Liu static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII,
12303d07e18SXiaodong Liu                                             const MachineFunction &MF) {
12403d07e18SXiaodong Liu   uint64_t FuncSize = 0;
12503d07e18SXiaodong Liu   for (auto &MBB : MF)
12603d07e18SXiaodong Liu     for (auto &MI : MBB)
12703d07e18SXiaodong Liu       FuncSize += TII->getInstSizeInBytes(MI);
12803d07e18SXiaodong Liu   return FuncSize;
12903d07e18SXiaodong Liu }
13003d07e18SXiaodong Liu 
1310e4378c5Swanglei static bool needScavSlotForCFR(MachineFunction &MF) {
1320e4378c5Swanglei   if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF())
1330e4378c5Swanglei     return false;
1340e4378c5Swanglei   for (auto &MBB : MF)
1350e4378c5Swanglei     for (auto &MI : MBB)
1360e4378c5Swanglei       if (MI.getOpcode() == LoongArch::PseudoST_CFR)
1370e4378c5Swanglei         return true;
1380e4378c5Swanglei   return false;
1390e4378c5Swanglei }
1400e4378c5Swanglei 
1414e2364a2Swanglei void LoongArchFrameLowering::processFunctionBeforeFrameFinalized(
1424e2364a2Swanglei     MachineFunction &MF, RegScavenger *RS) const {
1434e2364a2Swanglei   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
1444e2364a2Swanglei   const TargetRegisterClass &RC = LoongArch::GPRRegClass;
14503d07e18SXiaodong Liu   const LoongArchInstrInfo *TII = STI.getInstrInfo();
14603d07e18SXiaodong Liu   LoongArchMachineFunctionInfo *LAFI =
14703d07e18SXiaodong Liu       MF.getInfo<LoongArchMachineFunctionInfo>();
1484e2364a2Swanglei   MachineFrameInfo &MFI = MF.getFrameInfo();
1494e2364a2Swanglei 
1500e4378c5Swanglei   unsigned ScavSlotsNum = 0;
1510e4378c5Swanglei 
1528d28e586SWANG Rui   // Far branches beyond 27-bit offset require a spill slot for scratch
1538d28e586SWANG Rui   // register.
1540e4378c5Swanglei   bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF));
1550e4378c5Swanglei   if (IsLargeFunction)
1560e4378c5Swanglei     ScavSlotsNum = 1;
1570e4378c5Swanglei 
1584e2364a2Swanglei   // estimateStackSize has been observed to under-estimate the final stack
1594e2364a2Swanglei   // size, so give ourselves wiggle-room by checking for stack size
1604e2364a2Swanglei   // representable an 11-bit signed field rather than 12-bits.
1610e4378c5Swanglei   if (!isInt<11>(MFI.estimateStackSize(MF)))
1620e4378c5Swanglei     ScavSlotsNum = std::max(ScavSlotsNum, 1u);
1634e2364a2Swanglei 
1640e4378c5Swanglei   // For CFR spill.
1650e4378c5Swanglei   if (needScavSlotForCFR(MF))
1660e4378c5Swanglei     ++ScavSlotsNum;
1670e4378c5Swanglei 
1680e4378c5Swanglei   // Create emergency spill slots.
1690e4378c5Swanglei   for (unsigned i = 0; i < ScavSlotsNum; ++i) {
170*1a935d7aSGuy David     int FI =
171*1a935d7aSGuy David         MFI.CreateSpillStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC));
1724e2364a2Swanglei     RS->addScavengingFrameIndex(FI);
1730e4378c5Swanglei     if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1)
1740e4378c5Swanglei       LAFI->setBranchRelaxationSpillFrameIndex(FI);
1754e2364a2Swanglei     LLVM_DEBUG(dbgs() << "Allocated FI(" << FI
1764e2364a2Swanglei                       << ") as the emergency spill slot.\n");
1774e2364a2Swanglei   }
1780e4378c5Swanglei }
1794e2364a2Swanglei 
18033388ae8SLu Weining void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
18133388ae8SLu Weining                                           MachineBasicBlock &MBB) const {
182c2d1d9f9Swanglei   MachineFrameInfo &MFI = MF.getFrameInfo();
1830c2b738fSwanglei   auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
184c2d1d9f9Swanglei   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
185c2d1d9f9Swanglei   const LoongArchInstrInfo *TII = STI.getInstrInfo();
186c2d1d9f9Swanglei   MachineBasicBlock::iterator MBBI = MBB.begin();
1874e2364a2Swanglei   bool IsLA64 = STI.is64Bit();
188c2d1d9f9Swanglei 
189c2d1d9f9Swanglei   Register SPReg = LoongArch::R3;
190c2d1d9f9Swanglei   Register FPReg = LoongArch::R22;
191c2d1d9f9Swanglei 
192c2d1d9f9Swanglei   // Debug location must be unknown since the first debug location is used
193c2d1d9f9Swanglei   // to determine the end of the prologue.
194c2d1d9f9Swanglei   DebugLoc DL;
195389079c8SLin Runze   // All calls are tail calls in GHC calling conv, and functions have no
196389079c8SLin Runze   // prologue/epilogue.
197389079c8SLin Runze   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
198389079c8SLin Runze     return;
199c2d1d9f9Swanglei   // Determine the correct frame layout
200c2d1d9f9Swanglei   determineFrameLayout(MF);
201c2d1d9f9Swanglei 
202c2d1d9f9Swanglei   // First, compute final stack size.
203c2d1d9f9Swanglei   uint64_t StackSize = MFI.getStackSize();
204f589e506Swanglei   uint64_t RealStackSize = StackSize;
205c2d1d9f9Swanglei 
206c2d1d9f9Swanglei   // Early exit if there is no need to allocate space in the stack.
207c2d1d9f9Swanglei   if (StackSize == 0 && !MFI.adjustsStack())
208c2d1d9f9Swanglei     return;
209c2d1d9f9Swanglei 
2100d17e1f0Shev   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
211f589e506Swanglei   // Split the SP adjustment to reduce the offsets of callee saved spill.
212f589e506Swanglei   if (FirstSPAdjustAmount)
213f589e506Swanglei     StackSize = FirstSPAdjustAmount;
214f589e506Swanglei 
215c2d1d9f9Swanglei   // Adjust stack.
216c2d1d9f9Swanglei   adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
217c2d1d9f9Swanglei   // Emit ".cfi_def_cfa_offset StackSize".
218c2d1d9f9Swanglei   unsigned CFIIndex =
219c2d1d9f9Swanglei       MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
220c2d1d9f9Swanglei   BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
221c2d1d9f9Swanglei       .addCFIIndex(CFIIndex)
222c2d1d9f9Swanglei       .setMIFlag(MachineInstr::FrameSetup);
223c2d1d9f9Swanglei 
224c2d1d9f9Swanglei   const auto &CSI = MFI.getCalleeSavedInfo();
225c2d1d9f9Swanglei 
226c2d1d9f9Swanglei   // The frame pointer is callee-saved, and code has been generated for us to
227c2d1d9f9Swanglei   // save it to the stack. We need to skip over the storing of callee-saved
228c2d1d9f9Swanglei   // registers as the frame pointer must be modified after it has been saved
229c2d1d9f9Swanglei   // to the stack, not before.
230c2d1d9f9Swanglei   std::advance(MBBI, CSI.size());
231c2d1d9f9Swanglei 
232c2d1d9f9Swanglei   // Iterate over list of callee-saved registers and emit .cfi_offset
233c2d1d9f9Swanglei   // directives.
234c2d1d9f9Swanglei   for (const auto &Entry : CSI) {
235c2d1d9f9Swanglei     int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
236c2d1d9f9Swanglei     unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
237c2d1d9f9Swanglei         nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));
238c2d1d9f9Swanglei     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
239c2d1d9f9Swanglei         .addCFIIndex(CFIIndex)
240c2d1d9f9Swanglei         .setMIFlag(MachineInstr::FrameSetup);
241c2d1d9f9Swanglei   }
242c2d1d9f9Swanglei 
243c2d1d9f9Swanglei   // Generate new FP.
244c2d1d9f9Swanglei   if (hasFP(MF)) {
2450c2b738fSwanglei     adjustReg(MBB, MBBI, DL, FPReg, SPReg,
2460c2b738fSwanglei               StackSize - LoongArchFI->getVarArgsSaveSize(),
2470c2b738fSwanglei               MachineInstr::FrameSetup);
248c2d1d9f9Swanglei 
2490c2b738fSwanglei     // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()"
2500c2b738fSwanglei     unsigned CFIIndex = MF.addFrameInst(
2510c2b738fSwanglei         MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true),
2520c2b738fSwanglei                                     LoongArchFI->getVarArgsSaveSize()));
253c2d1d9f9Swanglei     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
254c2d1d9f9Swanglei         .addCFIIndex(CFIIndex)
255c2d1d9f9Swanglei         .setMIFlag(MachineInstr::FrameSetup);
256f589e506Swanglei   }
257daf067daSwanglei 
258f589e506Swanglei   // Emit the second SP adjustment after saving callee saved registers.
2590d17e1f0Shev   if (FirstSPAdjustAmount) {
2600d17e1f0Shev     uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;
261f589e506Swanglei     assert(SecondSPAdjustAmount > 0 &&
262f589e506Swanglei            "SecondSPAdjustAmount should be greater than zero");
263f589e506Swanglei     adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,
264f589e506Swanglei               MachineInstr::FrameSetup);
265f589e506Swanglei 
2660d17e1f0Shev     if (!hasFP(MF)) {
267f589e506Swanglei       // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",
268f589e506Swanglei       // don't emit an sp-based .cfi_def_cfa_offset
269f589e506Swanglei       // Emit ".cfi_def_cfa_offset RealStackSize"
270f589e506Swanglei       unsigned CFIIndex = MF.addFrameInst(
271f589e506Swanglei           MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
272f589e506Swanglei       BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
273f589e506Swanglei           .addCFIIndex(CFIIndex)
274f589e506Swanglei           .setMIFlag(MachineInstr::FrameSetup);
275f589e506Swanglei     }
276f589e506Swanglei   }
277f589e506Swanglei 
278f589e506Swanglei   if (hasFP(MF)) {
279daf067daSwanglei     // Realign stack.
280daf067daSwanglei     if (RI->hasStackRealignment(MF)) {
2811bb77664Swanglei       unsigned Align = Log2(MFI.getMaxAlign());
2821bb77664Swanglei       assert(Align > 0 && "The stack realignment size is invalid!");
283daf067daSwanglei       BuildMI(MBB, MBBI, DL,
2841bb77664Swanglei               TII->get(IsLA64 ? LoongArch::BSTRINS_D : LoongArch::BSTRINS_W),
2851bb77664Swanglei               SPReg)
286daf067daSwanglei           .addReg(SPReg)
2871bb77664Swanglei           .addReg(LoongArch::R0)
2881bb77664Swanglei           .addImm(Align - 1)
2891bb77664Swanglei           .addImm(0)
290daf067daSwanglei           .setMIFlag(MachineInstr::FrameSetup);
291daf067daSwanglei       // FP will be used to restore the frame in the epilogue, so we need
292daf067daSwanglei       // another base register BP to record SP after re-alignment. SP will
293daf067daSwanglei       // track the current stack after allocating variable sized objects.
294daf067daSwanglei       if (hasBP(MF)) {
295daf067daSwanglei         // move BP, $sp
296daf067daSwanglei         BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR),
297daf067daSwanglei                 LoongArchABI::getBPReg())
298daf067daSwanglei             .addReg(SPReg)
299daf067daSwanglei             .addReg(LoongArch::R0)
300daf067daSwanglei             .setMIFlag(MachineInstr::FrameSetup);
301daf067daSwanglei       }
302daf067daSwanglei     }
303c2d1d9f9Swanglei   }
30433388ae8SLu Weining }
30533388ae8SLu Weining 
30633388ae8SLu Weining void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
30733388ae8SLu Weining                                           MachineBasicBlock &MBB) const {
308c2d1d9f9Swanglei   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
309c2d1d9f9Swanglei   MachineFrameInfo &MFI = MF.getFrameInfo();
3100c2b738fSwanglei   auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
311c2d1d9f9Swanglei   Register SPReg = LoongArch::R3;
312389079c8SLin Runze   // All calls are tail calls in GHC calling conv, and functions have no
313389079c8SLin Runze   // prologue/epilogue.
314389079c8SLin Runze   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
315389079c8SLin Runze     return;
316c2d1d9f9Swanglei   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
317c2d1d9f9Swanglei   DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
318c2d1d9f9Swanglei 
319c2d1d9f9Swanglei   const auto &CSI = MFI.getCalleeSavedInfo();
320c2d1d9f9Swanglei   // Skip to before the restores of callee-saved registers.
321c2d1d9f9Swanglei   auto LastFrameDestroy = MBBI;
322c2d1d9f9Swanglei   if (!CSI.empty())
323c2d1d9f9Swanglei     LastFrameDestroy = std::prev(MBBI, CSI.size());
324c2d1d9f9Swanglei 
325c2d1d9f9Swanglei   // Get the number of bytes from FrameInfo.
326c2d1d9f9Swanglei   uint64_t StackSize = MFI.getStackSize();
327c2d1d9f9Swanglei 
328c2d1d9f9Swanglei   // Restore the stack pointer.
329c2d1d9f9Swanglei   if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
330c2d1d9f9Swanglei     assert(hasFP(MF) && "frame pointer should not have been eliminated");
3310c2b738fSwanglei     adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22,
3320c2b738fSwanglei               -StackSize + LoongArchFI->getVarArgsSaveSize(),
333c2d1d9f9Swanglei               MachineInstr::FrameDestroy);
334c2d1d9f9Swanglei   }
335c2d1d9f9Swanglei 
336f589e506Swanglei   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
337f589e506Swanglei   if (FirstSPAdjustAmount) {
338f589e506Swanglei     uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount;
339f589e506Swanglei     assert(SecondSPAdjustAmount > 0 &&
340f589e506Swanglei            "SecondSPAdjustAmount should be greater than zero");
341f589e506Swanglei 
342f589e506Swanglei     adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount,
343f589e506Swanglei               MachineInstr::FrameDestroy);
344f589e506Swanglei     StackSize = FirstSPAdjustAmount;
345f589e506Swanglei   }
346f589e506Swanglei 
347c2d1d9f9Swanglei   // Deallocate stack
348c2d1d9f9Swanglei   adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
349c2d1d9f9Swanglei }
350c2d1d9f9Swanglei 
351f589e506Swanglei // We would like to split the SP adjustment to reduce prologue/epilogue
352f589e506Swanglei // as following instructions. In this way, the offset of the callee saved
353f589e506Swanglei // register could fit in a single store.
354f589e506Swanglei // e.g.
355f589e506Swanglei //   addi.d  $sp, $sp, -2032
356f589e506Swanglei //   st.d    $ra, $sp,  2024
357f589e506Swanglei //   st.d    $fp, $sp,  2016
358f589e506Swanglei //   addi.d  $sp, $sp,   -16
3590d17e1f0Shev uint64_t LoongArchFrameLowering::getFirstSPAdjustAmount(
3600d17e1f0Shev     const MachineFunction &MF) const {
361f589e506Swanglei   const MachineFrameInfo &MFI = MF.getFrameInfo();
362f589e506Swanglei   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
363f589e506Swanglei 
364f589e506Swanglei   // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed
365f589e506Swanglei   // 12-bit and there exists a callee-saved register needing to be pushed.
3660d17e1f0Shev   if (!isInt<12>(MFI.getStackSize()) && (CSI.size() > 0)) {
367f589e506Swanglei     // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will
368f589e506Swanglei     // cause sp = sp + 2048 in the epilogue to be split into multiple
369f589e506Swanglei     // instructions. Offsets smaller than 2048 can fit in a single load/store
370f589e506Swanglei     // instruction, and we have to stick with the stack alignment.
371f589e506Swanglei     // So (2048 - StackAlign) will satisfy the stack alignment.
3720d17e1f0Shev     return 2048 - getStackAlign().value();
373f589e506Swanglei   }
374f589e506Swanglei   return 0;
375f589e506Swanglei }
376f589e506Swanglei 
377c2d1d9f9Swanglei void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
378c2d1d9f9Swanglei                                                   BitVector &SavedRegs,
379c2d1d9f9Swanglei                                                   RegScavenger *RS) const {
380c2d1d9f9Swanglei   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
381c2d1d9f9Swanglei   // Unconditionally spill RA and FP only if the function uses a frame
382c2d1d9f9Swanglei   // pointer.
383c2d1d9f9Swanglei   if (hasFP(MF)) {
384c2d1d9f9Swanglei     SavedRegs.set(LoongArch::R1);
385c2d1d9f9Swanglei     SavedRegs.set(LoongArch::R22);
386c2d1d9f9Swanglei   }
387c2d1d9f9Swanglei   // Mark BP as used if function has dedicated base pointer.
388c2d1d9f9Swanglei   if (hasBP(MF))
389c2d1d9f9Swanglei     SavedRegs.set(LoongArchABI::getBPReg());
39033388ae8SLu Weining }
3915b1ec705Swanglei 
3920c2b738fSwanglei // Do not preserve stack space within prologue for outgoing variables if the
3930c2b738fSwanglei // function contains variable size objects.
3940c2b738fSwanglei // Let eliminateCallFramePseudoInstr preserve stack space for it.
3950c2b738fSwanglei bool LoongArchFrameLowering::hasReservedCallFrame(
3960c2b738fSwanglei     const MachineFunction &MF) const {
3970c2b738fSwanglei   return !MF.getFrameInfo().hasVarSizedObjects();
3980c2b738fSwanglei }
3990c2b738fSwanglei 
4000c2b738fSwanglei // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.
4010c2b738fSwanglei MachineBasicBlock::iterator
4020c2b738fSwanglei LoongArchFrameLowering::eliminateCallFramePseudoInstr(
4030c2b738fSwanglei     MachineFunction &MF, MachineBasicBlock &MBB,
4040c2b738fSwanglei     MachineBasicBlock::iterator MI) const {
4050c2b738fSwanglei   Register SPReg = LoongArch::R3;
4060c2b738fSwanglei   DebugLoc DL = MI->getDebugLoc();
4070c2b738fSwanglei 
4080c2b738fSwanglei   if (!hasReservedCallFrame(MF)) {
4090c2b738fSwanglei     // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and
4100c2b738fSwanglei     // ADJCALLSTACKUP must be converted to instructions manipulating the stack
4110c2b738fSwanglei     // pointer. This is necessary when there is a variable length stack
4120c2b738fSwanglei     // allocation (e.g. alloca), which means it's not possible to allocate
4130c2b738fSwanglei     // space for outgoing arguments from within the function prologue.
4140c2b738fSwanglei     int64_t Amount = MI->getOperand(0).getImm();
4150c2b738fSwanglei 
4160c2b738fSwanglei     if (Amount != 0) {
4170c2b738fSwanglei       // Ensure the stack remains aligned after adjustment.
4180c2b738fSwanglei       Amount = alignSPAdjust(Amount);
4190c2b738fSwanglei 
4200c2b738fSwanglei       if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN)
4210c2b738fSwanglei         Amount = -Amount;
4220c2b738fSwanglei 
4230c2b738fSwanglei       adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
4240c2b738fSwanglei     }
4250c2b738fSwanglei   }
4260c2b738fSwanglei 
4270c2b738fSwanglei   return MBB.erase(MI);
4280c2b738fSwanglei }
4290c2b738fSwanglei 
430d20c54cbSwanglei bool LoongArchFrameLowering::spillCalleeSavedRegisters(
431d20c54cbSwanglei     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
432d20c54cbSwanglei     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
433d20c54cbSwanglei   if (CSI.empty())
434d20c54cbSwanglei     return true;
435d20c54cbSwanglei 
436d20c54cbSwanglei   MachineFunction *MF = MBB.getParent();
437d20c54cbSwanglei   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
438d20c54cbSwanglei 
439d20c54cbSwanglei   // Insert the spill to the stack frame.
440d20c54cbSwanglei   for (auto &CS : CSI) {
441d20c54cbSwanglei     Register Reg = CS.getReg();
442d20c54cbSwanglei     // If the register is RA and the return address is taken by method
443d20c54cbSwanglei     // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag.
444d20c54cbSwanglei     bool IsKill =
445d20c54cbSwanglei         !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken());
446d20c54cbSwanglei     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
447b5efec4bSChristudasan Devadasan     TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI,
448b5efec4bSChristudasan Devadasan                             Register());
449d20c54cbSwanglei   }
450d20c54cbSwanglei 
451d20c54cbSwanglei   return true;
452d20c54cbSwanglei }
453d20c54cbSwanglei 
4545b1ec705Swanglei StackOffset LoongArchFrameLowering::getFrameIndexReference(
4555b1ec705Swanglei     const MachineFunction &MF, int FI, Register &FrameReg) const {
4565b1ec705Swanglei   const MachineFrameInfo &MFI = MF.getFrameInfo();
4575b1ec705Swanglei   const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
4580c2b738fSwanglei   auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
459daf067daSwanglei   uint64_t StackSize = MFI.getStackSize();
460f589e506Swanglei   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
4615b1ec705Swanglei 
4625b1ec705Swanglei   // Callee-saved registers should be referenced relative to the stack
4635b1ec705Swanglei   // pointer (positive offset), otherwise use the frame pointer (negative
4645b1ec705Swanglei   // offset).
4655b1ec705Swanglei   const auto &CSI = MFI.getCalleeSavedInfo();
4665b1ec705Swanglei   int MinCSFI = 0;
4675b1ec705Swanglei   int MaxCSFI = -1;
4685b1ec705Swanglei   StackOffset Offset =
4695b1ec705Swanglei       StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
4705b1ec705Swanglei                             MFI.getOffsetAdjustment());
4715b1ec705Swanglei 
4725b1ec705Swanglei   if (CSI.size()) {
4735b1ec705Swanglei     MinCSFI = CSI[0].getFrameIdx();
4745b1ec705Swanglei     MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
4755b1ec705Swanglei   }
4765b1ec705Swanglei 
477daf067daSwanglei   if (FI >= MinCSFI && FI <= MaxCSFI) {
4785b1ec705Swanglei     FrameReg = LoongArch::R3;
479f589e506Swanglei     if (FirstSPAdjustAmount)
480f589e506Swanglei       Offset += StackOffset::getFixed(FirstSPAdjustAmount);
481f589e506Swanglei     else
482daf067daSwanglei       Offset += StackOffset::getFixed(StackSize);
483daf067daSwanglei   } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {
484daf067daSwanglei     // If the stack was realigned, the frame pointer is set in order to allow
485daf067daSwanglei     // SP to be restored, so we need another base register to record the stack
486daf067daSwanglei     // after realignment.
487daf067daSwanglei     FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3;
488daf067daSwanglei     Offset += StackOffset::getFixed(StackSize);
4890c2b738fSwanglei   } else {
4900c2b738fSwanglei     FrameReg = RI->getFrameRegister(MF);
491daf067daSwanglei     if (hasFP(MF))
4920c2b738fSwanglei       Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize());
493daf067daSwanglei     else
494daf067daSwanglei       Offset += StackOffset::getFixed(StackSize);
4955b1ec705Swanglei   }
4965b1ec705Swanglei 
4975b1ec705Swanglei   return Offset;
4985b1ec705Swanglei }
49925ecfbf8Swanglei 
50025ecfbf8Swanglei bool LoongArchFrameLowering::enableShrinkWrapping(
50125ecfbf8Swanglei     const MachineFunction &MF) const {
50225ecfbf8Swanglei   // Keep the conventional code flow when not optimizing.
50325ecfbf8Swanglei   if (MF.getFunction().hasOptNone())
50425ecfbf8Swanglei     return false;
50525ecfbf8Swanglei 
50625ecfbf8Swanglei   return true;
50725ecfbf8Swanglei }
508