xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
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"
14*753f127fSDimitry Andric #include "LoongArchMachineFunctionInfo.h"
1581ad6265SDimitry Andric #include "LoongArchSubtarget.h"
16*753f127fSDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
1781ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
1881ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
2281ad6265SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
2381ad6265SDimitry Andric #include "llvm/MC/MCDwarf.h"
2481ad6265SDimitry Andric 
2581ad6265SDimitry Andric using namespace llvm;
2681ad6265SDimitry Andric 
2781ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-frame-lowering"
2881ad6265SDimitry Andric 
2981ad6265SDimitry Andric // Return true if the specified function should have a dedicated frame
3081ad6265SDimitry Andric // pointer register.  This is true if frame pointer elimination is
3181ad6265SDimitry Andric // disabled, if it needs dynamic stack realignment, if the function has
3281ad6265SDimitry Andric // variable sized allocas, or if the frame address is taken.
3381ad6265SDimitry Andric bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const {
3481ad6265SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
3781ad6265SDimitry Andric   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
3881ad6265SDimitry Andric          RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
3981ad6265SDimitry Andric          MFI.isFrameAddressTaken();
4081ad6265SDimitry Andric }
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {
4381ad6265SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
4481ad6265SDimitry Andric   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric   return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);
4781ad6265SDimitry Andric }
4881ad6265SDimitry Andric 
49*753f127fSDimitry Andric void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,
50*753f127fSDimitry Andric                                        MachineBasicBlock::iterator MBBI,
51*753f127fSDimitry Andric                                        const DebugLoc &DL, Register DestReg,
52*753f127fSDimitry Andric                                        Register SrcReg, int64_t Val,
53*753f127fSDimitry Andric                                        MachineInstr::MIFlag Flag) const {
54*753f127fSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
55*753f127fSDimitry Andric   bool IsLA64 = STI.is64Bit();
56*753f127fSDimitry Andric 
57*753f127fSDimitry Andric   if (DestReg == SrcReg && Val == 0)
58*753f127fSDimitry Andric     return;
59*753f127fSDimitry Andric 
60*753f127fSDimitry Andric   if (isInt<12>(Val)) {
61*753f127fSDimitry Andric     // addi.w/d $DstReg, $SrcReg, Val
62*753f127fSDimitry Andric     BuildMI(MBB, MBBI, DL,
63*753f127fSDimitry Andric             TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), DestReg)
64*753f127fSDimitry Andric         .addReg(SrcReg)
65*753f127fSDimitry Andric         .addImm(Val)
66*753f127fSDimitry Andric         .setMIFlag(Flag);
67*753f127fSDimitry Andric     return;
68*753f127fSDimitry Andric   }
69*753f127fSDimitry Andric 
70*753f127fSDimitry Andric   report_fatal_error("adjustReg cannot yet handle adjustments >12 bits");
71*753f127fSDimitry Andric }
72*753f127fSDimitry Andric 
73*753f127fSDimitry Andric // Determine the size of the frame and maximum call frame size.
74*753f127fSDimitry Andric void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {
75*753f127fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
76*753f127fSDimitry Andric 
77*753f127fSDimitry Andric   // Get the number of bytes to allocate from the FrameInfo.
78*753f127fSDimitry Andric   uint64_t FrameSize = MFI.getStackSize();
79*753f127fSDimitry Andric 
80*753f127fSDimitry Andric   // Make sure the frame is aligned.
81*753f127fSDimitry Andric   FrameSize = alignTo(FrameSize, getStackAlign());
82*753f127fSDimitry Andric 
83*753f127fSDimitry Andric   // Update frame info.
84*753f127fSDimitry Andric   MFI.setStackSize(FrameSize);
85*753f127fSDimitry Andric }
86*753f127fSDimitry Andric 
8781ad6265SDimitry Andric void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
8881ad6265SDimitry Andric                                           MachineBasicBlock &MBB) const {
89*753f127fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
90*753f127fSDimitry Andric   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
91*753f127fSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
92*753f127fSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
93*753f127fSDimitry Andric 
94*753f127fSDimitry Andric   Register SPReg = LoongArch::R3;
95*753f127fSDimitry Andric   Register FPReg = LoongArch::R22;
96*753f127fSDimitry Andric 
97*753f127fSDimitry Andric   // Debug location must be unknown since the first debug location is used
98*753f127fSDimitry Andric   // to determine the end of the prologue.
99*753f127fSDimitry Andric   DebugLoc DL;
100*753f127fSDimitry Andric 
101*753f127fSDimitry Andric   // Determine the correct frame layout
102*753f127fSDimitry Andric   determineFrameLayout(MF);
103*753f127fSDimitry Andric 
104*753f127fSDimitry Andric   // First, compute final stack size.
105*753f127fSDimitry Andric   uint64_t StackSize = MFI.getStackSize();
106*753f127fSDimitry Andric 
107*753f127fSDimitry Andric   // Early exit if there is no need to allocate space in the stack.
108*753f127fSDimitry Andric   if (StackSize == 0 && !MFI.adjustsStack())
109*753f127fSDimitry Andric     return;
110*753f127fSDimitry Andric 
111*753f127fSDimitry Andric   // Adjust stack.
112*753f127fSDimitry Andric   adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
113*753f127fSDimitry Andric   // Emit ".cfi_def_cfa_offset StackSize".
114*753f127fSDimitry Andric   unsigned CFIIndex =
115*753f127fSDimitry Andric       MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
116*753f127fSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
117*753f127fSDimitry Andric       .addCFIIndex(CFIIndex)
118*753f127fSDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
119*753f127fSDimitry Andric 
120*753f127fSDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
121*753f127fSDimitry Andric 
122*753f127fSDimitry Andric   // The frame pointer is callee-saved, and code has been generated for us to
123*753f127fSDimitry Andric   // save it to the stack. We need to skip over the storing of callee-saved
124*753f127fSDimitry Andric   // registers as the frame pointer must be modified after it has been saved
125*753f127fSDimitry Andric   // to the stack, not before.
126*753f127fSDimitry Andric   std::advance(MBBI, CSI.size());
127*753f127fSDimitry Andric 
128*753f127fSDimitry Andric   // Iterate over list of callee-saved registers and emit .cfi_offset
129*753f127fSDimitry Andric   // directives.
130*753f127fSDimitry Andric   for (const auto &Entry : CSI) {
131*753f127fSDimitry Andric     int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
132*753f127fSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
133*753f127fSDimitry Andric         nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));
134*753f127fSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
135*753f127fSDimitry Andric         .addCFIIndex(CFIIndex)
136*753f127fSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
137*753f127fSDimitry Andric   }
138*753f127fSDimitry Andric 
139*753f127fSDimitry Andric   // Generate new FP.
140*753f127fSDimitry Andric   if (hasFP(MF)) {
141*753f127fSDimitry Andric     adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize, MachineInstr::FrameSetup);
142*753f127fSDimitry Andric 
143*753f127fSDimitry Andric     // Emit ".cfi_def_cfa $fp, 0"
144*753f127fSDimitry Andric     unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
145*753f127fSDimitry Andric         nullptr, RI->getDwarfRegNum(FPReg, true), 0));
146*753f127fSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
147*753f127fSDimitry Andric         .addCFIIndex(CFIIndex)
148*753f127fSDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
149*753f127fSDimitry Andric   }
15081ad6265SDimitry Andric }
15181ad6265SDimitry Andric 
15281ad6265SDimitry Andric void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
15381ad6265SDimitry Andric                                           MachineBasicBlock &MBB) const {
154*753f127fSDimitry Andric   const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
155*753f127fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
156*753f127fSDimitry Andric   Register SPReg = LoongArch::R3;
157*753f127fSDimitry Andric 
158*753f127fSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
159*753f127fSDimitry Andric   DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
160*753f127fSDimitry Andric 
161*753f127fSDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
162*753f127fSDimitry Andric   // Skip to before the restores of callee-saved registers.
163*753f127fSDimitry Andric   auto LastFrameDestroy = MBBI;
164*753f127fSDimitry Andric   if (!CSI.empty())
165*753f127fSDimitry Andric     LastFrameDestroy = std::prev(MBBI, CSI.size());
166*753f127fSDimitry Andric 
167*753f127fSDimitry Andric   // Get the number of bytes from FrameInfo.
168*753f127fSDimitry Andric   uint64_t StackSize = MFI.getStackSize();
169*753f127fSDimitry Andric 
170*753f127fSDimitry Andric   // Restore the stack pointer.
171*753f127fSDimitry Andric   if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
172*753f127fSDimitry Andric     assert(hasFP(MF) && "frame pointer should not have been eliminated");
173*753f127fSDimitry Andric     adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, -StackSize,
174*753f127fSDimitry Andric               MachineInstr::FrameDestroy);
175*753f127fSDimitry Andric   }
176*753f127fSDimitry Andric 
177*753f127fSDimitry Andric   // Deallocate stack
178*753f127fSDimitry Andric   adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
179*753f127fSDimitry Andric }
180*753f127fSDimitry Andric 
181*753f127fSDimitry Andric void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
182*753f127fSDimitry Andric                                                   BitVector &SavedRegs,
183*753f127fSDimitry Andric                                                   RegScavenger *RS) const {
184*753f127fSDimitry Andric   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
185*753f127fSDimitry Andric   // Unconditionally spill RA and FP only if the function uses a frame
186*753f127fSDimitry Andric   // pointer.
187*753f127fSDimitry Andric   if (hasFP(MF)) {
188*753f127fSDimitry Andric     SavedRegs.set(LoongArch::R1);
189*753f127fSDimitry Andric     SavedRegs.set(LoongArch::R22);
190*753f127fSDimitry Andric   }
191*753f127fSDimitry Andric   // Mark BP as used if function has dedicated base pointer.
192*753f127fSDimitry Andric   if (hasBP(MF))
193*753f127fSDimitry Andric     SavedRegs.set(LoongArchABI::getBPReg());
194*753f127fSDimitry Andric }
195*753f127fSDimitry Andric 
196*753f127fSDimitry Andric StackOffset LoongArchFrameLowering::getFrameIndexReference(
197*753f127fSDimitry Andric     const MachineFunction &MF, int FI, Register &FrameReg) const {
198*753f127fSDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
199*753f127fSDimitry Andric   const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
200*753f127fSDimitry Andric 
201*753f127fSDimitry Andric   // Callee-saved registers should be referenced relative to the stack
202*753f127fSDimitry Andric   // pointer (positive offset), otherwise use the frame pointer (negative
203*753f127fSDimitry Andric   // offset).
204*753f127fSDimitry Andric   const auto &CSI = MFI.getCalleeSavedInfo();
205*753f127fSDimitry Andric   int MinCSFI = 0;
206*753f127fSDimitry Andric   int MaxCSFI = -1;
207*753f127fSDimitry Andric   StackOffset Offset =
208*753f127fSDimitry Andric       StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
209*753f127fSDimitry Andric                             MFI.getOffsetAdjustment());
210*753f127fSDimitry Andric 
211*753f127fSDimitry Andric   if (CSI.size()) {
212*753f127fSDimitry Andric     MinCSFI = CSI[0].getFrameIdx();
213*753f127fSDimitry Andric     MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
214*753f127fSDimitry Andric   }
215*753f127fSDimitry Andric 
216*753f127fSDimitry Andric   FrameReg = RI->getFrameRegister(MF);
217*753f127fSDimitry Andric   if ((FI >= MinCSFI && FI <= MaxCSFI) || !hasFP(MF)) {
218*753f127fSDimitry Andric     FrameReg = LoongArch::R3;
219*753f127fSDimitry Andric     Offset += StackOffset::getFixed(MFI.getStackSize());
220*753f127fSDimitry Andric   }
221*753f127fSDimitry Andric 
222*753f127fSDimitry Andric   return Offset;
22381ad6265SDimitry Andric }
224