1 //===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the LoongArch implementation of TargetFrameLowering class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "LoongArchFrameLowering.h"
14 #include "LoongArchMachineFunctionInfo.h"
15 #include "LoongArchSubtarget.h"
16 #include "MCTargetDesc/LoongArchBaseInfo.h"
17 #include "llvm/CodeGen/MachineFrameInfo.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/CodeGen/MachineInstrBuilder.h"
20 #include "llvm/CodeGen/MachineRegisterInfo.h"
21 #include "llvm/CodeGen/RegisterScavenging.h"
22 #include "llvm/IR/DiagnosticInfo.h"
23 #include "llvm/MC/MCDwarf.h"
24
25 using namespace llvm;
26
27 #define DEBUG_TYPE "loongarch-frame-lowering"
28
29 // Return true if the specified function should have a dedicated frame
30 // pointer register. This is true if frame pointer elimination is
31 // disabled, if it needs dynamic stack realignment, if the function has
32 // variable sized allocas, or if the frame address is taken.
hasFP(const MachineFunction & MF) const33 bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const {
34 const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
35
36 const MachineFrameInfo &MFI = MF.getFrameInfo();
37 return MF.getTarget().Options.DisableFramePointerElim(MF) ||
38 RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
39 MFI.isFrameAddressTaken();
40 }
41
hasBP(const MachineFunction & MF) const42 bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {
43 const MachineFrameInfo &MFI = MF.getFrameInfo();
44 const TargetRegisterInfo *TRI = STI.getRegisterInfo();
45
46 return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);
47 }
48
adjustReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,Register DestReg,Register SrcReg,int64_t Val,MachineInstr::MIFlag Flag) const49 void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,
50 MachineBasicBlock::iterator MBBI,
51 const DebugLoc &DL, Register DestReg,
52 Register SrcReg, int64_t Val,
53 MachineInstr::MIFlag Flag) const {
54 const LoongArchInstrInfo *TII = STI.getInstrInfo();
55 bool IsLA64 = STI.is64Bit();
56
57 if (DestReg == SrcReg && Val == 0)
58 return;
59
60 if (isInt<12>(Val)) {
61 // addi.w/d $DstReg, $SrcReg, Val
62 BuildMI(MBB, MBBI, DL,
63 TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), DestReg)
64 .addReg(SrcReg)
65 .addImm(Val)
66 .setMIFlag(Flag);
67 return;
68 }
69
70 report_fatal_error("adjustReg cannot yet handle adjustments >12 bits");
71 }
72
73 // Determine the size of the frame and maximum call frame size.
determineFrameLayout(MachineFunction & MF) const74 void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {
75 MachineFrameInfo &MFI = MF.getFrameInfo();
76
77 // Get the number of bytes to allocate from the FrameInfo.
78 uint64_t FrameSize = MFI.getStackSize();
79
80 // Make sure the frame is aligned.
81 FrameSize = alignTo(FrameSize, getStackAlign());
82
83 // Update frame info.
84 MFI.setStackSize(FrameSize);
85 }
86
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const87 void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
88 MachineBasicBlock &MBB) const {
89 MachineFrameInfo &MFI = MF.getFrameInfo();
90 const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
91 const LoongArchInstrInfo *TII = STI.getInstrInfo();
92 MachineBasicBlock::iterator MBBI = MBB.begin();
93
94 Register SPReg = LoongArch::R3;
95 Register FPReg = LoongArch::R22;
96
97 // Debug location must be unknown since the first debug location is used
98 // to determine the end of the prologue.
99 DebugLoc DL;
100
101 // Determine the correct frame layout
102 determineFrameLayout(MF);
103
104 // First, compute final stack size.
105 uint64_t StackSize = MFI.getStackSize();
106
107 // Early exit if there is no need to allocate space in the stack.
108 if (StackSize == 0 && !MFI.adjustsStack())
109 return;
110
111 // Adjust stack.
112 adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
113 // Emit ".cfi_def_cfa_offset StackSize".
114 unsigned CFIIndex =
115 MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
116 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
117 .addCFIIndex(CFIIndex)
118 .setMIFlag(MachineInstr::FrameSetup);
119
120 const auto &CSI = MFI.getCalleeSavedInfo();
121
122 // The frame pointer is callee-saved, and code has been generated for us to
123 // save it to the stack. We need to skip over the storing of callee-saved
124 // registers as the frame pointer must be modified after it has been saved
125 // to the stack, not before.
126 std::advance(MBBI, CSI.size());
127
128 // Iterate over list of callee-saved registers and emit .cfi_offset
129 // directives.
130 for (const auto &Entry : CSI) {
131 int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
132 unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
133 nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));
134 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
135 .addCFIIndex(CFIIndex)
136 .setMIFlag(MachineInstr::FrameSetup);
137 }
138
139 // Generate new FP.
140 if (hasFP(MF)) {
141 adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize, MachineInstr::FrameSetup);
142
143 // Emit ".cfi_def_cfa $fp, 0"
144 unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
145 nullptr, RI->getDwarfRegNum(FPReg, true), 0));
146 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
147 .addCFIIndex(CFIIndex)
148 .setMIFlag(MachineInstr::FrameSetup);
149 }
150 }
151
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const152 void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
153 MachineBasicBlock &MBB) const {
154 const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
155 MachineFrameInfo &MFI = MF.getFrameInfo();
156 Register SPReg = LoongArch::R3;
157
158 MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
159 DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
160
161 const auto &CSI = MFI.getCalleeSavedInfo();
162 // Skip to before the restores of callee-saved registers.
163 auto LastFrameDestroy = MBBI;
164 if (!CSI.empty())
165 LastFrameDestroy = std::prev(MBBI, CSI.size());
166
167 // Get the number of bytes from FrameInfo.
168 uint64_t StackSize = MFI.getStackSize();
169
170 // Restore the stack pointer.
171 if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
172 assert(hasFP(MF) && "frame pointer should not have been eliminated");
173 adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, -StackSize,
174 MachineInstr::FrameDestroy);
175 }
176
177 // Deallocate stack
178 adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
179 }
180
determineCalleeSaves(MachineFunction & MF,BitVector & SavedRegs,RegScavenger * RS) const181 void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
182 BitVector &SavedRegs,
183 RegScavenger *RS) const {
184 TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
185 // Unconditionally spill RA and FP only if the function uses a frame
186 // pointer.
187 if (hasFP(MF)) {
188 SavedRegs.set(LoongArch::R1);
189 SavedRegs.set(LoongArch::R22);
190 }
191 // Mark BP as used if function has dedicated base pointer.
192 if (hasBP(MF))
193 SavedRegs.set(LoongArchABI::getBPReg());
194 }
195
getFrameIndexReference(const MachineFunction & MF,int FI,Register & FrameReg) const196 StackOffset LoongArchFrameLowering::getFrameIndexReference(
197 const MachineFunction &MF, int FI, Register &FrameReg) const {
198 const MachineFrameInfo &MFI = MF.getFrameInfo();
199 const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
200
201 // Callee-saved registers should be referenced relative to the stack
202 // pointer (positive offset), otherwise use the frame pointer (negative
203 // offset).
204 const auto &CSI = MFI.getCalleeSavedInfo();
205 int MinCSFI = 0;
206 int MaxCSFI = -1;
207 StackOffset Offset =
208 StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
209 MFI.getOffsetAdjustment());
210
211 if (CSI.size()) {
212 MinCSFI = CSI[0].getFrameIdx();
213 MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
214 }
215
216 FrameReg = RI->getFrameRegister(MF);
217 if ((FI >= MinCSFI && FI <= MaxCSFI) || !hasFP(MF)) {
218 FrameReg = LoongArch::R3;
219 Offset += StackOffset::getFixed(MFI.getStackSize());
220 }
221
222 return Offset;
223 }
224