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"
17bdd1243dSDimitry 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.
hasFP(const MachineFunction & MF) const3481ad6265SDimitry 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
hasBP(const MachineFunction & MF) const4381ad6265SDimitry 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
adjustReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,Register DestReg,Register SrcReg,int64_t Val,MachineInstr::MIFlag Flag) const50753f127fSDimitry 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();
57bdd1243dSDimitry 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
64bdd1243dSDimitry 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
71bdd1243dSDimitry Andric // Try to split the offset across two ADDIs. We need to keep the stack pointer
72bdd1243dSDimitry Andric // aligned after each ADDI. We need to determine the maximum value we can put
73bdd1243dSDimitry Andric // in each ADDI. In the negative direction, we can use -2048 which is always
74bdd1243dSDimitry Andric // sufficiently aligned. In the positive direction, we need to find the
75bdd1243dSDimitry Andric // largest 12-bit immediate that is aligned. Exclude -4096 since it can be
76bdd1243dSDimitry Andric // created with LU12I.W.
77bdd1243dSDimitry Andric assert(getStackAlign().value() < 2048 && "Stack alignment too large");
78bdd1243dSDimitry Andric int64_t MaxPosAdjStep = 2048 - getStackAlign().value();
79bdd1243dSDimitry Andric if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) {
80bdd1243dSDimitry Andric int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep;
81bdd1243dSDimitry Andric Val -= FirstAdj;
82bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
83bdd1243dSDimitry Andric .addReg(SrcReg)
84bdd1243dSDimitry Andric .addImm(FirstAdj)
85bdd1243dSDimitry Andric .setMIFlag(Flag);
86bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)
87bdd1243dSDimitry Andric .addReg(DestReg, RegState::Kill)
88bdd1243dSDimitry Andric .addImm(Val)
89bdd1243dSDimitry Andric .setMIFlag(Flag);
90bdd1243dSDimitry Andric return;
91bdd1243dSDimitry Andric }
92bdd1243dSDimitry Andric
93bdd1243dSDimitry Andric unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
94bdd1243dSDimitry Andric if (Val < 0) {
95bdd1243dSDimitry Andric Val = -Val;
96bdd1243dSDimitry Andric Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W;
97bdd1243dSDimitry Andric }
98bdd1243dSDimitry Andric
99bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
100bdd1243dSDimitry Andric Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
101bdd1243dSDimitry Andric TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag);
102bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)
103bdd1243dSDimitry Andric .addReg(SrcReg)
104bdd1243dSDimitry Andric .addReg(ScratchReg, RegState::Kill)
105bdd1243dSDimitry Andric .setMIFlag(Flag);
106753f127fSDimitry Andric }
107753f127fSDimitry Andric
108753f127fSDimitry Andric // Determine the size of the frame and maximum call frame size.
determineFrameLayout(MachineFunction & MF) const109753f127fSDimitry 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
estimateFunctionSizeInBytes(const LoongArchInstrInfo * TII,const MachineFunction & MF)122bdd1243dSDimitry Andric static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII,
123bdd1243dSDimitry Andric const MachineFunction &MF) {
124bdd1243dSDimitry Andric uint64_t FuncSize = 0;
125bdd1243dSDimitry Andric for (auto &MBB : MF)
126bdd1243dSDimitry Andric for (auto &MI : MBB)
127bdd1243dSDimitry Andric FuncSize += TII->getInstSizeInBytes(MI);
128bdd1243dSDimitry Andric return FuncSize;
129bdd1243dSDimitry Andric }
130bdd1243dSDimitry Andric
needScavSlotForCFR(MachineFunction & MF)131bdd1243dSDimitry Andric static bool needScavSlotForCFR(MachineFunction &MF) {
132bdd1243dSDimitry Andric if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF())
133bdd1243dSDimitry Andric return false;
134bdd1243dSDimitry Andric for (auto &MBB : MF)
135bdd1243dSDimitry Andric for (auto &MI : MBB)
136bdd1243dSDimitry Andric if (MI.getOpcode() == LoongArch::PseudoST_CFR)
137bdd1243dSDimitry Andric return true;
138bdd1243dSDimitry Andric return false;
139bdd1243dSDimitry Andric }
140bdd1243dSDimitry Andric
processFunctionBeforeFrameFinalized(MachineFunction & MF,RegScavenger * RS) const141bdd1243dSDimitry Andric void LoongArchFrameLowering::processFunctionBeforeFrameFinalized(
142bdd1243dSDimitry Andric MachineFunction &MF, RegScavenger *RS) const {
143bdd1243dSDimitry Andric const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
144bdd1243dSDimitry Andric const TargetRegisterClass &RC = LoongArch::GPRRegClass;
145bdd1243dSDimitry Andric const LoongArchInstrInfo *TII = STI.getInstrInfo();
146bdd1243dSDimitry Andric LoongArchMachineFunctionInfo *LAFI =
147bdd1243dSDimitry Andric MF.getInfo<LoongArchMachineFunctionInfo>();
148bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
149bdd1243dSDimitry Andric
150bdd1243dSDimitry Andric unsigned ScavSlotsNum = 0;
151bdd1243dSDimitry Andric
152*0fca6ea1SDimitry Andric // Far branches beyond 27-bit offset require a spill slot for scratch
153*0fca6ea1SDimitry Andric // register.
154bdd1243dSDimitry Andric bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF));
155bdd1243dSDimitry Andric if (IsLargeFunction)
156bdd1243dSDimitry Andric ScavSlotsNum = 1;
157bdd1243dSDimitry Andric
158bdd1243dSDimitry Andric // estimateStackSize has been observed to under-estimate the final stack
159bdd1243dSDimitry Andric // size, so give ourselves wiggle-room by checking for stack size
160bdd1243dSDimitry Andric // representable an 11-bit signed field rather than 12-bits.
161bdd1243dSDimitry Andric if (!isInt<11>(MFI.estimateStackSize(MF)))
162bdd1243dSDimitry Andric ScavSlotsNum = std::max(ScavSlotsNum, 1u);
163bdd1243dSDimitry Andric
164bdd1243dSDimitry Andric // For CFR spill.
165bdd1243dSDimitry Andric if (needScavSlotForCFR(MF))
166bdd1243dSDimitry Andric ++ScavSlotsNum;
167bdd1243dSDimitry Andric
168bdd1243dSDimitry Andric // Create emergency spill slots.
169bdd1243dSDimitry Andric for (unsigned i = 0; i < ScavSlotsNum; ++i) {
170bdd1243dSDimitry Andric int FI = MFI.CreateStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC),
171bdd1243dSDimitry Andric false);
172bdd1243dSDimitry Andric RS->addScavengingFrameIndex(FI);
173bdd1243dSDimitry Andric if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1)
174bdd1243dSDimitry Andric LAFI->setBranchRelaxationSpillFrameIndex(FI);
175bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Allocated FI(" << FI
176bdd1243dSDimitry Andric << ") as the emergency spill slot.\n");
177bdd1243dSDimitry Andric }
178bdd1243dSDimitry Andric }
179bdd1243dSDimitry Andric
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const18081ad6265SDimitry Andric void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
18181ad6265SDimitry Andric MachineBasicBlock &MBB) const {
182753f127fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
183bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
184753f127fSDimitry Andric const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
185753f127fSDimitry Andric const LoongArchInstrInfo *TII = STI.getInstrInfo();
186753f127fSDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin();
187bdd1243dSDimitry Andric bool IsLA64 = STI.is64Bit();
188753f127fSDimitry Andric
189753f127fSDimitry Andric Register SPReg = LoongArch::R3;
190753f127fSDimitry Andric Register FPReg = LoongArch::R22;
191753f127fSDimitry Andric
192753f127fSDimitry Andric // Debug location must be unknown since the first debug location is used
193753f127fSDimitry Andric // to determine the end of the prologue.
194753f127fSDimitry Andric DebugLoc DL;
195bdd1243dSDimitry Andric // All calls are tail calls in GHC calling conv, and functions have no
196bdd1243dSDimitry Andric // prologue/epilogue.
197bdd1243dSDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC)
198bdd1243dSDimitry Andric return;
199753f127fSDimitry Andric // Determine the correct frame layout
200753f127fSDimitry Andric determineFrameLayout(MF);
201753f127fSDimitry Andric
202753f127fSDimitry Andric // First, compute final stack size.
203753f127fSDimitry Andric uint64_t StackSize = MFI.getStackSize();
204bdd1243dSDimitry Andric uint64_t RealStackSize = StackSize;
205753f127fSDimitry Andric
206753f127fSDimitry Andric // Early exit if there is no need to allocate space in the stack.
207753f127fSDimitry Andric if (StackSize == 0 && !MFI.adjustsStack())
208753f127fSDimitry Andric return;
209753f127fSDimitry Andric
210*0fca6ea1SDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
211bdd1243dSDimitry Andric // Split the SP adjustment to reduce the offsets of callee saved spill.
212bdd1243dSDimitry Andric if (FirstSPAdjustAmount)
213bdd1243dSDimitry Andric StackSize = FirstSPAdjustAmount;
214bdd1243dSDimitry Andric
215753f127fSDimitry Andric // Adjust stack.
216753f127fSDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
217753f127fSDimitry Andric // Emit ".cfi_def_cfa_offset StackSize".
218753f127fSDimitry Andric unsigned CFIIndex =
219753f127fSDimitry Andric MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
220753f127fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
221753f127fSDimitry Andric .addCFIIndex(CFIIndex)
222753f127fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
223753f127fSDimitry Andric
224753f127fSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo();
225753f127fSDimitry Andric
226753f127fSDimitry Andric // The frame pointer is callee-saved, and code has been generated for us to
227753f127fSDimitry Andric // save it to the stack. We need to skip over the storing of callee-saved
228753f127fSDimitry Andric // registers as the frame pointer must be modified after it has been saved
229753f127fSDimitry Andric // to the stack, not before.
230753f127fSDimitry Andric std::advance(MBBI, CSI.size());
231753f127fSDimitry Andric
232753f127fSDimitry Andric // Iterate over list of callee-saved registers and emit .cfi_offset
233753f127fSDimitry Andric // directives.
234753f127fSDimitry Andric for (const auto &Entry : CSI) {
235753f127fSDimitry Andric int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
236753f127fSDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
237753f127fSDimitry Andric nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));
238753f127fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
239753f127fSDimitry Andric .addCFIIndex(CFIIndex)
240753f127fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
241753f127fSDimitry Andric }
242753f127fSDimitry Andric
243753f127fSDimitry Andric // Generate new FP.
244753f127fSDimitry Andric if (hasFP(MF)) {
245bdd1243dSDimitry Andric adjustReg(MBB, MBBI, DL, FPReg, SPReg,
246bdd1243dSDimitry Andric StackSize - LoongArchFI->getVarArgsSaveSize(),
247bdd1243dSDimitry Andric MachineInstr::FrameSetup);
248753f127fSDimitry Andric
249bdd1243dSDimitry Andric // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()"
250bdd1243dSDimitry Andric unsigned CFIIndex = MF.addFrameInst(
251bdd1243dSDimitry Andric MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true),
252bdd1243dSDimitry Andric LoongArchFI->getVarArgsSaveSize()));
253753f127fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
254753f127fSDimitry Andric .addCFIIndex(CFIIndex)
255753f127fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
256753f127fSDimitry Andric }
257bdd1243dSDimitry Andric
258bdd1243dSDimitry Andric // Emit the second SP adjustment after saving callee saved registers.
259*0fca6ea1SDimitry Andric if (FirstSPAdjustAmount) {
260*0fca6ea1SDimitry Andric uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;
261bdd1243dSDimitry Andric assert(SecondSPAdjustAmount > 0 &&
262bdd1243dSDimitry Andric "SecondSPAdjustAmount should be greater than zero");
263bdd1243dSDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,
264bdd1243dSDimitry Andric MachineInstr::FrameSetup);
265bdd1243dSDimitry Andric
266*0fca6ea1SDimitry Andric if (!hasFP(MF)) {
267bdd1243dSDimitry Andric // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",
268bdd1243dSDimitry Andric // don't emit an sp-based .cfi_def_cfa_offset
269bdd1243dSDimitry Andric // Emit ".cfi_def_cfa_offset RealStackSize"
270bdd1243dSDimitry Andric unsigned CFIIndex = MF.addFrameInst(
271bdd1243dSDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
272bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
273bdd1243dSDimitry Andric .addCFIIndex(CFIIndex)
274bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
275bdd1243dSDimitry Andric }
276bdd1243dSDimitry Andric }
277bdd1243dSDimitry Andric
278bdd1243dSDimitry Andric if (hasFP(MF)) {
279bdd1243dSDimitry Andric // Realign stack.
280bdd1243dSDimitry Andric if (RI->hasStackRealignment(MF)) {
2815f757f3fSDimitry Andric unsigned Align = Log2(MFI.getMaxAlign());
2825f757f3fSDimitry Andric assert(Align > 0 && "The stack realignment size is invalid!");
283bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL,
2845f757f3fSDimitry Andric TII->get(IsLA64 ? LoongArch::BSTRINS_D : LoongArch::BSTRINS_W),
2855f757f3fSDimitry Andric SPReg)
286bdd1243dSDimitry Andric .addReg(SPReg)
2875f757f3fSDimitry Andric .addReg(LoongArch::R0)
2885f757f3fSDimitry Andric .addImm(Align - 1)
2895f757f3fSDimitry Andric .addImm(0)
290bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
291bdd1243dSDimitry Andric // FP will be used to restore the frame in the epilogue, so we need
292bdd1243dSDimitry Andric // another base register BP to record SP after re-alignment. SP will
293bdd1243dSDimitry Andric // track the current stack after allocating variable sized objects.
294bdd1243dSDimitry Andric if (hasBP(MF)) {
295bdd1243dSDimitry Andric // move BP, $sp
296bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR),
297bdd1243dSDimitry Andric LoongArchABI::getBPReg())
298bdd1243dSDimitry Andric .addReg(SPReg)
299bdd1243dSDimitry Andric .addReg(LoongArch::R0)
300bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup);
301bdd1243dSDimitry Andric }
302bdd1243dSDimitry Andric }
303bdd1243dSDimitry Andric }
30481ad6265SDimitry Andric }
30581ad6265SDimitry Andric
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const30681ad6265SDimitry Andric void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
30781ad6265SDimitry Andric MachineBasicBlock &MBB) const {
308753f127fSDimitry Andric const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
309753f127fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
310bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
311753f127fSDimitry Andric Register SPReg = LoongArch::R3;
312bdd1243dSDimitry Andric // All calls are tail calls in GHC calling conv, and functions have no
313bdd1243dSDimitry Andric // prologue/epilogue.
314bdd1243dSDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC)
315bdd1243dSDimitry Andric return;
316753f127fSDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
317753f127fSDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
318753f127fSDimitry Andric
319753f127fSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo();
320753f127fSDimitry Andric // Skip to before the restores of callee-saved registers.
321753f127fSDimitry Andric auto LastFrameDestroy = MBBI;
322753f127fSDimitry Andric if (!CSI.empty())
323753f127fSDimitry Andric LastFrameDestroy = std::prev(MBBI, CSI.size());
324753f127fSDimitry Andric
325753f127fSDimitry Andric // Get the number of bytes from FrameInfo.
326753f127fSDimitry Andric uint64_t StackSize = MFI.getStackSize();
327753f127fSDimitry Andric
328753f127fSDimitry Andric // Restore the stack pointer.
329753f127fSDimitry Andric if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
330753f127fSDimitry Andric assert(hasFP(MF) && "frame pointer should not have been eliminated");
331bdd1243dSDimitry Andric adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22,
332bdd1243dSDimitry Andric -StackSize + LoongArchFI->getVarArgsSaveSize(),
333753f127fSDimitry Andric MachineInstr::FrameDestroy);
334753f127fSDimitry Andric }
335753f127fSDimitry Andric
336bdd1243dSDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
337bdd1243dSDimitry Andric if (FirstSPAdjustAmount) {
338bdd1243dSDimitry Andric uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount;
339bdd1243dSDimitry Andric assert(SecondSPAdjustAmount > 0 &&
340bdd1243dSDimitry Andric "SecondSPAdjustAmount should be greater than zero");
341bdd1243dSDimitry Andric
342bdd1243dSDimitry Andric adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount,
343bdd1243dSDimitry Andric MachineInstr::FrameDestroy);
344bdd1243dSDimitry Andric StackSize = FirstSPAdjustAmount;
345bdd1243dSDimitry Andric }
346bdd1243dSDimitry Andric
347753f127fSDimitry Andric // Deallocate stack
348753f127fSDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
349753f127fSDimitry Andric }
350753f127fSDimitry Andric
351bdd1243dSDimitry Andric // We would like to split the SP adjustment to reduce prologue/epilogue
352bdd1243dSDimitry Andric // as following instructions. In this way, the offset of the callee saved
353bdd1243dSDimitry Andric // register could fit in a single store.
354bdd1243dSDimitry Andric // e.g.
355bdd1243dSDimitry Andric // addi.d $sp, $sp, -2032
356bdd1243dSDimitry Andric // st.d $ra, $sp, 2024
357bdd1243dSDimitry Andric // st.d $fp, $sp, 2016
358bdd1243dSDimitry Andric // addi.d $sp, $sp, -16
getFirstSPAdjustAmount(const MachineFunction & MF) const359*0fca6ea1SDimitry Andric uint64_t LoongArchFrameLowering::getFirstSPAdjustAmount(
360*0fca6ea1SDimitry Andric const MachineFunction &MF) const {
361bdd1243dSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo();
362bdd1243dSDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
363bdd1243dSDimitry Andric
364bdd1243dSDimitry Andric // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed
365bdd1243dSDimitry Andric // 12-bit and there exists a callee-saved register needing to be pushed.
366*0fca6ea1SDimitry Andric if (!isInt<12>(MFI.getStackSize()) && (CSI.size() > 0)) {
367bdd1243dSDimitry Andric // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will
368bdd1243dSDimitry Andric // cause sp = sp + 2048 in the epilogue to be split into multiple
369bdd1243dSDimitry Andric // instructions. Offsets smaller than 2048 can fit in a single load/store
370bdd1243dSDimitry Andric // instruction, and we have to stick with the stack alignment.
371bdd1243dSDimitry Andric // So (2048 - StackAlign) will satisfy the stack alignment.
372*0fca6ea1SDimitry Andric return 2048 - getStackAlign().value();
373bdd1243dSDimitry Andric }
374bdd1243dSDimitry Andric return 0;
375bdd1243dSDimitry Andric }
376bdd1243dSDimitry Andric
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const377753f127fSDimitry Andric void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
378753f127fSDimitry Andric BitVector &SavedRegs,
379753f127fSDimitry Andric RegScavenger *RS) const {
380753f127fSDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
381753f127fSDimitry Andric // Unconditionally spill RA and FP only if the function uses a frame
382753f127fSDimitry Andric // pointer.
383753f127fSDimitry Andric if (hasFP(MF)) {
384753f127fSDimitry Andric SavedRegs.set(LoongArch::R1);
385753f127fSDimitry Andric SavedRegs.set(LoongArch::R22);
386753f127fSDimitry Andric }
387753f127fSDimitry Andric // Mark BP as used if function has dedicated base pointer.
388753f127fSDimitry Andric if (hasBP(MF))
389753f127fSDimitry Andric SavedRegs.set(LoongArchABI::getBPReg());
390753f127fSDimitry Andric }
391753f127fSDimitry Andric
392bdd1243dSDimitry Andric // Do not preserve stack space within prologue for outgoing variables if the
393bdd1243dSDimitry Andric // function contains variable size objects.
394bdd1243dSDimitry Andric // Let eliminateCallFramePseudoInstr preserve stack space for it.
hasReservedCallFrame(const MachineFunction & MF) const395bdd1243dSDimitry Andric bool LoongArchFrameLowering::hasReservedCallFrame(
396bdd1243dSDimitry Andric const MachineFunction &MF) const {
397bdd1243dSDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects();
398bdd1243dSDimitry Andric }
399bdd1243dSDimitry Andric
400bdd1243dSDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.
401bdd1243dSDimitry Andric MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator MI) const402bdd1243dSDimitry Andric LoongArchFrameLowering::eliminateCallFramePseudoInstr(
403bdd1243dSDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB,
404bdd1243dSDimitry Andric MachineBasicBlock::iterator MI) const {
405bdd1243dSDimitry Andric Register SPReg = LoongArch::R3;
406bdd1243dSDimitry Andric DebugLoc DL = MI->getDebugLoc();
407bdd1243dSDimitry Andric
408bdd1243dSDimitry Andric if (!hasReservedCallFrame(MF)) {
409bdd1243dSDimitry Andric // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and
410bdd1243dSDimitry Andric // ADJCALLSTACKUP must be converted to instructions manipulating the stack
411bdd1243dSDimitry Andric // pointer. This is necessary when there is a variable length stack
412bdd1243dSDimitry Andric // allocation (e.g. alloca), which means it's not possible to allocate
413bdd1243dSDimitry Andric // space for outgoing arguments from within the function prologue.
414bdd1243dSDimitry Andric int64_t Amount = MI->getOperand(0).getImm();
415bdd1243dSDimitry Andric
416bdd1243dSDimitry Andric if (Amount != 0) {
417bdd1243dSDimitry Andric // Ensure the stack remains aligned after adjustment.
418bdd1243dSDimitry Andric Amount = alignSPAdjust(Amount);
419bdd1243dSDimitry Andric
420bdd1243dSDimitry Andric if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN)
421bdd1243dSDimitry Andric Amount = -Amount;
422bdd1243dSDimitry Andric
423bdd1243dSDimitry Andric adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
424bdd1243dSDimitry Andric }
425bdd1243dSDimitry Andric }
426bdd1243dSDimitry Andric
427bdd1243dSDimitry Andric return MBB.erase(MI);
428bdd1243dSDimitry Andric }
429bdd1243dSDimitry Andric
spillCalleeSavedRegisters(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,ArrayRef<CalleeSavedInfo> CSI,const TargetRegisterInfo * TRI) const430bdd1243dSDimitry Andric bool LoongArchFrameLowering::spillCalleeSavedRegisters(
431bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
432bdd1243dSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
433bdd1243dSDimitry Andric if (CSI.empty())
434bdd1243dSDimitry Andric return true;
435bdd1243dSDimitry Andric
436bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
437bdd1243dSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
438bdd1243dSDimitry Andric
439bdd1243dSDimitry Andric // Insert the spill to the stack frame.
440bdd1243dSDimitry Andric for (auto &CS : CSI) {
441bdd1243dSDimitry Andric Register Reg = CS.getReg();
442bdd1243dSDimitry Andric // If the register is RA and the return address is taken by method
443bdd1243dSDimitry Andric // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag.
444bdd1243dSDimitry Andric bool IsKill =
445bdd1243dSDimitry Andric !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken());
446bdd1243dSDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
447bdd1243dSDimitry Andric TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI,
448bdd1243dSDimitry Andric Register());
449bdd1243dSDimitry Andric }
450bdd1243dSDimitry Andric
451bdd1243dSDimitry Andric return true;
452bdd1243dSDimitry Andric }
453bdd1243dSDimitry Andric
getFrameIndexReference(const MachineFunction & MF,int FI,Register & FrameReg) const454753f127fSDimitry Andric StackOffset LoongArchFrameLowering::getFrameIndexReference(
455753f127fSDimitry Andric const MachineFunction &MF, int FI, Register &FrameReg) const {
456753f127fSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo();
457753f127fSDimitry Andric const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
458bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
459bdd1243dSDimitry Andric uint64_t StackSize = MFI.getStackSize();
460bdd1243dSDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
461753f127fSDimitry Andric
462753f127fSDimitry Andric // Callee-saved registers should be referenced relative to the stack
463753f127fSDimitry Andric // pointer (positive offset), otherwise use the frame pointer (negative
464753f127fSDimitry Andric // offset).
465753f127fSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo();
466753f127fSDimitry Andric int MinCSFI = 0;
467753f127fSDimitry Andric int MaxCSFI = -1;
468753f127fSDimitry Andric StackOffset Offset =
469753f127fSDimitry Andric StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
470753f127fSDimitry Andric MFI.getOffsetAdjustment());
471753f127fSDimitry Andric
472753f127fSDimitry Andric if (CSI.size()) {
473753f127fSDimitry Andric MinCSFI = CSI[0].getFrameIdx();
474753f127fSDimitry Andric MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
475753f127fSDimitry Andric }
476753f127fSDimitry Andric
477bdd1243dSDimitry Andric if (FI >= MinCSFI && FI <= MaxCSFI) {
478753f127fSDimitry Andric FrameReg = LoongArch::R3;
479bdd1243dSDimitry Andric if (FirstSPAdjustAmount)
480bdd1243dSDimitry Andric Offset += StackOffset::getFixed(FirstSPAdjustAmount);
481bdd1243dSDimitry Andric else
482bdd1243dSDimitry Andric Offset += StackOffset::getFixed(StackSize);
483bdd1243dSDimitry Andric } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {
484bdd1243dSDimitry Andric // If the stack was realigned, the frame pointer is set in order to allow
485bdd1243dSDimitry Andric // SP to be restored, so we need another base register to record the stack
486bdd1243dSDimitry Andric // after realignment.
487bdd1243dSDimitry Andric FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3;
488bdd1243dSDimitry Andric Offset += StackOffset::getFixed(StackSize);
489bdd1243dSDimitry Andric } else {
490bdd1243dSDimitry Andric FrameReg = RI->getFrameRegister(MF);
491bdd1243dSDimitry Andric if (hasFP(MF))
492bdd1243dSDimitry Andric Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize());
493bdd1243dSDimitry Andric else
494bdd1243dSDimitry Andric Offset += StackOffset::getFixed(StackSize);
495753f127fSDimitry Andric }
496753f127fSDimitry Andric
497753f127fSDimitry Andric return Offset;
49881ad6265SDimitry Andric }
49906c3fb27SDimitry Andric
enableShrinkWrapping(const MachineFunction & MF) const50006c3fb27SDimitry Andric bool LoongArchFrameLowering::enableShrinkWrapping(
50106c3fb27SDimitry Andric const MachineFunction &MF) const {
50206c3fb27SDimitry Andric // Keep the conventional code flow when not optimizing.
50306c3fb27SDimitry Andric if (MF.getFunction().hasOptNone())
50406c3fb27SDimitry Andric return false;
50506c3fb27SDimitry Andric
50606c3fb27SDimitry Andric return true;
50706c3fb27SDimitry Andric }
508