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. 33 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 42 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 49 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. 74 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 87 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 152 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 181 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 196 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