133388ae8SLu Weining //===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==// 233388ae8SLu Weining // 333388ae8SLu Weining // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 433388ae8SLu Weining // See https://llvm.org/LICENSE.txt for license information. 533388ae8SLu Weining // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 633388ae8SLu Weining // 733388ae8SLu Weining //===----------------------------------------------------------------------===// 833388ae8SLu Weining // 933388ae8SLu Weining // This file contains the LoongArch implementation of TargetFrameLowering class. 1033388ae8SLu Weining // 1133388ae8SLu Weining //===----------------------------------------------------------------------===// 1233388ae8SLu Weining 1333388ae8SLu Weining #include "LoongArchFrameLowering.h" 14c2d1d9f9Swanglei #include "LoongArchMachineFunctionInfo.h" 1533388ae8SLu Weining #include "LoongArchSubtarget.h" 16c2d1d9f9Swanglei #include "MCTargetDesc/LoongArchBaseInfo.h" 170e4378c5Swanglei #include "MCTargetDesc/LoongArchMCTargetDesc.h" 1833388ae8SLu Weining #include "llvm/CodeGen/MachineFrameInfo.h" 1933388ae8SLu Weining #include "llvm/CodeGen/MachineFunction.h" 2033388ae8SLu Weining #include "llvm/CodeGen/MachineInstrBuilder.h" 2133388ae8SLu Weining #include "llvm/CodeGen/MachineRegisterInfo.h" 2233388ae8SLu Weining #include "llvm/CodeGen/RegisterScavenging.h" 2333388ae8SLu Weining #include "llvm/IR/DiagnosticInfo.h" 2433388ae8SLu Weining #include "llvm/MC/MCDwarf.h" 2533388ae8SLu Weining 2633388ae8SLu Weining using namespace llvm; 2733388ae8SLu Weining 2833388ae8SLu Weining #define DEBUG_TYPE "loongarch-frame-lowering" 2933388ae8SLu Weining 3033388ae8SLu Weining // Return true if the specified function should have a dedicated frame 3133388ae8SLu Weining // pointer register. This is true if frame pointer elimination is 3233388ae8SLu Weining // disabled, if it needs dynamic stack realignment, if the function has 3333388ae8SLu Weining // variable sized allocas, or if the frame address is taken. 34ad4a582fSAlex Rønne Petersen bool LoongArchFrameLowering::hasFPImpl(const MachineFunction &MF) const { 3533388ae8SLu Weining const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 3633388ae8SLu Weining 3733388ae8SLu Weining const MachineFrameInfo &MFI = MF.getFrameInfo(); 3833388ae8SLu Weining return MF.getTarget().Options.DisableFramePointerElim(MF) || 3933388ae8SLu Weining RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || 4033388ae8SLu Weining MFI.isFrameAddressTaken(); 4133388ae8SLu Weining } 4233388ae8SLu Weining 4333388ae8SLu Weining bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const { 4433388ae8SLu Weining const MachineFrameInfo &MFI = MF.getFrameInfo(); 4533388ae8SLu Weining const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 4633388ae8SLu Weining 4733388ae8SLu Weining return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF); 4833388ae8SLu Weining } 4933388ae8SLu Weining 50c2d1d9f9Swanglei void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB, 51c2d1d9f9Swanglei MachineBasicBlock::iterator MBBI, 52c2d1d9f9Swanglei const DebugLoc &DL, Register DestReg, 53c2d1d9f9Swanglei Register SrcReg, int64_t Val, 54c2d1d9f9Swanglei MachineInstr::MIFlag Flag) const { 55c2d1d9f9Swanglei const LoongArchInstrInfo *TII = STI.getInstrInfo(); 56c2d1d9f9Swanglei bool IsLA64 = STI.is64Bit(); 57c2a44b59SWANG Xuerui unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W; 58c2d1d9f9Swanglei 59c2d1d9f9Swanglei if (DestReg == SrcReg && Val == 0) 60c2d1d9f9Swanglei return; 61c2d1d9f9Swanglei 62c2d1d9f9Swanglei if (isInt<12>(Val)) { 63c2d1d9f9Swanglei // addi.w/d $DstReg, $SrcReg, Val 64c2a44b59SWANG Xuerui BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) 65c2d1d9f9Swanglei .addReg(SrcReg) 66c2d1d9f9Swanglei .addImm(Val) 67c2d1d9f9Swanglei .setMIFlag(Flag); 68c2d1d9f9Swanglei return; 69c2d1d9f9Swanglei } 70c2d1d9f9Swanglei 71c2a44b59SWANG Xuerui // Try to split the offset across two ADDIs. We need to keep the stack pointer 72c2a44b59SWANG Xuerui // aligned after each ADDI. We need to determine the maximum value we can put 73c2a44b59SWANG Xuerui // in each ADDI. In the negative direction, we can use -2048 which is always 74c2a44b59SWANG Xuerui // sufficiently aligned. In the positive direction, we need to find the 75c2a44b59SWANG Xuerui // largest 12-bit immediate that is aligned. Exclude -4096 since it can be 76c2a44b59SWANG Xuerui // created with LU12I.W. 77c2a44b59SWANG Xuerui assert(getStackAlign().value() < 2048 && "Stack alignment too large"); 78c2a44b59SWANG Xuerui int64_t MaxPosAdjStep = 2048 - getStackAlign().value(); 79c2a44b59SWANG Xuerui if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) { 80c2a44b59SWANG Xuerui int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep; 81c2a44b59SWANG Xuerui Val -= FirstAdj; 82c2a44b59SWANG Xuerui BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) 83c2a44b59SWANG Xuerui .addReg(SrcReg) 84c2a44b59SWANG Xuerui .addImm(FirstAdj) 85c2a44b59SWANG Xuerui .setMIFlag(Flag); 86c2a44b59SWANG Xuerui BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) 87c2a44b59SWANG Xuerui .addReg(DestReg, RegState::Kill) 88c2a44b59SWANG Xuerui .addImm(Val) 89c2a44b59SWANG Xuerui .setMIFlag(Flag); 90c2a44b59SWANG Xuerui return; 91c2a44b59SWANG Xuerui } 92c2a44b59SWANG Xuerui 93c2a44b59SWANG Xuerui unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W; 94c2a44b59SWANG Xuerui if (Val < 0) { 95c2a44b59SWANG Xuerui Val = -Val; 96c2a44b59SWANG Xuerui Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W; 97c2a44b59SWANG Xuerui } 98c2a44b59SWANG Xuerui 99c2a44b59SWANG Xuerui MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); 100c2a44b59SWANG Xuerui Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 101c2a44b59SWANG Xuerui TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag); 102c2a44b59SWANG Xuerui BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) 103c2a44b59SWANG Xuerui .addReg(SrcReg) 104c2a44b59SWANG Xuerui .addReg(ScratchReg, RegState::Kill) 105c2a44b59SWANG Xuerui .setMIFlag(Flag); 106c2d1d9f9Swanglei } 107c2d1d9f9Swanglei 108c2d1d9f9Swanglei // Determine the size of the frame and maximum call frame size. 109c2d1d9f9Swanglei void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const { 110c2d1d9f9Swanglei MachineFrameInfo &MFI = MF.getFrameInfo(); 111c2d1d9f9Swanglei 112c2d1d9f9Swanglei // Get the number of bytes to allocate from the FrameInfo. 113c2d1d9f9Swanglei uint64_t FrameSize = MFI.getStackSize(); 114c2d1d9f9Swanglei 115c2d1d9f9Swanglei // Make sure the frame is aligned. 116c2d1d9f9Swanglei FrameSize = alignTo(FrameSize, getStackAlign()); 117c2d1d9f9Swanglei 118c2d1d9f9Swanglei // Update frame info. 119c2d1d9f9Swanglei MFI.setStackSize(FrameSize); 120c2d1d9f9Swanglei } 121c2d1d9f9Swanglei 12203d07e18SXiaodong Liu static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII, 12303d07e18SXiaodong Liu const MachineFunction &MF) { 12403d07e18SXiaodong Liu uint64_t FuncSize = 0; 12503d07e18SXiaodong Liu for (auto &MBB : MF) 12603d07e18SXiaodong Liu for (auto &MI : MBB) 12703d07e18SXiaodong Liu FuncSize += TII->getInstSizeInBytes(MI); 12803d07e18SXiaodong Liu return FuncSize; 12903d07e18SXiaodong Liu } 13003d07e18SXiaodong Liu 1310e4378c5Swanglei static bool needScavSlotForCFR(MachineFunction &MF) { 1320e4378c5Swanglei if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF()) 1330e4378c5Swanglei return false; 1340e4378c5Swanglei for (auto &MBB : MF) 1350e4378c5Swanglei for (auto &MI : MBB) 1360e4378c5Swanglei if (MI.getOpcode() == LoongArch::PseudoST_CFR) 1370e4378c5Swanglei return true; 1380e4378c5Swanglei return false; 1390e4378c5Swanglei } 1400e4378c5Swanglei 1414e2364a2Swanglei void LoongArchFrameLowering::processFunctionBeforeFrameFinalized( 1424e2364a2Swanglei MachineFunction &MF, RegScavenger *RS) const { 1434e2364a2Swanglei const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); 1444e2364a2Swanglei const TargetRegisterClass &RC = LoongArch::GPRRegClass; 14503d07e18SXiaodong Liu const LoongArchInstrInfo *TII = STI.getInstrInfo(); 14603d07e18SXiaodong Liu LoongArchMachineFunctionInfo *LAFI = 14703d07e18SXiaodong Liu MF.getInfo<LoongArchMachineFunctionInfo>(); 1484e2364a2Swanglei MachineFrameInfo &MFI = MF.getFrameInfo(); 1494e2364a2Swanglei 1500e4378c5Swanglei unsigned ScavSlotsNum = 0; 1510e4378c5Swanglei 1528d28e586SWANG Rui // Far branches beyond 27-bit offset require a spill slot for scratch 1538d28e586SWANG Rui // register. 1540e4378c5Swanglei bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF)); 1550e4378c5Swanglei if (IsLargeFunction) 1560e4378c5Swanglei ScavSlotsNum = 1; 1570e4378c5Swanglei 1584e2364a2Swanglei // estimateStackSize has been observed to under-estimate the final stack 1594e2364a2Swanglei // size, so give ourselves wiggle-room by checking for stack size 1604e2364a2Swanglei // representable an 11-bit signed field rather than 12-bits. 1610e4378c5Swanglei if (!isInt<11>(MFI.estimateStackSize(MF))) 1620e4378c5Swanglei ScavSlotsNum = std::max(ScavSlotsNum, 1u); 1634e2364a2Swanglei 1640e4378c5Swanglei // For CFR spill. 1650e4378c5Swanglei if (needScavSlotForCFR(MF)) 1660e4378c5Swanglei ++ScavSlotsNum; 1670e4378c5Swanglei 1680e4378c5Swanglei // Create emergency spill slots. 1690e4378c5Swanglei for (unsigned i = 0; i < ScavSlotsNum; ++i) { 170*1a935d7aSGuy David int FI = 171*1a935d7aSGuy David MFI.CreateSpillStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC)); 1724e2364a2Swanglei RS->addScavengingFrameIndex(FI); 1730e4378c5Swanglei if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1) 1740e4378c5Swanglei LAFI->setBranchRelaxationSpillFrameIndex(FI); 1754e2364a2Swanglei LLVM_DEBUG(dbgs() << "Allocated FI(" << FI 1764e2364a2Swanglei << ") as the emergency spill slot.\n"); 1774e2364a2Swanglei } 1780e4378c5Swanglei } 1794e2364a2Swanglei 18033388ae8SLu Weining void LoongArchFrameLowering::emitPrologue(MachineFunction &MF, 18133388ae8SLu Weining MachineBasicBlock &MBB) const { 182c2d1d9f9Swanglei MachineFrameInfo &MFI = MF.getFrameInfo(); 1830c2b738fSwanglei auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 184c2d1d9f9Swanglei const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); 185c2d1d9f9Swanglei const LoongArchInstrInfo *TII = STI.getInstrInfo(); 186c2d1d9f9Swanglei MachineBasicBlock::iterator MBBI = MBB.begin(); 1874e2364a2Swanglei bool IsLA64 = STI.is64Bit(); 188c2d1d9f9Swanglei 189c2d1d9f9Swanglei Register SPReg = LoongArch::R3; 190c2d1d9f9Swanglei Register FPReg = LoongArch::R22; 191c2d1d9f9Swanglei 192c2d1d9f9Swanglei // Debug location must be unknown since the first debug location is used 193c2d1d9f9Swanglei // to determine the end of the prologue. 194c2d1d9f9Swanglei DebugLoc DL; 195389079c8SLin Runze // All calls are tail calls in GHC calling conv, and functions have no 196389079c8SLin Runze // prologue/epilogue. 197389079c8SLin Runze if (MF.getFunction().getCallingConv() == CallingConv::GHC) 198389079c8SLin Runze return; 199c2d1d9f9Swanglei // Determine the correct frame layout 200c2d1d9f9Swanglei determineFrameLayout(MF); 201c2d1d9f9Swanglei 202c2d1d9f9Swanglei // First, compute final stack size. 203c2d1d9f9Swanglei uint64_t StackSize = MFI.getStackSize(); 204f589e506Swanglei uint64_t RealStackSize = StackSize; 205c2d1d9f9Swanglei 206c2d1d9f9Swanglei // Early exit if there is no need to allocate space in the stack. 207c2d1d9f9Swanglei if (StackSize == 0 && !MFI.adjustsStack()) 208c2d1d9f9Swanglei return; 209c2d1d9f9Swanglei 2100d17e1f0Shev uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 211f589e506Swanglei // Split the SP adjustment to reduce the offsets of callee saved spill. 212f589e506Swanglei if (FirstSPAdjustAmount) 213f589e506Swanglei StackSize = FirstSPAdjustAmount; 214f589e506Swanglei 215c2d1d9f9Swanglei // Adjust stack. 216c2d1d9f9Swanglei adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); 217c2d1d9f9Swanglei // Emit ".cfi_def_cfa_offset StackSize". 218c2d1d9f9Swanglei unsigned CFIIndex = 219c2d1d9f9Swanglei MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); 220c2d1d9f9Swanglei BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 221c2d1d9f9Swanglei .addCFIIndex(CFIIndex) 222c2d1d9f9Swanglei .setMIFlag(MachineInstr::FrameSetup); 223c2d1d9f9Swanglei 224c2d1d9f9Swanglei const auto &CSI = MFI.getCalleeSavedInfo(); 225c2d1d9f9Swanglei 226c2d1d9f9Swanglei // The frame pointer is callee-saved, and code has been generated for us to 227c2d1d9f9Swanglei // save it to the stack. We need to skip over the storing of callee-saved 228c2d1d9f9Swanglei // registers as the frame pointer must be modified after it has been saved 229c2d1d9f9Swanglei // to the stack, not before. 230c2d1d9f9Swanglei std::advance(MBBI, CSI.size()); 231c2d1d9f9Swanglei 232c2d1d9f9Swanglei // Iterate over list of callee-saved registers and emit .cfi_offset 233c2d1d9f9Swanglei // directives. 234c2d1d9f9Swanglei for (const auto &Entry : CSI) { 235c2d1d9f9Swanglei int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); 236c2d1d9f9Swanglei unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 237c2d1d9f9Swanglei nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset)); 238c2d1d9f9Swanglei BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 239c2d1d9f9Swanglei .addCFIIndex(CFIIndex) 240c2d1d9f9Swanglei .setMIFlag(MachineInstr::FrameSetup); 241c2d1d9f9Swanglei } 242c2d1d9f9Swanglei 243c2d1d9f9Swanglei // Generate new FP. 244c2d1d9f9Swanglei if (hasFP(MF)) { 2450c2b738fSwanglei adjustReg(MBB, MBBI, DL, FPReg, SPReg, 2460c2b738fSwanglei StackSize - LoongArchFI->getVarArgsSaveSize(), 2470c2b738fSwanglei MachineInstr::FrameSetup); 248c2d1d9f9Swanglei 2490c2b738fSwanglei // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()" 2500c2b738fSwanglei unsigned CFIIndex = MF.addFrameInst( 2510c2b738fSwanglei MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true), 2520c2b738fSwanglei LoongArchFI->getVarArgsSaveSize())); 253c2d1d9f9Swanglei BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 254c2d1d9f9Swanglei .addCFIIndex(CFIIndex) 255c2d1d9f9Swanglei .setMIFlag(MachineInstr::FrameSetup); 256f589e506Swanglei } 257daf067daSwanglei 258f589e506Swanglei // Emit the second SP adjustment after saving callee saved registers. 2590d17e1f0Shev if (FirstSPAdjustAmount) { 2600d17e1f0Shev uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount; 261f589e506Swanglei assert(SecondSPAdjustAmount > 0 && 262f589e506Swanglei "SecondSPAdjustAmount should be greater than zero"); 263f589e506Swanglei adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, 264f589e506Swanglei MachineInstr::FrameSetup); 265f589e506Swanglei 2660d17e1f0Shev if (!hasFP(MF)) { 267f589e506Swanglei // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", 268f589e506Swanglei // don't emit an sp-based .cfi_def_cfa_offset 269f589e506Swanglei // Emit ".cfi_def_cfa_offset RealStackSize" 270f589e506Swanglei unsigned CFIIndex = MF.addFrameInst( 271f589e506Swanglei MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize)); 272f589e506Swanglei BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 273f589e506Swanglei .addCFIIndex(CFIIndex) 274f589e506Swanglei .setMIFlag(MachineInstr::FrameSetup); 275f589e506Swanglei } 276f589e506Swanglei } 277f589e506Swanglei 278f589e506Swanglei if (hasFP(MF)) { 279daf067daSwanglei // Realign stack. 280daf067daSwanglei if (RI->hasStackRealignment(MF)) { 2811bb77664Swanglei unsigned Align = Log2(MFI.getMaxAlign()); 2821bb77664Swanglei assert(Align > 0 && "The stack realignment size is invalid!"); 283daf067daSwanglei BuildMI(MBB, MBBI, DL, 2841bb77664Swanglei TII->get(IsLA64 ? LoongArch::BSTRINS_D : LoongArch::BSTRINS_W), 2851bb77664Swanglei SPReg) 286daf067daSwanglei .addReg(SPReg) 2871bb77664Swanglei .addReg(LoongArch::R0) 2881bb77664Swanglei .addImm(Align - 1) 2891bb77664Swanglei .addImm(0) 290daf067daSwanglei .setMIFlag(MachineInstr::FrameSetup); 291daf067daSwanglei // FP will be used to restore the frame in the epilogue, so we need 292daf067daSwanglei // another base register BP to record SP after re-alignment. SP will 293daf067daSwanglei // track the current stack after allocating variable sized objects. 294daf067daSwanglei if (hasBP(MF)) { 295daf067daSwanglei // move BP, $sp 296daf067daSwanglei BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR), 297daf067daSwanglei LoongArchABI::getBPReg()) 298daf067daSwanglei .addReg(SPReg) 299daf067daSwanglei .addReg(LoongArch::R0) 300daf067daSwanglei .setMIFlag(MachineInstr::FrameSetup); 301daf067daSwanglei } 302daf067daSwanglei } 303c2d1d9f9Swanglei } 30433388ae8SLu Weining } 30533388ae8SLu Weining 30633388ae8SLu Weining void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF, 30733388ae8SLu Weining MachineBasicBlock &MBB) const { 308c2d1d9f9Swanglei const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); 309c2d1d9f9Swanglei MachineFrameInfo &MFI = MF.getFrameInfo(); 3100c2b738fSwanglei auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 311c2d1d9f9Swanglei Register SPReg = LoongArch::R3; 312389079c8SLin Runze // All calls are tail calls in GHC calling conv, and functions have no 313389079c8SLin Runze // prologue/epilogue. 314389079c8SLin Runze if (MF.getFunction().getCallingConv() == CallingConv::GHC) 315389079c8SLin Runze return; 316c2d1d9f9Swanglei MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); 317c2d1d9f9Swanglei DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 318c2d1d9f9Swanglei 319c2d1d9f9Swanglei const auto &CSI = MFI.getCalleeSavedInfo(); 320c2d1d9f9Swanglei // Skip to before the restores of callee-saved registers. 321c2d1d9f9Swanglei auto LastFrameDestroy = MBBI; 322c2d1d9f9Swanglei if (!CSI.empty()) 323c2d1d9f9Swanglei LastFrameDestroy = std::prev(MBBI, CSI.size()); 324c2d1d9f9Swanglei 325c2d1d9f9Swanglei // Get the number of bytes from FrameInfo. 326c2d1d9f9Swanglei uint64_t StackSize = MFI.getStackSize(); 327c2d1d9f9Swanglei 328c2d1d9f9Swanglei // Restore the stack pointer. 329c2d1d9f9Swanglei if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) { 330c2d1d9f9Swanglei assert(hasFP(MF) && "frame pointer should not have been eliminated"); 3310c2b738fSwanglei adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, 3320c2b738fSwanglei -StackSize + LoongArchFI->getVarArgsSaveSize(), 333c2d1d9f9Swanglei MachineInstr::FrameDestroy); 334c2d1d9f9Swanglei } 335c2d1d9f9Swanglei 336f589e506Swanglei uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 337f589e506Swanglei if (FirstSPAdjustAmount) { 338f589e506Swanglei uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount; 339f589e506Swanglei assert(SecondSPAdjustAmount > 0 && 340f589e506Swanglei "SecondSPAdjustAmount should be greater than zero"); 341f589e506Swanglei 342f589e506Swanglei adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, 343f589e506Swanglei MachineInstr::FrameDestroy); 344f589e506Swanglei StackSize = FirstSPAdjustAmount; 345f589e506Swanglei } 346f589e506Swanglei 347c2d1d9f9Swanglei // Deallocate stack 348c2d1d9f9Swanglei adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); 349c2d1d9f9Swanglei } 350c2d1d9f9Swanglei 351f589e506Swanglei // We would like to split the SP adjustment to reduce prologue/epilogue 352f589e506Swanglei // as following instructions. In this way, the offset of the callee saved 353f589e506Swanglei // register could fit in a single store. 354f589e506Swanglei // e.g. 355f589e506Swanglei // addi.d $sp, $sp, -2032 356f589e506Swanglei // st.d $ra, $sp, 2024 357f589e506Swanglei // st.d $fp, $sp, 2016 358f589e506Swanglei // addi.d $sp, $sp, -16 3590d17e1f0Shev uint64_t LoongArchFrameLowering::getFirstSPAdjustAmount( 3600d17e1f0Shev const MachineFunction &MF) const { 361f589e506Swanglei const MachineFrameInfo &MFI = MF.getFrameInfo(); 362f589e506Swanglei const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 363f589e506Swanglei 364f589e506Swanglei // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed 365f589e506Swanglei // 12-bit and there exists a callee-saved register needing to be pushed. 3660d17e1f0Shev if (!isInt<12>(MFI.getStackSize()) && (CSI.size() > 0)) { 367f589e506Swanglei // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will 368f589e506Swanglei // cause sp = sp + 2048 in the epilogue to be split into multiple 369f589e506Swanglei // instructions. Offsets smaller than 2048 can fit in a single load/store 370f589e506Swanglei // instruction, and we have to stick with the stack alignment. 371f589e506Swanglei // So (2048 - StackAlign) will satisfy the stack alignment. 3720d17e1f0Shev return 2048 - getStackAlign().value(); 373f589e506Swanglei } 374f589e506Swanglei return 0; 375f589e506Swanglei } 376f589e506Swanglei 377c2d1d9f9Swanglei void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF, 378c2d1d9f9Swanglei BitVector &SavedRegs, 379c2d1d9f9Swanglei RegScavenger *RS) const { 380c2d1d9f9Swanglei TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 381c2d1d9f9Swanglei // Unconditionally spill RA and FP only if the function uses a frame 382c2d1d9f9Swanglei // pointer. 383c2d1d9f9Swanglei if (hasFP(MF)) { 384c2d1d9f9Swanglei SavedRegs.set(LoongArch::R1); 385c2d1d9f9Swanglei SavedRegs.set(LoongArch::R22); 386c2d1d9f9Swanglei } 387c2d1d9f9Swanglei // Mark BP as used if function has dedicated base pointer. 388c2d1d9f9Swanglei if (hasBP(MF)) 389c2d1d9f9Swanglei SavedRegs.set(LoongArchABI::getBPReg()); 39033388ae8SLu Weining } 3915b1ec705Swanglei 3920c2b738fSwanglei // Do not preserve stack space within prologue for outgoing variables if the 3930c2b738fSwanglei // function contains variable size objects. 3940c2b738fSwanglei // Let eliminateCallFramePseudoInstr preserve stack space for it. 3950c2b738fSwanglei bool LoongArchFrameLowering::hasReservedCallFrame( 3960c2b738fSwanglei const MachineFunction &MF) const { 3970c2b738fSwanglei return !MF.getFrameInfo().hasVarSizedObjects(); 3980c2b738fSwanglei } 3990c2b738fSwanglei 4000c2b738fSwanglei // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 4010c2b738fSwanglei MachineBasicBlock::iterator 4020c2b738fSwanglei LoongArchFrameLowering::eliminateCallFramePseudoInstr( 4030c2b738fSwanglei MachineFunction &MF, MachineBasicBlock &MBB, 4040c2b738fSwanglei MachineBasicBlock::iterator MI) const { 4050c2b738fSwanglei Register SPReg = LoongArch::R3; 4060c2b738fSwanglei DebugLoc DL = MI->getDebugLoc(); 4070c2b738fSwanglei 4080c2b738fSwanglei if (!hasReservedCallFrame(MF)) { 4090c2b738fSwanglei // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 4100c2b738fSwanglei // ADJCALLSTACKUP must be converted to instructions manipulating the stack 4110c2b738fSwanglei // pointer. This is necessary when there is a variable length stack 4120c2b738fSwanglei // allocation (e.g. alloca), which means it's not possible to allocate 4130c2b738fSwanglei // space for outgoing arguments from within the function prologue. 4140c2b738fSwanglei int64_t Amount = MI->getOperand(0).getImm(); 4150c2b738fSwanglei 4160c2b738fSwanglei if (Amount != 0) { 4170c2b738fSwanglei // Ensure the stack remains aligned after adjustment. 4180c2b738fSwanglei Amount = alignSPAdjust(Amount); 4190c2b738fSwanglei 4200c2b738fSwanglei if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN) 4210c2b738fSwanglei Amount = -Amount; 4220c2b738fSwanglei 4230c2b738fSwanglei adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 4240c2b738fSwanglei } 4250c2b738fSwanglei } 4260c2b738fSwanglei 4270c2b738fSwanglei return MBB.erase(MI); 4280c2b738fSwanglei } 4290c2b738fSwanglei 430d20c54cbSwanglei bool LoongArchFrameLowering::spillCalleeSavedRegisters( 431d20c54cbSwanglei MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 432d20c54cbSwanglei ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 433d20c54cbSwanglei if (CSI.empty()) 434d20c54cbSwanglei return true; 435d20c54cbSwanglei 436d20c54cbSwanglei MachineFunction *MF = MBB.getParent(); 437d20c54cbSwanglei const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 438d20c54cbSwanglei 439d20c54cbSwanglei // Insert the spill to the stack frame. 440d20c54cbSwanglei for (auto &CS : CSI) { 441d20c54cbSwanglei Register Reg = CS.getReg(); 442d20c54cbSwanglei // If the register is RA and the return address is taken by method 443d20c54cbSwanglei // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag. 444d20c54cbSwanglei bool IsKill = 445d20c54cbSwanglei !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken()); 446d20c54cbSwanglei const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 447b5efec4bSChristudasan Devadasan TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI, 448b5efec4bSChristudasan Devadasan Register()); 449d20c54cbSwanglei } 450d20c54cbSwanglei 451d20c54cbSwanglei return true; 452d20c54cbSwanglei } 453d20c54cbSwanglei 4545b1ec705Swanglei StackOffset LoongArchFrameLowering::getFrameIndexReference( 4555b1ec705Swanglei const MachineFunction &MF, int FI, Register &FrameReg) const { 4565b1ec705Swanglei const MachineFrameInfo &MFI = MF.getFrameInfo(); 4575b1ec705Swanglei const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 4580c2b738fSwanglei auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 459daf067daSwanglei uint64_t StackSize = MFI.getStackSize(); 460f589e506Swanglei uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 4615b1ec705Swanglei 4625b1ec705Swanglei // Callee-saved registers should be referenced relative to the stack 4635b1ec705Swanglei // pointer (positive offset), otherwise use the frame pointer (negative 4645b1ec705Swanglei // offset). 4655b1ec705Swanglei const auto &CSI = MFI.getCalleeSavedInfo(); 4665b1ec705Swanglei int MinCSFI = 0; 4675b1ec705Swanglei int MaxCSFI = -1; 4685b1ec705Swanglei StackOffset Offset = 4695b1ec705Swanglei StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + 4705b1ec705Swanglei MFI.getOffsetAdjustment()); 4715b1ec705Swanglei 4725b1ec705Swanglei if (CSI.size()) { 4735b1ec705Swanglei MinCSFI = CSI[0].getFrameIdx(); 4745b1ec705Swanglei MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 4755b1ec705Swanglei } 4765b1ec705Swanglei 477daf067daSwanglei if (FI >= MinCSFI && FI <= MaxCSFI) { 4785b1ec705Swanglei FrameReg = LoongArch::R3; 479f589e506Swanglei if (FirstSPAdjustAmount) 480f589e506Swanglei Offset += StackOffset::getFixed(FirstSPAdjustAmount); 481f589e506Swanglei else 482daf067daSwanglei Offset += StackOffset::getFixed(StackSize); 483daf067daSwanglei } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { 484daf067daSwanglei // If the stack was realigned, the frame pointer is set in order to allow 485daf067daSwanglei // SP to be restored, so we need another base register to record the stack 486daf067daSwanglei // after realignment. 487daf067daSwanglei FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3; 488daf067daSwanglei Offset += StackOffset::getFixed(StackSize); 4890c2b738fSwanglei } else { 4900c2b738fSwanglei FrameReg = RI->getFrameRegister(MF); 491daf067daSwanglei if (hasFP(MF)) 4920c2b738fSwanglei Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize()); 493daf067daSwanglei else 494daf067daSwanglei Offset += StackOffset::getFixed(StackSize); 4955b1ec705Swanglei } 4965b1ec705Swanglei 4975b1ec705Swanglei return Offset; 4985b1ec705Swanglei } 49925ecfbf8Swanglei 50025ecfbf8Swanglei bool LoongArchFrameLowering::enableShrinkWrapping( 50125ecfbf8Swanglei const MachineFunction &MF) const { 50225ecfbf8Swanglei // Keep the conventional code flow when not optimizing. 50325ecfbf8Swanglei if (MF.getFunction().hasOptNone()) 50425ecfbf8Swanglei return false; 50525ecfbf8Swanglei 50625ecfbf8Swanglei return true; 50725ecfbf8Swanglei } 508