xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file contains the LoongArch implementation of TargetFrameLowering class.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "LoongArchFrameLowering.h"
14753f127fSDimitry Andric #include "LoongArchMachineFunctionInfo.h"
1581ad6265SDimitry Andric #include "LoongArchSubtarget.h"
16753f127fSDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
17*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
1881ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
2381ad6265SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
2481ad6265SDimitry Andric #include "llvm/MC/MCDwarf.h"
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric using namespace llvm;
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-frame-lowering"
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric // Return true if the specified function should have a dedicated frame
3181ad6265SDimitry Andric // pointer register.  This is true if frame pointer elimination is
3281ad6265SDimitry Andric // disabled, if it needs dynamic stack realignment, if the function has
3381ad6265SDimitry Andric // variable sized allocas, or if the frame address is taken.
3481ad6265SDimitry Andric bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const {
3581ad6265SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
3881ad6265SDimitry Andric   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
3981ad6265SDimitry Andric          RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
4081ad6265SDimitry Andric          MFI.isFrameAddressTaken();
4181ad6265SDimitry Andric }
4281ad6265SDimitry Andric 
4381ad6265SDimitry Andric bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {
4481ad6265SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
4581ad6265SDimitry Andric   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric   return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);
4881ad6265SDimitry Andric }
4981ad6265SDimitry Andric 
50753f127fSDimitry Andric void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,
51753f127fSDimitry Andric                                        MachineBasicBlock::iterator MBBI,
52753f127fSDimitry Andric                                        const DebugLoc &DL, Register DestReg,
53753f127fSDimitry Andric                                        Register SrcReg, int64_t Val,
54753f127fSDimitry Andric                                        MachineInstr::MIFlag Flag) const {
55753f127fSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
56753f127fSDimitry Andric   bool IsLA64 = STI.is64Bit();
57*bdd1243dSDimitry Andric   unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
58753f127fSDimitry Andric 
59753f127fSDimitry Andric   if (DestReg == SrcReg && Val == 0)
60753f127fSDimitry Andric     return;
61753f127fSDimitry Andric 
62753f127fSDimitry Andric   if (isInt<12>(Val)) {
63753f127fSDimitry Andric     // addi.w/d $DstReg, $SrcReg, Val
64*bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
65753f127fSDimitry Andric         .addReg(SrcReg)
66753f127fSDimitry Andric         .addImm(Val)
67753f127fSDimitry Andric         .setMIFlag(Flag);
68753f127fSDimitry Andric     return;
69753f127fSDimitry Andric   }
70753f127fSDimitry Andric 
71*bdd1243dSDimitry Andric   // Try to split the offset across two ADDIs. We need to keep the stack pointer
72*bdd1243dSDimitry Andric   // aligned after each ADDI. We need to determine the maximum value we can put
73*bdd1243dSDimitry Andric   // in each ADDI. In the negative direction, we can use -2048 which is always
74*bdd1243dSDimitry Andric   // sufficiently aligned. In the positive direction, we need to find the
75*bdd1243dSDimitry Andric   // largest 12-bit immediate that is aligned. Exclude -4096 since it can be
76*bdd1243dSDimitry Andric   // created with LU12I.W.
77*bdd1243dSDimitry Andric   assert(getStackAlign().value() < 2048 && "Stack alignment too large");
78*bdd1243dSDimitry Andric   int64_t MaxPosAdjStep = 2048 - getStackAlign().value();
79*bdd1243dSDimitry Andric   if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) {
80*bdd1243dSDimitry Andric     int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep;
81*bdd1243dSDimitry Andric     Val -= FirstAdj;
82*bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
83*bdd1243dSDimitry Andric         .addReg(SrcReg)
84*bdd1243dSDimitry Andric         .addImm(FirstAdj)
85*bdd1243dSDimitry Andric         .setMIFlag(Flag);
86*bdd1243dSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
87*bdd1243dSDimitry Andric         .addReg(DestReg, RegState::Kill)
88*bdd1243dSDimitry Andric         .addImm(Val)
89*bdd1243dSDimitry Andric         .setMIFlag(Flag);
90*bdd1243dSDimitry Andric     return;
91*bdd1243dSDimitry Andric   }
92*bdd1243dSDimitry Andric 
93*bdd1243dSDimitry Andric   unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
94*bdd1243dSDimitry Andric   if (Val < 0) {
95*bdd1243dSDimitry Andric     Val = -Val;
96*bdd1243dSDimitry Andric     Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W;
97*bdd1243dSDimitry Andric   }
98*bdd1243dSDimitry Andric 
99*bdd1243dSDimitry Andric   MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
100*bdd1243dSDimitry Andric   Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
101*bdd1243dSDimitry Andric   TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag);
102*bdd1243dSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)
103*bdd1243dSDimitry Andric       .addReg(SrcReg)
104*bdd1243dSDimitry Andric       .addReg(ScratchReg, RegState::Kill)
105*bdd1243dSDimitry Andric       .setMIFlag(Flag);
106753f127fSDimitry Andric }
107753f127fSDimitry Andric 
108753f127fSDimitry Andric // Determine the size of the frame and maximum call frame size.
109753f127fSDimitry Andric void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {
110753f127fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
111753f127fSDimitry Andric 
112753f127fSDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
113753f127fSDimitry Andric   uint64_t FrameSize = MFI.getStackSize();
114753f127fSDimitry Andric 
115753f127fSDimitry Andric   // Make sure the frame is aligned.
116753f127fSDimitry Andric   FrameSize = alignTo(FrameSize, getStackAlign());
117753f127fSDimitry Andric 
118753f127fSDimitry Andric   // Update frame info.
119753f127fSDimitry Andric   MFI.setStackSize(FrameSize);
120753f127fSDimitry Andric }
121753f127fSDimitry Andric 
122*bdd1243dSDimitry Andric static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII,
123*bdd1243dSDimitry Andric                                             const MachineFunction &MF) {
124*bdd1243dSDimitry Andric   uint64_t FuncSize = 0;
125*bdd1243dSDimitry Andric   for (auto &MBB : MF)
126*bdd1243dSDimitry Andric     for (auto &MI : MBB)
127*bdd1243dSDimitry Andric       FuncSize += TII->getInstSizeInBytes(MI);
128*bdd1243dSDimitry Andric   return FuncSize;
129*bdd1243dSDimitry Andric }
130*bdd1243dSDimitry Andric 
131*bdd1243dSDimitry Andric static bool needScavSlotForCFR(MachineFunction &MF) {
132*bdd1243dSDimitry Andric   if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF())
133*bdd1243dSDimitry Andric     return false;
134*bdd1243dSDimitry Andric   for (auto &MBB : MF)
135*bdd1243dSDimitry Andric     for (auto &MI : MBB)
136*bdd1243dSDimitry Andric       if (MI.getOpcode() == LoongArch::PseudoST_CFR)
137*bdd1243dSDimitry Andric         return true;
138*bdd1243dSDimitry Andric   return false;
139*bdd1243dSDimitry Andric }
140*bdd1243dSDimitry Andric 
141*bdd1243dSDimitry Andric void LoongArchFrameLowering::processFunctionBeforeFrameFinalized(
142*bdd1243dSDimitry Andric     MachineFunction &MF, RegScavenger *RS) const {
143*bdd1243dSDimitry Andric   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
144*bdd1243dSDimitry Andric   const TargetRegisterClass &RC = LoongArch::GPRRegClass;
145*bdd1243dSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
146*bdd1243dSDimitry Andric   LoongArchMachineFunctionInfo *LAFI =
147*bdd1243dSDimitry Andric       MF.getInfo<LoongArchMachineFunctionInfo>();
148*bdd1243dSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
149*bdd1243dSDimitry Andric 
150*bdd1243dSDimitry Andric   unsigned ScavSlotsNum = 0;
151*bdd1243dSDimitry Andric 
152*bdd1243dSDimitry Andric   // Far branches beyond 27-bit offset require a spill slot for scratch register.
153*bdd1243dSDimitry Andric   bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF));
154*bdd1243dSDimitry Andric   if (IsLargeFunction)
155*bdd1243dSDimitry Andric     ScavSlotsNum = 1;
156*bdd1243dSDimitry Andric 
157*bdd1243dSDimitry Andric   // estimateStackSize has been observed to under-estimate the final stack
158*bdd1243dSDimitry Andric   // size, so give ourselves wiggle-room by checking for stack size
159*bdd1243dSDimitry Andric   // representable an 11-bit signed field rather than 12-bits.
160*bdd1243dSDimitry Andric   if (!isInt<11>(MFI.estimateStackSize(MF)))
161*bdd1243dSDimitry Andric     ScavSlotsNum = std::max(ScavSlotsNum, 1u);
162*bdd1243dSDimitry Andric 
163*bdd1243dSDimitry Andric   // For CFR spill.
164*bdd1243dSDimitry Andric   if (needScavSlotForCFR(MF))
165*bdd1243dSDimitry Andric     ++ScavSlotsNum;
166*bdd1243dSDimitry Andric 
167*bdd1243dSDimitry Andric   // Create emergency spill slots.
168*bdd1243dSDimitry Andric   for (unsigned i = 0; i < ScavSlotsNum; ++i) {
169*bdd1243dSDimitry Andric     int FI = MFI.CreateStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC),
170*bdd1243dSDimitry Andric                                    false);
171*bdd1243dSDimitry Andric     RS->addScavengingFrameIndex(FI);
172*bdd1243dSDimitry Andric     if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1)
173*bdd1243dSDimitry Andric       LAFI->setBranchRelaxationSpillFrameIndex(FI);
174*bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "Allocated FI(" << FI
175*bdd1243dSDimitry Andric                       << ") as the emergency spill slot.\n");
176*bdd1243dSDimitry Andric   }
177*bdd1243dSDimitry Andric }
178*bdd1243dSDimitry Andric 
17981ad6265SDimitry Andric void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
18081ad6265SDimitry Andric                                           MachineBasicBlock &MBB) const {
181753f127fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
182*bdd1243dSDimitry Andric   auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
183753f127fSDimitry Andric   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
184753f127fSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
185753f127fSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
186*bdd1243dSDimitry Andric   bool IsLA64 = STI.is64Bit();
187753f127fSDimitry Andric 
188753f127fSDimitry Andric   Register SPReg = LoongArch::R3;
189753f127fSDimitry Andric   Register FPReg = LoongArch::R22;
190753f127fSDimitry Andric 
191753f127fSDimitry Andric   // Debug location must be unknown since the first debug location is used
192753f127fSDimitry Andric   // to determine the end of the prologue.
193753f127fSDimitry Andric   DebugLoc DL;
194*bdd1243dSDimitry Andric   // All calls are tail calls in GHC calling conv, and functions have no
195*bdd1243dSDimitry Andric   // prologue/epilogue.
196*bdd1243dSDimitry Andric   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
197*bdd1243dSDimitry Andric     return;
198753f127fSDimitry Andric   // Determine the correct frame layout
199753f127fSDimitry Andric   determineFrameLayout(MF);
200753f127fSDimitry Andric 
201753f127fSDimitry Andric   // First, compute final stack size.
202753f127fSDimitry Andric   uint64_t StackSize = MFI.getStackSize();
203*bdd1243dSDimitry Andric   uint64_t RealStackSize = StackSize;
204753f127fSDimitry Andric 
205753f127fSDimitry Andric   // Early exit if there is no need to allocate space in the stack.
206753f127fSDimitry Andric   if (StackSize == 0 && !MFI.adjustsStack())
207753f127fSDimitry Andric     return;
208753f127fSDimitry Andric 
209*bdd1243dSDimitry Andric   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF, true);
210*bdd1243dSDimitry Andric   uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;
211*bdd1243dSDimitry Andric   // Split the SP adjustment to reduce the offsets of callee saved spill.
212*bdd1243dSDimitry Andric   if (FirstSPAdjustAmount)
213*bdd1243dSDimitry Andric     StackSize = FirstSPAdjustAmount;
214*bdd1243dSDimitry Andric 
215753f127fSDimitry Andric   // Adjust stack.
216753f127fSDimitry Andric   adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
217*bdd1243dSDimitry Andric   if (FirstSPAdjustAmount != 2048 || SecondSPAdjustAmount == 0) {
218753f127fSDimitry Andric     // Emit ".cfi_def_cfa_offset StackSize".
219753f127fSDimitry Andric     unsigned CFIIndex =
220753f127fSDimitry Andric         MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
221753f127fSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
222753f127fSDimitry Andric         .addCFIIndex(CFIIndex)
223753f127fSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
224*bdd1243dSDimitry Andric   }
225753f127fSDimitry Andric 
226753f127fSDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
227753f127fSDimitry Andric 
228753f127fSDimitry Andric   // The frame pointer is callee-saved, and code has been generated for us to
229753f127fSDimitry Andric   // save it to the stack. We need to skip over the storing of callee-saved
230753f127fSDimitry Andric   // registers as the frame pointer must be modified after it has been saved
231753f127fSDimitry Andric   // to the stack, not before.
232753f127fSDimitry Andric   std::advance(MBBI, CSI.size());
233753f127fSDimitry Andric 
234753f127fSDimitry Andric   // Iterate over list of callee-saved registers and emit .cfi_offset
235753f127fSDimitry Andric   // directives.
236753f127fSDimitry Andric   for (const auto &Entry : CSI) {
237753f127fSDimitry Andric     int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
238753f127fSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
239753f127fSDimitry Andric         nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));
240753f127fSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
241753f127fSDimitry Andric         .addCFIIndex(CFIIndex)
242753f127fSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
243753f127fSDimitry Andric   }
244753f127fSDimitry Andric 
245753f127fSDimitry Andric   // Generate new FP.
246753f127fSDimitry Andric   if (hasFP(MF)) {
247*bdd1243dSDimitry Andric     adjustReg(MBB, MBBI, DL, FPReg, SPReg,
248*bdd1243dSDimitry Andric               StackSize - LoongArchFI->getVarArgsSaveSize(),
249*bdd1243dSDimitry Andric               MachineInstr::FrameSetup);
250753f127fSDimitry Andric 
251*bdd1243dSDimitry Andric     // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()"
252*bdd1243dSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(
253*bdd1243dSDimitry Andric         MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true),
254*bdd1243dSDimitry Andric                                     LoongArchFI->getVarArgsSaveSize()));
255753f127fSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
256753f127fSDimitry Andric         .addCFIIndex(CFIIndex)
257753f127fSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
258753f127fSDimitry Andric   }
259*bdd1243dSDimitry Andric 
260*bdd1243dSDimitry Andric   // Emit the second SP adjustment after saving callee saved registers.
261*bdd1243dSDimitry Andric   if (FirstSPAdjustAmount && SecondSPAdjustAmount) {
262*bdd1243dSDimitry Andric     if (hasFP(MF)) {
263*bdd1243dSDimitry Andric       assert(SecondSPAdjustAmount > 0 &&
264*bdd1243dSDimitry Andric              "SecondSPAdjustAmount should be greater than zero");
265*bdd1243dSDimitry Andric       adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,
266*bdd1243dSDimitry Andric                 MachineInstr::FrameSetup);
267*bdd1243dSDimitry Andric     } else {
268*bdd1243dSDimitry Andric       // FIXME: RegScavenger will place the spill instruction before the
269*bdd1243dSDimitry Andric       // prologue if a VReg is created in the prologue. This will pollute the
270*bdd1243dSDimitry Andric       // caller's stack data. Therefore, until there is better way, we just use
271*bdd1243dSDimitry Andric       // the `addi.w/d` instruction for stack adjustment to ensure that VReg
272*bdd1243dSDimitry Andric       // will not be created.
273*bdd1243dSDimitry Andric       for (int Val = SecondSPAdjustAmount; Val > 0; Val -= 2048)
274*bdd1243dSDimitry Andric         BuildMI(MBB, MBBI, DL,
275*bdd1243dSDimitry Andric                 TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), SPReg)
276*bdd1243dSDimitry Andric             .addReg(SPReg)
277*bdd1243dSDimitry Andric             .addImm(Val < 2048 ? -Val : -2048)
278*bdd1243dSDimitry Andric             .setMIFlag(MachineInstr::FrameSetup);
279*bdd1243dSDimitry Andric 
280*bdd1243dSDimitry Andric       // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",
281*bdd1243dSDimitry Andric       // don't emit an sp-based .cfi_def_cfa_offset
282*bdd1243dSDimitry Andric       // Emit ".cfi_def_cfa_offset RealStackSize"
283*bdd1243dSDimitry Andric       unsigned CFIIndex = MF.addFrameInst(
284*bdd1243dSDimitry Andric           MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
285*bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
286*bdd1243dSDimitry Andric           .addCFIIndex(CFIIndex)
287*bdd1243dSDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
288*bdd1243dSDimitry Andric     }
289*bdd1243dSDimitry Andric   }
290*bdd1243dSDimitry Andric 
291*bdd1243dSDimitry Andric   if (hasFP(MF)) {
292*bdd1243dSDimitry Andric     // Realign stack.
293*bdd1243dSDimitry Andric     if (RI->hasStackRealignment(MF)) {
294*bdd1243dSDimitry Andric       unsigned ShiftAmount = Log2(MFI.getMaxAlign());
295*bdd1243dSDimitry Andric       Register VR =
296*bdd1243dSDimitry Andric           MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
297*bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL,
298*bdd1243dSDimitry Andric               TII->get(IsLA64 ? LoongArch::SRLI_D : LoongArch::SRLI_W), VR)
299*bdd1243dSDimitry Andric           .addReg(SPReg)
300*bdd1243dSDimitry Andric           .addImm(ShiftAmount)
301*bdd1243dSDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
302*bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL,
303*bdd1243dSDimitry Andric               TII->get(IsLA64 ? LoongArch::SLLI_D : LoongArch::SLLI_W), SPReg)
304*bdd1243dSDimitry Andric           .addReg(VR)
305*bdd1243dSDimitry Andric           .addImm(ShiftAmount)
306*bdd1243dSDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
307*bdd1243dSDimitry Andric       // FP will be used to restore the frame in the epilogue, so we need
308*bdd1243dSDimitry Andric       // another base register BP to record SP after re-alignment. SP will
309*bdd1243dSDimitry Andric       // track the current stack after allocating variable sized objects.
310*bdd1243dSDimitry Andric       if (hasBP(MF)) {
311*bdd1243dSDimitry Andric         // move BP, $sp
312*bdd1243dSDimitry Andric         BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR),
313*bdd1243dSDimitry Andric                 LoongArchABI::getBPReg())
314*bdd1243dSDimitry Andric             .addReg(SPReg)
315*bdd1243dSDimitry Andric             .addReg(LoongArch::R0)
316*bdd1243dSDimitry Andric             .setMIFlag(MachineInstr::FrameSetup);
317*bdd1243dSDimitry Andric       }
318*bdd1243dSDimitry Andric     }
319*bdd1243dSDimitry Andric   }
32081ad6265SDimitry Andric }
32181ad6265SDimitry Andric 
32281ad6265SDimitry Andric void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
32381ad6265SDimitry Andric                                           MachineBasicBlock &MBB) const {
324753f127fSDimitry Andric   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
325753f127fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
326*bdd1243dSDimitry Andric   auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
327753f127fSDimitry Andric   Register SPReg = LoongArch::R3;
328*bdd1243dSDimitry Andric   // All calls are tail calls in GHC calling conv, and functions have no
329*bdd1243dSDimitry Andric   // prologue/epilogue.
330*bdd1243dSDimitry Andric   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
331*bdd1243dSDimitry Andric     return;
332753f127fSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
333753f127fSDimitry Andric   DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
334753f127fSDimitry Andric 
335753f127fSDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
336753f127fSDimitry Andric   // Skip to before the restores of callee-saved registers.
337753f127fSDimitry Andric   auto LastFrameDestroy = MBBI;
338753f127fSDimitry Andric   if (!CSI.empty())
339753f127fSDimitry Andric     LastFrameDestroy = std::prev(MBBI, CSI.size());
340753f127fSDimitry Andric 
341753f127fSDimitry Andric   // Get the number of bytes from FrameInfo.
342753f127fSDimitry Andric   uint64_t StackSize = MFI.getStackSize();
343753f127fSDimitry Andric 
344753f127fSDimitry Andric   // Restore the stack pointer.
345753f127fSDimitry Andric   if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
346753f127fSDimitry Andric     assert(hasFP(MF) && "frame pointer should not have been eliminated");
347*bdd1243dSDimitry Andric     adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22,
348*bdd1243dSDimitry Andric               -StackSize + LoongArchFI->getVarArgsSaveSize(),
349753f127fSDimitry Andric               MachineInstr::FrameDestroy);
350753f127fSDimitry Andric   }
351753f127fSDimitry Andric 
352*bdd1243dSDimitry Andric   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
353*bdd1243dSDimitry Andric   if (FirstSPAdjustAmount) {
354*bdd1243dSDimitry Andric     uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount;
355*bdd1243dSDimitry Andric     assert(SecondSPAdjustAmount > 0 &&
356*bdd1243dSDimitry Andric            "SecondSPAdjustAmount should be greater than zero");
357*bdd1243dSDimitry Andric 
358*bdd1243dSDimitry Andric     adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount,
359*bdd1243dSDimitry Andric               MachineInstr::FrameDestroy);
360*bdd1243dSDimitry Andric     StackSize = FirstSPAdjustAmount;
361*bdd1243dSDimitry Andric   }
362*bdd1243dSDimitry Andric 
363753f127fSDimitry Andric   // Deallocate stack
364753f127fSDimitry Andric   adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
365753f127fSDimitry Andric }
366753f127fSDimitry Andric 
367*bdd1243dSDimitry Andric // We would like to split the SP adjustment to reduce prologue/epilogue
368*bdd1243dSDimitry Andric // as following instructions. In this way, the offset of the callee saved
369*bdd1243dSDimitry Andric // register could fit in a single store.
370*bdd1243dSDimitry Andric // e.g.
371*bdd1243dSDimitry Andric //   addi.d  $sp, $sp, -2032
372*bdd1243dSDimitry Andric //   st.d    $ra, $sp,  2024
373*bdd1243dSDimitry Andric //   st.d    $fp, $sp,  2016
374*bdd1243dSDimitry Andric //   addi.d  $sp, $sp,   -16
375*bdd1243dSDimitry Andric uint64_t
376*bdd1243dSDimitry Andric LoongArchFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF,
377*bdd1243dSDimitry Andric                                                bool IsPrologue) const {
378*bdd1243dSDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
379*bdd1243dSDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
380*bdd1243dSDimitry Andric 
381*bdd1243dSDimitry Andric   // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed
382*bdd1243dSDimitry Andric   // 12-bit and there exists a callee-saved register needing to be pushed.
383*bdd1243dSDimitry Andric   if (!isInt<12>(MFI.getStackSize())) {
384*bdd1243dSDimitry Andric     // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will
385*bdd1243dSDimitry Andric     // cause sp = sp + 2048 in the epilogue to be split into multiple
386*bdd1243dSDimitry Andric     // instructions. Offsets smaller than 2048 can fit in a single load/store
387*bdd1243dSDimitry Andric     // instruction, and we have to stick with the stack alignment.
388*bdd1243dSDimitry Andric     // So (2048 - StackAlign) will satisfy the stack alignment.
389*bdd1243dSDimitry Andric     //
390*bdd1243dSDimitry Andric     // FIXME: This place may seem odd. When using multiple ADDI instructions to
391*bdd1243dSDimitry Andric     // adjust the stack in Prologue, and there are no callee-saved registers, we
392*bdd1243dSDimitry Andric     // can take advantage of the logic of split sp ajustment to reduce code
393*bdd1243dSDimitry Andric     // changes.
394*bdd1243dSDimitry Andric     return CSI.size() > 0 ? 2048 - getStackAlign().value()
395*bdd1243dSDimitry Andric                           : (IsPrologue ? 2048 : 0);
396*bdd1243dSDimitry Andric   }
397*bdd1243dSDimitry Andric   return 0;
398*bdd1243dSDimitry Andric }
399*bdd1243dSDimitry Andric 
400753f127fSDimitry Andric void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
401753f127fSDimitry Andric                                                   BitVector &SavedRegs,
402753f127fSDimitry Andric                                                   RegScavenger *RS) const {
403753f127fSDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
404753f127fSDimitry Andric   // Unconditionally spill RA and FP only if the function uses a frame
405753f127fSDimitry Andric   // pointer.
406753f127fSDimitry Andric   if (hasFP(MF)) {
407753f127fSDimitry Andric     SavedRegs.set(LoongArch::R1);
408753f127fSDimitry Andric     SavedRegs.set(LoongArch::R22);
409753f127fSDimitry Andric   }
410753f127fSDimitry Andric   // Mark BP as used if function has dedicated base pointer.
411753f127fSDimitry Andric   if (hasBP(MF))
412753f127fSDimitry Andric     SavedRegs.set(LoongArchABI::getBPReg());
413753f127fSDimitry Andric }
414753f127fSDimitry Andric 
415*bdd1243dSDimitry Andric // Do not preserve stack space within prologue for outgoing variables if the
416*bdd1243dSDimitry Andric // function contains variable size objects.
417*bdd1243dSDimitry Andric // Let eliminateCallFramePseudoInstr preserve stack space for it.
418*bdd1243dSDimitry Andric bool LoongArchFrameLowering::hasReservedCallFrame(
419*bdd1243dSDimitry Andric     const MachineFunction &MF) const {
420*bdd1243dSDimitry Andric   return !MF.getFrameInfo().hasVarSizedObjects();
421*bdd1243dSDimitry Andric }
422*bdd1243dSDimitry Andric 
423*bdd1243dSDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.
424*bdd1243dSDimitry Andric MachineBasicBlock::iterator
425*bdd1243dSDimitry Andric LoongArchFrameLowering::eliminateCallFramePseudoInstr(
426*bdd1243dSDimitry Andric     MachineFunction &MF, MachineBasicBlock &MBB,
427*bdd1243dSDimitry Andric     MachineBasicBlock::iterator MI) const {
428*bdd1243dSDimitry Andric   Register SPReg = LoongArch::R3;
429*bdd1243dSDimitry Andric   DebugLoc DL = MI->getDebugLoc();
430*bdd1243dSDimitry Andric 
431*bdd1243dSDimitry Andric   if (!hasReservedCallFrame(MF)) {
432*bdd1243dSDimitry Andric     // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and
433*bdd1243dSDimitry Andric     // ADJCALLSTACKUP must be converted to instructions manipulating the stack
434*bdd1243dSDimitry Andric     // pointer. This is necessary when there is a variable length stack
435*bdd1243dSDimitry Andric     // allocation (e.g. alloca), which means it's not possible to allocate
436*bdd1243dSDimitry Andric     // space for outgoing arguments from within the function prologue.
437*bdd1243dSDimitry Andric     int64_t Amount = MI->getOperand(0).getImm();
438*bdd1243dSDimitry Andric 
439*bdd1243dSDimitry Andric     if (Amount != 0) {
440*bdd1243dSDimitry Andric       // Ensure the stack remains aligned after adjustment.
441*bdd1243dSDimitry Andric       Amount = alignSPAdjust(Amount);
442*bdd1243dSDimitry Andric 
443*bdd1243dSDimitry Andric       if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN)
444*bdd1243dSDimitry Andric         Amount = -Amount;
445*bdd1243dSDimitry Andric 
446*bdd1243dSDimitry Andric       adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
447*bdd1243dSDimitry Andric     }
448*bdd1243dSDimitry Andric   }
449*bdd1243dSDimitry Andric 
450*bdd1243dSDimitry Andric   return MBB.erase(MI);
451*bdd1243dSDimitry Andric }
452*bdd1243dSDimitry Andric 
453*bdd1243dSDimitry Andric bool LoongArchFrameLowering::spillCalleeSavedRegisters(
454*bdd1243dSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
455*bdd1243dSDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
456*bdd1243dSDimitry Andric   if (CSI.empty())
457*bdd1243dSDimitry Andric     return true;
458*bdd1243dSDimitry Andric 
459*bdd1243dSDimitry Andric   MachineFunction *MF = MBB.getParent();
460*bdd1243dSDimitry Andric   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
461*bdd1243dSDimitry Andric 
462*bdd1243dSDimitry Andric   // Insert the spill to the stack frame.
463*bdd1243dSDimitry Andric   for (auto &CS : CSI) {
464*bdd1243dSDimitry Andric     Register Reg = CS.getReg();
465*bdd1243dSDimitry Andric     // If the register is RA and the return address is taken by method
466*bdd1243dSDimitry Andric     // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag.
467*bdd1243dSDimitry Andric     bool IsKill =
468*bdd1243dSDimitry Andric         !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken());
469*bdd1243dSDimitry Andric     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
470*bdd1243dSDimitry Andric     TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI,
471*bdd1243dSDimitry Andric                             Register());
472*bdd1243dSDimitry Andric   }
473*bdd1243dSDimitry Andric 
474*bdd1243dSDimitry Andric   return true;
475*bdd1243dSDimitry Andric }
476*bdd1243dSDimitry Andric 
477753f127fSDimitry Andric StackOffset LoongArchFrameLowering::getFrameIndexReference(
478753f127fSDimitry Andric     const MachineFunction &MF, int FI, Register &FrameReg) const {
479753f127fSDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
480753f127fSDimitry Andric   const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
481*bdd1243dSDimitry Andric   auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
482*bdd1243dSDimitry Andric   uint64_t StackSize = MFI.getStackSize();
483*bdd1243dSDimitry Andric   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
484753f127fSDimitry Andric 
485753f127fSDimitry Andric   // Callee-saved registers should be referenced relative to the stack
486753f127fSDimitry Andric   // pointer (positive offset), otherwise use the frame pointer (negative
487753f127fSDimitry Andric   // offset).
488753f127fSDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
489753f127fSDimitry Andric   int MinCSFI = 0;
490753f127fSDimitry Andric   int MaxCSFI = -1;
491753f127fSDimitry Andric   StackOffset Offset =
492753f127fSDimitry Andric       StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
493753f127fSDimitry Andric                             MFI.getOffsetAdjustment());
494753f127fSDimitry Andric 
495753f127fSDimitry Andric   if (CSI.size()) {
496753f127fSDimitry Andric     MinCSFI = CSI[0].getFrameIdx();
497753f127fSDimitry Andric     MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
498753f127fSDimitry Andric   }
499753f127fSDimitry Andric 
500*bdd1243dSDimitry Andric   if (FI >= MinCSFI && FI <= MaxCSFI) {
501753f127fSDimitry Andric     FrameReg = LoongArch::R3;
502*bdd1243dSDimitry Andric     if (FirstSPAdjustAmount)
503*bdd1243dSDimitry Andric       Offset += StackOffset::getFixed(FirstSPAdjustAmount);
504*bdd1243dSDimitry Andric     else
505*bdd1243dSDimitry Andric       Offset += StackOffset::getFixed(StackSize);
506*bdd1243dSDimitry Andric   } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {
507*bdd1243dSDimitry Andric     // If the stack was realigned, the frame pointer is set in order to allow
508*bdd1243dSDimitry Andric     // SP to be restored, so we need another base register to record the stack
509*bdd1243dSDimitry Andric     // after realignment.
510*bdd1243dSDimitry Andric     FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3;
511*bdd1243dSDimitry Andric     Offset += StackOffset::getFixed(StackSize);
512*bdd1243dSDimitry Andric   } else {
513*bdd1243dSDimitry Andric     FrameReg = RI->getFrameRegister(MF);
514*bdd1243dSDimitry Andric     if (hasFP(MF))
515*bdd1243dSDimitry Andric       Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize());
516*bdd1243dSDimitry Andric     else
517*bdd1243dSDimitry Andric       Offset += StackOffset::getFixed(StackSize);
518753f127fSDimitry Andric   }
519753f127fSDimitry Andric 
520753f127fSDimitry Andric   return Offset;
52181ad6265SDimitry Andric }
522