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