| //===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains the LoongArch implementation of TargetFrameLowering class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "LoongArchFrameLowering.h" | |
| #include "LoongArchMachineFunctionInfo.h" | |
| #include "LoongArchSubtarget.h" | |
| #include "MCTargetDesc/LoongArchBaseInfo.h" | |
| #include "MCTargetDesc/LoongArchMCTargetDesc.h" | |
| #include "llvm/CodeGen/MachineFrameInfo.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/RegisterScavenging.h" | |
| #include "llvm/IR/DiagnosticInfo.h" | |
| #include "llvm/MC/MCDwarf.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "loongarch-frame-lowering" | |
| // Return true if the specified function should have a dedicated frame | |
| // pointer register. This is true if frame pointer elimination is | |
| // disabled, if it needs dynamic stack realignment, if the function has | |
| // variable sized allocas, or if the frame address is taken. | |
| bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const { | |
| const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); | |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| return MF.getTarget().Options.DisableFramePointerElim(MF) || | |
| RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || | |
| MFI.isFrameAddressTaken(); | |
| } | |
| bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const { | |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| const TargetRegisterInfo *TRI = STI.getRegisterInfo(); | |
| return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF); | |
| } | |
| void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MBBI, | |
| const DebugLoc &DL, Register DestReg, | |
| Register SrcReg, int64_t Val, | |
| MachineInstr::MIFlag Flag) const { | |
| const LoongArchInstrInfo *TII = STI.getInstrInfo(); | |
| bool IsLA64 = STI.is64Bit(); | |
| unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W; | |
| if (DestReg == SrcReg && Val == 0) | |
| return; | |
| if (isInt<12>(Val)) { | |
| // addi.w/d $DstReg, $SrcReg, Val | |
| BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) | |
| .addReg(SrcReg) | |
| .addImm(Val) | |
| .setMIFlag(Flag); | |
| return; | |
| } | |
| // Try to split the offset across two ADDIs. We need to keep the stack pointer | |
| // aligned after each ADDI. We need to determine the maximum value we can put | |
| // in each ADDI. In the negative direction, we can use -2048 which is always | |
| // sufficiently aligned. In the positive direction, we need to find the | |
| // largest 12-bit immediate that is aligned. Exclude -4096 since it can be | |
| // created with LU12I.W. | |
| assert(getStackAlign().value() < 2048 && "Stack alignment too large"); | |
| int64_t MaxPosAdjStep = 2048 - getStackAlign().value(); | |
| if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) { | |
| int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep; | |
| Val -= FirstAdj; | |
| BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) | |
| .addReg(SrcReg) | |
| .addImm(FirstAdj) | |
| .setMIFlag(Flag); | |
| BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) | |
| .addReg(DestReg, RegState::Kill) | |
| .addImm(Val) | |
| .setMIFlag(Flag); | |
| return; | |
| } | |
| unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W; | |
| if (Val < 0) { | |
| Val = -Val; | |
| Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W; | |
| } | |
| MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); | |
| Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); | |
| TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag); | |
| BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) | |
| .addReg(SrcReg) | |
| .addReg(ScratchReg, RegState::Kill) | |
| .setMIFlag(Flag); | |
| } | |
| // Determine the size of the frame and maximum call frame size. | |
| void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const { | |
| MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| // Get the number of bytes to allocate from the FrameInfo. | |
| uint64_t FrameSize = MFI.getStackSize(); | |
| // Make sure the frame is aligned. | |
| FrameSize = alignTo(FrameSize, getStackAlign()); | |
| // Update frame info. | |
| MFI.setStackSize(FrameSize); | |
| } | |
| static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII, | |
| const MachineFunction &MF) { | |
| uint64_t FuncSize = 0; | |
| for (auto &MBB : MF) | |
| for (auto &MI : MBB) | |
| FuncSize += TII->getInstSizeInBytes(MI); | |
| return FuncSize; | |
| } | |
| static bool needScavSlotForCFR(MachineFunction &MF) { | |
| if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF()) | |
| return false; | |
| for (auto &MBB : MF) | |
| for (auto &MI : MBB) | |
| if (MI.getOpcode() == LoongArch::PseudoST_CFR) | |
| return true; | |
| return false; | |
| } | |
| void LoongArchFrameLowering::processFunctionBeforeFrameFinalized( | |
| MachineFunction &MF, RegScavenger *RS) const { | |
| const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); | |
| const TargetRegisterClass &RC = LoongArch::GPRRegClass; | |
| const LoongArchInstrInfo *TII = STI.getInstrInfo(); | |
| LoongArchMachineFunctionInfo *LAFI = | |
| MF.getInfo<LoongArchMachineFunctionInfo>(); | |
| MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| unsigned ScavSlotsNum = 0; | |
| // Far branches beyond 27-bit offset require a spill slot for scratch register. | |
| bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF)); | |
| if (IsLargeFunction) | |
| ScavSlotsNum = 1; | |
| // estimateStackSize has been observed to under-estimate the final stack | |
| // size, so give ourselves wiggle-room by checking for stack size | |
| // representable an 11-bit signed field rather than 12-bits. | |
| if (!isInt<11>(MFI.estimateStackSize(MF))) | |
| ScavSlotsNum = std::max(ScavSlotsNum, 1u); | |
| // For CFR spill. | |
| if (needScavSlotForCFR(MF)) | |
| ++ScavSlotsNum; | |
| // Create emergency spill slots. | |
| for (unsigned i = 0; i < ScavSlotsNum; ++i) { | |
| int FI = MFI.CreateStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC), | |
| false); | |
| RS->addScavengingFrameIndex(FI); | |
| if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1) | |
| LAFI->setBranchRelaxationSpillFrameIndex(FI); | |
| LLVM_DEBUG(dbgs() << "Allocated FI(" << FI | |
| << ") as the emergency spill slot.\n"); | |
| } | |
| } | |
| void LoongArchFrameLowering::emitPrologue(MachineFunction &MF, | |
| MachineBasicBlock &MBB) const { | |
| MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); | |
| const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); | |
| const LoongArchInstrInfo *TII = STI.getInstrInfo(); | |
| MachineBasicBlock::iterator MBBI = MBB.begin(); | |
| bool IsLA64 = STI.is64Bit(); | |
| Register SPReg = LoongArch::R3; | |
| Register FPReg = LoongArch::R22; | |
| // Debug location must be unknown since the first debug location is used | |
| // to determine the end of the prologue. | |
| DebugLoc DL; | |
| // All calls are tail calls in GHC calling conv, and functions have no | |
| // prologue/epilogue. | |
| if (MF.getFunction().getCallingConv() == CallingConv::GHC) | |
| return; | |
| // Determine the correct frame layout | |
| determineFrameLayout(MF); | |
| // First, compute final stack size. | |
| uint64_t StackSize = MFI.getStackSize(); | |
| uint64_t RealStackSize = StackSize; | |
| // Early exit if there is no need to allocate space in the stack. | |
| if (StackSize == 0 && !MFI.adjustsStack()) | |
| return; | |
| uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF, true); | |
| uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount; | |
| // Split the SP adjustment to reduce the offsets of callee saved spill. | |
| if (FirstSPAdjustAmount) | |
| StackSize = FirstSPAdjustAmount; | |
| // Adjust stack. | |
| adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); | |
| if (FirstSPAdjustAmount != 2048 || SecondSPAdjustAmount == 0) { | |
| // Emit ".cfi_def_cfa_offset StackSize". | |
| unsigned CFIIndex = | |
| MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); | |
| BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | |
| .addCFIIndex(CFIIndex) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| } | |
| const auto &CSI = MFI.getCalleeSavedInfo(); | |
| // The frame pointer is callee-saved, and code has been generated for us to | |
| // save it to the stack. We need to skip over the storing of callee-saved | |
| // registers as the frame pointer must be modified after it has been saved | |
| // to the stack, not before. | |
| std::advance(MBBI, CSI.size()); | |
| // Iterate over list of callee-saved registers and emit .cfi_offset | |
| // directives. | |
| for (const auto &Entry : CSI) { | |
| int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); | |
| unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( | |
| nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset)); | |
| BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | |
| .addCFIIndex(CFIIndex) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| } | |
| // Generate new FP. | |
| if (hasFP(MF)) { | |
| adjustReg(MBB, MBBI, DL, FPReg, SPReg, | |
| StackSize - LoongArchFI->getVarArgsSaveSize(), | |
| MachineInstr::FrameSetup); | |
| // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()" | |
| unsigned CFIIndex = MF.addFrameInst( | |
| MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true), | |
| LoongArchFI->getVarArgsSaveSize())); | |
| BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | |
| .addCFIIndex(CFIIndex) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| } | |
| // Emit the second SP adjustment after saving callee saved registers. | |
| if (FirstSPAdjustAmount && SecondSPAdjustAmount) { | |
| if (hasFP(MF)) { | |
| assert(SecondSPAdjustAmount > 0 && | |
| "SecondSPAdjustAmount should be greater than zero"); | |
| adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, | |
| MachineInstr::FrameSetup); | |
| } else { | |
| // FIXME: RegScavenger will place the spill instruction before the | |
| // prologue if a VReg is created in the prologue. This will pollute the | |
| // caller's stack data. Therefore, until there is better way, we just use | |
| // the `addi.w/d` instruction for stack adjustment to ensure that VReg | |
| // will not be created. | |
| for (int Val = SecondSPAdjustAmount; Val > 0; Val -= 2048) | |
| BuildMI(MBB, MBBI, DL, | |
| TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), SPReg) | |
| .addReg(SPReg) | |
| .addImm(Val < 2048 ? -Val : -2048) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", | |
| // don't emit an sp-based .cfi_def_cfa_offset | |
| // Emit ".cfi_def_cfa_offset RealStackSize" | |
| unsigned CFIIndex = MF.addFrameInst( | |
| MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize)); | |
| BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | |
| .addCFIIndex(CFIIndex) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| } | |
| } | |
| if (hasFP(MF)) { | |
| // Realign stack. | |
| if (RI->hasStackRealignment(MF)) { | |
| unsigned ShiftAmount = Log2(MFI.getMaxAlign()); | |
| Register VR = | |
| MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); | |
| BuildMI(MBB, MBBI, DL, | |
| TII->get(IsLA64 ? LoongArch::SRLI_D : LoongArch::SRLI_W), VR) | |
| .addReg(SPReg) | |
| .addImm(ShiftAmount) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| BuildMI(MBB, MBBI, DL, | |
| TII->get(IsLA64 ? LoongArch::SLLI_D : LoongArch::SLLI_W), SPReg) | |
| .addReg(VR) | |
| .addImm(ShiftAmount) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| // FP will be used to restore the frame in the epilogue, so we need | |
| // another base register BP to record SP after re-alignment. SP will | |
| // track the current stack after allocating variable sized objects. | |
| if (hasBP(MF)) { | |
| // move BP, $sp | |
| BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR), | |
| LoongArchABI::getBPReg()) | |
| .addReg(SPReg) | |
| .addReg(LoongArch::R0) | |
| .setMIFlag(MachineInstr::FrameSetup); | |
| } | |
| } | |
| } | |
| } | |
| void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF, | |
| MachineBasicBlock &MBB) const { | |
| const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); | |
| MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); | |
| Register SPReg = LoongArch::R3; | |
| // All calls are tail calls in GHC calling conv, and functions have no | |
| // prologue/epilogue. | |
| if (MF.getFunction().getCallingConv() == CallingConv::GHC) | |
| return; | |
| MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); | |
| DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); | |
| const auto &CSI = MFI.getCalleeSavedInfo(); | |
| // Skip to before the restores of callee-saved registers. | |
| auto LastFrameDestroy = MBBI; | |
| if (!CSI.empty()) | |
| LastFrameDestroy = std::prev(MBBI, CSI.size()); | |
| // Get the number of bytes from FrameInfo. | |
| uint64_t StackSize = MFI.getStackSize(); | |
| // Restore the stack pointer. | |
| if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) { | |
| assert(hasFP(MF) && "frame pointer should not have been eliminated"); | |
| adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, | |
| -StackSize + LoongArchFI->getVarArgsSaveSize(), | |
| MachineInstr::FrameDestroy); | |
| } | |
| uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); | |
| if (FirstSPAdjustAmount) { | |
| uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount; | |
| assert(SecondSPAdjustAmount > 0 && | |
| "SecondSPAdjustAmount should be greater than zero"); | |
| adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, | |
| MachineInstr::FrameDestroy); | |
| StackSize = FirstSPAdjustAmount; | |
| } | |
| // Deallocate stack | |
| adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); | |
| } | |
| // We would like to split the SP adjustment to reduce prologue/epilogue | |
| // as following instructions. In this way, the offset of the callee saved | |
| // register could fit in a single store. | |
| // e.g. | |
| // addi.d $sp, $sp, -2032 | |
| // st.d $ra, $sp, 2024 | |
| // st.d $fp, $sp, 2016 | |
| // addi.d $sp, $sp, -16 | |
| uint64_t | |
| LoongArchFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF, | |
| bool IsPrologue) const { | |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); | |
| // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed | |
| // 12-bit and there exists a callee-saved register needing to be pushed. | |
| if (!isInt<12>(MFI.getStackSize())) { | |
| // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will | |
| // cause sp = sp + 2048 in the epilogue to be split into multiple | |
| // instructions. Offsets smaller than 2048 can fit in a single load/store | |
| // instruction, and we have to stick with the stack alignment. | |
| // So (2048 - StackAlign) will satisfy the stack alignment. | |
| // | |
| // FIXME: This place may seem odd. When using multiple ADDI instructions to | |
| // adjust the stack in Prologue, and there are no callee-saved registers, we | |
| // can take advantage of the logic of split sp ajustment to reduce code | |
| // changes. | |
| return CSI.size() > 0 ? 2048 - getStackAlign().value() | |
| : (IsPrologue ? 2048 : 0); | |
| } | |
| return 0; | |
| } | |
| void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF, | |
| BitVector &SavedRegs, | |
| RegScavenger *RS) const { | |
| TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); | |
| // Unconditionally spill RA and FP only if the function uses a frame | |
| // pointer. | |
| if (hasFP(MF)) { | |
| SavedRegs.set(LoongArch::R1); | |
| SavedRegs.set(LoongArch::R22); | |
| } | |
| // Mark BP as used if function has dedicated base pointer. | |
| if (hasBP(MF)) | |
| SavedRegs.set(LoongArchABI::getBPReg()); | |
| } | |
| // Do not preserve stack space within prologue for outgoing variables if the | |
| // function contains variable size objects. | |
| // Let eliminateCallFramePseudoInstr preserve stack space for it. | |
| bool LoongArchFrameLowering::hasReservedCallFrame( | |
| const MachineFunction &MF) const { | |
| return !MF.getFrameInfo().hasVarSizedObjects(); | |
| } | |
| // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. | |
| MachineBasicBlock::iterator | |
| LoongArchFrameLowering::eliminateCallFramePseudoInstr( | |
| MachineFunction &MF, MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MI) const { | |
| Register SPReg = LoongArch::R3; | |
| DebugLoc DL = MI->getDebugLoc(); | |
| if (!hasReservedCallFrame(MF)) { | |
| // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and | |
| // ADJCALLSTACKUP must be converted to instructions manipulating the stack | |
| // pointer. This is necessary when there is a variable length stack | |
| // allocation (e.g. alloca), which means it's not possible to allocate | |
| // space for outgoing arguments from within the function prologue. | |
| int64_t Amount = MI->getOperand(0).getImm(); | |
| if (Amount != 0) { | |
| // Ensure the stack remains aligned after adjustment. | |
| Amount = alignSPAdjust(Amount); | |
| if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN) | |
| Amount = -Amount; | |
| adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); | |
| } | |
| } | |
| return MBB.erase(MI); | |
| } | |
| bool LoongArchFrameLowering::spillCalleeSavedRegisters( | |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, | |
| ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { | |
| if (CSI.empty()) | |
| return true; | |
| MachineFunction *MF = MBB.getParent(); | |
| const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); | |
| // Insert the spill to the stack frame. | |
| for (auto &CS : CSI) { | |
| Register Reg = CS.getReg(); | |
| // If the register is RA and the return address is taken by method | |
| // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag. | |
| bool IsKill = | |
| !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken()); | |
| const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); | |
| TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI, | |
| Register()); | |
| } | |
| return true; | |
| } | |
| StackOffset LoongArchFrameLowering::getFrameIndexReference( | |
| const MachineFunction &MF, int FI, Register &FrameReg) const { | |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); | |
| const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); | |
| auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); | |
| uint64_t StackSize = MFI.getStackSize(); | |
| uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); | |
| // Callee-saved registers should be referenced relative to the stack | |
| // pointer (positive offset), otherwise use the frame pointer (negative | |
| // offset). | |
| const auto &CSI = MFI.getCalleeSavedInfo(); | |
| int MinCSFI = 0; | |
| int MaxCSFI = -1; | |
| StackOffset Offset = | |
| StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + | |
| MFI.getOffsetAdjustment()); | |
| if (CSI.size()) { | |
| MinCSFI = CSI[0].getFrameIdx(); | |
| MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); | |
| } | |
| if (FI >= MinCSFI && FI <= MaxCSFI) { | |
| FrameReg = LoongArch::R3; | |
| if (FirstSPAdjustAmount) | |
| Offset += StackOffset::getFixed(FirstSPAdjustAmount); | |
| else | |
| Offset += StackOffset::getFixed(StackSize); | |
| } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { | |
| // If the stack was realigned, the frame pointer is set in order to allow | |
| // SP to be restored, so we need another base register to record the stack | |
| // after realignment. | |
| FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3; | |
| Offset += StackOffset::getFixed(StackSize); | |
| } else { | |
| FrameReg = RI->getFrameRegister(MF); | |
| if (hasFP(MF)) | |
| Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize()); | |
| else | |
| Offset += StackOffset::getFixed(StackSize); | |
| } | |
| return Offset; | |
| } |