Path: blob/main/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
35269 views
//===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the LoongArch implementation of TargetFrameLowering class.9//10//===----------------------------------------------------------------------===//1112#include "LoongArchFrameLowering.h"13#include "LoongArchMachineFunctionInfo.h"14#include "LoongArchSubtarget.h"15#include "MCTargetDesc/LoongArchBaseInfo.h"16#include "MCTargetDesc/LoongArchMCTargetDesc.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"2425using namespace llvm;2627#define DEBUG_TYPE "loongarch-frame-lowering"2829// Return true if the specified function should have a dedicated frame30// pointer register. This is true if frame pointer elimination is31// disabled, if it needs dynamic stack realignment, if the function has32// variable sized allocas, or if the frame address is taken.33bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const {34const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();3536const MachineFrameInfo &MFI = MF.getFrameInfo();37return MF.getTarget().Options.DisableFramePointerElim(MF) ||38RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||39MFI.isFrameAddressTaken();40}4142bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {43const MachineFrameInfo &MFI = MF.getFrameInfo();44const TargetRegisterInfo *TRI = STI.getRegisterInfo();4546return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);47}4849void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,50MachineBasicBlock::iterator MBBI,51const DebugLoc &DL, Register DestReg,52Register SrcReg, int64_t Val,53MachineInstr::MIFlag Flag) const {54const LoongArchInstrInfo *TII = STI.getInstrInfo();55bool IsLA64 = STI.is64Bit();56unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;5758if (DestReg == SrcReg && Val == 0)59return;6061if (isInt<12>(Val)) {62// addi.w/d $DstReg, $SrcReg, Val63BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)64.addReg(SrcReg)65.addImm(Val)66.setMIFlag(Flag);67return;68}6970// Try to split the offset across two ADDIs. We need to keep the stack pointer71// aligned after each ADDI. We need to determine the maximum value we can put72// in each ADDI. In the negative direction, we can use -2048 which is always73// sufficiently aligned. In the positive direction, we need to find the74// largest 12-bit immediate that is aligned. Exclude -4096 since it can be75// created with LU12I.W.76assert(getStackAlign().value() < 2048 && "Stack alignment too large");77int64_t MaxPosAdjStep = 2048 - getStackAlign().value();78if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) {79int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep;80Val -= FirstAdj;81BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)82.addReg(SrcReg)83.addImm(FirstAdj)84.setMIFlag(Flag);85BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)86.addReg(DestReg, RegState::Kill)87.addImm(Val)88.setMIFlag(Flag);89return;90}9192unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;93if (Val < 0) {94Val = -Val;95Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W;96}9798MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();99Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);100TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag);101BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)102.addReg(SrcReg)103.addReg(ScratchReg, RegState::Kill)104.setMIFlag(Flag);105}106107// Determine the size of the frame and maximum call frame size.108void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {109MachineFrameInfo &MFI = MF.getFrameInfo();110111// Get the number of bytes to allocate from the FrameInfo.112uint64_t FrameSize = MFI.getStackSize();113114// Make sure the frame is aligned.115FrameSize = alignTo(FrameSize, getStackAlign());116117// Update frame info.118MFI.setStackSize(FrameSize);119}120121static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII,122const MachineFunction &MF) {123uint64_t FuncSize = 0;124for (auto &MBB : MF)125for (auto &MI : MBB)126FuncSize += TII->getInstSizeInBytes(MI);127return FuncSize;128}129130static bool needScavSlotForCFR(MachineFunction &MF) {131if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF())132return false;133for (auto &MBB : MF)134for (auto &MI : MBB)135if (MI.getOpcode() == LoongArch::PseudoST_CFR)136return true;137return false;138}139140void LoongArchFrameLowering::processFunctionBeforeFrameFinalized(141MachineFunction &MF, RegScavenger *RS) const {142const LoongArchRegisterInfo *RI = STI.getRegisterInfo();143const TargetRegisterClass &RC = LoongArch::GPRRegClass;144const LoongArchInstrInfo *TII = STI.getInstrInfo();145LoongArchMachineFunctionInfo *LAFI =146MF.getInfo<LoongArchMachineFunctionInfo>();147MachineFrameInfo &MFI = MF.getFrameInfo();148149unsigned ScavSlotsNum = 0;150151// Far branches beyond 27-bit offset require a spill slot for scratch152// register.153bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF));154if (IsLargeFunction)155ScavSlotsNum = 1;156157// estimateStackSize has been observed to under-estimate the final stack158// size, so give ourselves wiggle-room by checking for stack size159// representable an 11-bit signed field rather than 12-bits.160if (!isInt<11>(MFI.estimateStackSize(MF)))161ScavSlotsNum = std::max(ScavSlotsNum, 1u);162163// For CFR spill.164if (needScavSlotForCFR(MF))165++ScavSlotsNum;166167// Create emergency spill slots.168for (unsigned i = 0; i < ScavSlotsNum; ++i) {169int FI = MFI.CreateStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC),170false);171RS->addScavengingFrameIndex(FI);172if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1)173LAFI->setBranchRelaxationSpillFrameIndex(FI);174LLVM_DEBUG(dbgs() << "Allocated FI(" << FI175<< ") as the emergency spill slot.\n");176}177}178179void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,180MachineBasicBlock &MBB) const {181MachineFrameInfo &MFI = MF.getFrameInfo();182auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();183const LoongArchRegisterInfo *RI = STI.getRegisterInfo();184const LoongArchInstrInfo *TII = STI.getInstrInfo();185MachineBasicBlock::iterator MBBI = MBB.begin();186bool IsLA64 = STI.is64Bit();187188Register SPReg = LoongArch::R3;189Register FPReg = LoongArch::R22;190191// Debug location must be unknown since the first debug location is used192// to determine the end of the prologue.193DebugLoc DL;194// All calls are tail calls in GHC calling conv, and functions have no195// prologue/epilogue.196if (MF.getFunction().getCallingConv() == CallingConv::GHC)197return;198// Determine the correct frame layout199determineFrameLayout(MF);200201// First, compute final stack size.202uint64_t StackSize = MFI.getStackSize();203uint64_t RealStackSize = StackSize;204205// Early exit if there is no need to allocate space in the stack.206if (StackSize == 0 && !MFI.adjustsStack())207return;208209uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);210// Split the SP adjustment to reduce the offsets of callee saved spill.211if (FirstSPAdjustAmount)212StackSize = FirstSPAdjustAmount;213214// Adjust stack.215adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);216// Emit ".cfi_def_cfa_offset StackSize".217unsigned CFIIndex =218MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));219BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))220.addCFIIndex(CFIIndex)221.setMIFlag(MachineInstr::FrameSetup);222223const auto &CSI = MFI.getCalleeSavedInfo();224225// The frame pointer is callee-saved, and code has been generated for us to226// save it to the stack. We need to skip over the storing of callee-saved227// registers as the frame pointer must be modified after it has been saved228// to the stack, not before.229std::advance(MBBI, CSI.size());230231// Iterate over list of callee-saved registers and emit .cfi_offset232// directives.233for (const auto &Entry : CSI) {234int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());235unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(236nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));237BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))238.addCFIIndex(CFIIndex)239.setMIFlag(MachineInstr::FrameSetup);240}241242// Generate new FP.243if (hasFP(MF)) {244adjustReg(MBB, MBBI, DL, FPReg, SPReg,245StackSize - LoongArchFI->getVarArgsSaveSize(),246MachineInstr::FrameSetup);247248// Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()"249unsigned CFIIndex = MF.addFrameInst(250MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true),251LoongArchFI->getVarArgsSaveSize()));252BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))253.addCFIIndex(CFIIndex)254.setMIFlag(MachineInstr::FrameSetup);255}256257// Emit the second SP adjustment after saving callee saved registers.258if (FirstSPAdjustAmount) {259uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;260assert(SecondSPAdjustAmount > 0 &&261"SecondSPAdjustAmount should be greater than zero");262adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,263MachineInstr::FrameSetup);264265if (!hasFP(MF)) {266// If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",267// don't emit an sp-based .cfi_def_cfa_offset268// Emit ".cfi_def_cfa_offset RealStackSize"269unsigned CFIIndex = MF.addFrameInst(270MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));271BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))272.addCFIIndex(CFIIndex)273.setMIFlag(MachineInstr::FrameSetup);274}275}276277if (hasFP(MF)) {278// Realign stack.279if (RI->hasStackRealignment(MF)) {280unsigned Align = Log2(MFI.getMaxAlign());281assert(Align > 0 && "The stack realignment size is invalid!");282BuildMI(MBB, MBBI, DL,283TII->get(IsLA64 ? LoongArch::BSTRINS_D : LoongArch::BSTRINS_W),284SPReg)285.addReg(SPReg)286.addReg(LoongArch::R0)287.addImm(Align - 1)288.addImm(0)289.setMIFlag(MachineInstr::FrameSetup);290// FP will be used to restore the frame in the epilogue, so we need291// another base register BP to record SP after re-alignment. SP will292// track the current stack after allocating variable sized objects.293if (hasBP(MF)) {294// move BP, $sp295BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR),296LoongArchABI::getBPReg())297.addReg(SPReg)298.addReg(LoongArch::R0)299.setMIFlag(MachineInstr::FrameSetup);300}301}302}303}304305void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,306MachineBasicBlock &MBB) const {307const LoongArchRegisterInfo *RI = STI.getRegisterInfo();308MachineFrameInfo &MFI = MF.getFrameInfo();309auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();310Register SPReg = LoongArch::R3;311// All calls are tail calls in GHC calling conv, and functions have no312// prologue/epilogue.313if (MF.getFunction().getCallingConv() == CallingConv::GHC)314return;315MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();316DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();317318const auto &CSI = MFI.getCalleeSavedInfo();319// Skip to before the restores of callee-saved registers.320auto LastFrameDestroy = MBBI;321if (!CSI.empty())322LastFrameDestroy = std::prev(MBBI, CSI.size());323324// Get the number of bytes from FrameInfo.325uint64_t StackSize = MFI.getStackSize();326327// Restore the stack pointer.328if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {329assert(hasFP(MF) && "frame pointer should not have been eliminated");330adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22,331-StackSize + LoongArchFI->getVarArgsSaveSize(),332MachineInstr::FrameDestroy);333}334335uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);336if (FirstSPAdjustAmount) {337uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount;338assert(SecondSPAdjustAmount > 0 &&339"SecondSPAdjustAmount should be greater than zero");340341adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount,342MachineInstr::FrameDestroy);343StackSize = FirstSPAdjustAmount;344}345346// Deallocate stack347adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);348}349350// We would like to split the SP adjustment to reduce prologue/epilogue351// as following instructions. In this way, the offset of the callee saved352// register could fit in a single store.353// e.g.354// addi.d $sp, $sp, -2032355// st.d $ra, $sp, 2024356// st.d $fp, $sp, 2016357// addi.d $sp, $sp, -16358uint64_t LoongArchFrameLowering::getFirstSPAdjustAmount(359const MachineFunction &MF) const {360const MachineFrameInfo &MFI = MF.getFrameInfo();361const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();362363// Return the FirstSPAdjustAmount if the StackSize can not fit in a signed364// 12-bit and there exists a callee-saved register needing to be pushed.365if (!isInt<12>(MFI.getStackSize()) && (CSI.size() > 0)) {366// FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will367// cause sp = sp + 2048 in the epilogue to be split into multiple368// instructions. Offsets smaller than 2048 can fit in a single load/store369// instruction, and we have to stick with the stack alignment.370// So (2048 - StackAlign) will satisfy the stack alignment.371return 2048 - getStackAlign().value();372}373return 0;374}375376void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,377BitVector &SavedRegs,378RegScavenger *RS) const {379TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);380// Unconditionally spill RA and FP only if the function uses a frame381// pointer.382if (hasFP(MF)) {383SavedRegs.set(LoongArch::R1);384SavedRegs.set(LoongArch::R22);385}386// Mark BP as used if function has dedicated base pointer.387if (hasBP(MF))388SavedRegs.set(LoongArchABI::getBPReg());389}390391// Do not preserve stack space within prologue for outgoing variables if the392// function contains variable size objects.393// Let eliminateCallFramePseudoInstr preserve stack space for it.394bool LoongArchFrameLowering::hasReservedCallFrame(395const MachineFunction &MF) const {396return !MF.getFrameInfo().hasVarSizedObjects();397}398399// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.400MachineBasicBlock::iterator401LoongArchFrameLowering::eliminateCallFramePseudoInstr(402MachineFunction &MF, MachineBasicBlock &MBB,403MachineBasicBlock::iterator MI) const {404Register SPReg = LoongArch::R3;405DebugLoc DL = MI->getDebugLoc();406407if (!hasReservedCallFrame(MF)) {408// If space has not been reserved for a call frame, ADJCALLSTACKDOWN and409// ADJCALLSTACKUP must be converted to instructions manipulating the stack410// pointer. This is necessary when there is a variable length stack411// allocation (e.g. alloca), which means it's not possible to allocate412// space for outgoing arguments from within the function prologue.413int64_t Amount = MI->getOperand(0).getImm();414415if (Amount != 0) {416// Ensure the stack remains aligned after adjustment.417Amount = alignSPAdjust(Amount);418419if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN)420Amount = -Amount;421422adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);423}424}425426return MBB.erase(MI);427}428429bool LoongArchFrameLowering::spillCalleeSavedRegisters(430MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,431ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {432if (CSI.empty())433return true;434435MachineFunction *MF = MBB.getParent();436const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();437438// Insert the spill to the stack frame.439for (auto &CS : CSI) {440Register Reg = CS.getReg();441// If the register is RA and the return address is taken by method442// LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag.443bool IsKill =444!(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken());445const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);446TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI,447Register());448}449450return true;451}452453StackOffset LoongArchFrameLowering::getFrameIndexReference(454const MachineFunction &MF, int FI, Register &FrameReg) const {455const MachineFrameInfo &MFI = MF.getFrameInfo();456const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();457auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();458uint64_t StackSize = MFI.getStackSize();459uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);460461// Callee-saved registers should be referenced relative to the stack462// pointer (positive offset), otherwise use the frame pointer (negative463// offset).464const auto &CSI = MFI.getCalleeSavedInfo();465int MinCSFI = 0;466int MaxCSFI = -1;467StackOffset Offset =468StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +469MFI.getOffsetAdjustment());470471if (CSI.size()) {472MinCSFI = CSI[0].getFrameIdx();473MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();474}475476if (FI >= MinCSFI && FI <= MaxCSFI) {477FrameReg = LoongArch::R3;478if (FirstSPAdjustAmount)479Offset += StackOffset::getFixed(FirstSPAdjustAmount);480else481Offset += StackOffset::getFixed(StackSize);482} else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {483// If the stack was realigned, the frame pointer is set in order to allow484// SP to be restored, so we need another base register to record the stack485// after realignment.486FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3;487Offset += StackOffset::getFixed(StackSize);488} else {489FrameReg = RI->getFrameRegister(MF);490if (hasFP(MF))491Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize());492else493Offset += StackOffset::getFixed(StackSize);494}495496return Offset;497}498499bool LoongArchFrameLowering::enableShrinkWrapping(500const MachineFunction &MF) const {501// Keep the conventional code flow when not optimizing.502if (MF.getFunction().hasOptNone())503return false;504505return true;506}507508509