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" 14753f127fSDimitry Andric #include "LoongArchMachineFunctionInfo.h" 1581ad6265SDimitry Andric #include "LoongArchSubtarget.h" 16753f127fSDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h" 17bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h" 1881ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 2281ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 2381ad6265SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 2481ad6265SDimitry Andric #include "llvm/MC/MCDwarf.h" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric using namespace llvm; 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-frame-lowering" 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric // Return true if the specified function should have a dedicated frame 3181ad6265SDimitry Andric // pointer register. This is true if frame pointer elimination is 3281ad6265SDimitry Andric // disabled, if it needs dynamic stack realignment, if the function has 3381ad6265SDimitry Andric // variable sized allocas, or if the frame address is taken. 3481ad6265SDimitry Andric bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const { 3581ad6265SDimitry Andric const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 3881ad6265SDimitry Andric return MF.getTarget().Options.DisableFramePointerElim(MF) || 3981ad6265SDimitry Andric RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || 4081ad6265SDimitry Andric MFI.isFrameAddressTaken(); 4181ad6265SDimitry Andric } 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const { 4481ad6265SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 4581ad6265SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF); 4881ad6265SDimitry Andric } 4981ad6265SDimitry Andric 50753f127fSDimitry Andric void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB, 51753f127fSDimitry Andric MachineBasicBlock::iterator MBBI, 52753f127fSDimitry Andric const DebugLoc &DL, Register DestReg, 53753f127fSDimitry Andric Register SrcReg, int64_t Val, 54753f127fSDimitry Andric MachineInstr::MIFlag Flag) const { 55753f127fSDimitry Andric const LoongArchInstrInfo *TII = STI.getInstrInfo(); 56753f127fSDimitry Andric bool IsLA64 = STI.is64Bit(); 57bdd1243dSDimitry Andric unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W; 58753f127fSDimitry Andric 59753f127fSDimitry Andric if (DestReg == SrcReg && Val == 0) 60753f127fSDimitry Andric return; 61753f127fSDimitry Andric 62753f127fSDimitry Andric if (isInt<12>(Val)) { 63753f127fSDimitry Andric // addi.w/d $DstReg, $SrcReg, Val 64bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) 65753f127fSDimitry Andric .addReg(SrcReg) 66753f127fSDimitry Andric .addImm(Val) 67753f127fSDimitry Andric .setMIFlag(Flag); 68753f127fSDimitry Andric return; 69753f127fSDimitry Andric } 70753f127fSDimitry Andric 71bdd1243dSDimitry Andric // Try to split the offset across two ADDIs. We need to keep the stack pointer 72bdd1243dSDimitry Andric // aligned after each ADDI. We need to determine the maximum value we can put 73bdd1243dSDimitry Andric // in each ADDI. In the negative direction, we can use -2048 which is always 74bdd1243dSDimitry Andric // sufficiently aligned. In the positive direction, we need to find the 75bdd1243dSDimitry Andric // largest 12-bit immediate that is aligned. Exclude -4096 since it can be 76bdd1243dSDimitry Andric // created with LU12I.W. 77bdd1243dSDimitry Andric assert(getStackAlign().value() < 2048 && "Stack alignment too large"); 78bdd1243dSDimitry Andric int64_t MaxPosAdjStep = 2048 - getStackAlign().value(); 79bdd1243dSDimitry Andric if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) { 80bdd1243dSDimitry Andric int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep; 81bdd1243dSDimitry Andric Val -= FirstAdj; 82bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) 83bdd1243dSDimitry Andric .addReg(SrcReg) 84bdd1243dSDimitry Andric .addImm(FirstAdj) 85bdd1243dSDimitry Andric .setMIFlag(Flag); 86bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg) 87bdd1243dSDimitry Andric .addReg(DestReg, RegState::Kill) 88bdd1243dSDimitry Andric .addImm(Val) 89bdd1243dSDimitry Andric .setMIFlag(Flag); 90bdd1243dSDimitry Andric return; 91bdd1243dSDimitry Andric } 92bdd1243dSDimitry Andric 93bdd1243dSDimitry Andric unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W; 94bdd1243dSDimitry Andric if (Val < 0) { 95bdd1243dSDimitry Andric Val = -Val; 96bdd1243dSDimitry Andric Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W; 97bdd1243dSDimitry Andric } 98bdd1243dSDimitry Andric 99bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); 100bdd1243dSDimitry Andric Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 101bdd1243dSDimitry Andric TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag); 102bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) 103bdd1243dSDimitry Andric .addReg(SrcReg) 104bdd1243dSDimitry Andric .addReg(ScratchReg, RegState::Kill) 105bdd1243dSDimitry Andric .setMIFlag(Flag); 106753f127fSDimitry Andric } 107753f127fSDimitry Andric 108753f127fSDimitry Andric // Determine the size of the frame and maximum call frame size. 109753f127fSDimitry Andric void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const { 110753f127fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 111753f127fSDimitry Andric 112753f127fSDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 113753f127fSDimitry Andric uint64_t FrameSize = MFI.getStackSize(); 114753f127fSDimitry Andric 115753f127fSDimitry Andric // Make sure the frame is aligned. 116753f127fSDimitry Andric FrameSize = alignTo(FrameSize, getStackAlign()); 117753f127fSDimitry Andric 118753f127fSDimitry Andric // Update frame info. 119753f127fSDimitry Andric MFI.setStackSize(FrameSize); 120753f127fSDimitry Andric } 121753f127fSDimitry Andric 122bdd1243dSDimitry Andric static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII, 123bdd1243dSDimitry Andric const MachineFunction &MF) { 124bdd1243dSDimitry Andric uint64_t FuncSize = 0; 125bdd1243dSDimitry Andric for (auto &MBB : MF) 126bdd1243dSDimitry Andric for (auto &MI : MBB) 127bdd1243dSDimitry Andric FuncSize += TII->getInstSizeInBytes(MI); 128bdd1243dSDimitry Andric return FuncSize; 129bdd1243dSDimitry Andric } 130bdd1243dSDimitry Andric 131bdd1243dSDimitry Andric static bool needScavSlotForCFR(MachineFunction &MF) { 132bdd1243dSDimitry Andric if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF()) 133bdd1243dSDimitry Andric return false; 134bdd1243dSDimitry Andric for (auto &MBB : MF) 135bdd1243dSDimitry Andric for (auto &MI : MBB) 136bdd1243dSDimitry Andric if (MI.getOpcode() == LoongArch::PseudoST_CFR) 137bdd1243dSDimitry Andric return true; 138bdd1243dSDimitry Andric return false; 139bdd1243dSDimitry Andric } 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric void LoongArchFrameLowering::processFunctionBeforeFrameFinalized( 142bdd1243dSDimitry Andric MachineFunction &MF, RegScavenger *RS) const { 143bdd1243dSDimitry Andric const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); 144bdd1243dSDimitry Andric const TargetRegisterClass &RC = LoongArch::GPRRegClass; 145bdd1243dSDimitry Andric const LoongArchInstrInfo *TII = STI.getInstrInfo(); 146bdd1243dSDimitry Andric LoongArchMachineFunctionInfo *LAFI = 147bdd1243dSDimitry Andric MF.getInfo<LoongArchMachineFunctionInfo>(); 148bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 149bdd1243dSDimitry Andric 150bdd1243dSDimitry Andric unsigned ScavSlotsNum = 0; 151bdd1243dSDimitry Andric 152bdd1243dSDimitry Andric // Far branches beyond 27-bit offset require a spill slot for scratch register. 153bdd1243dSDimitry Andric bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF)); 154bdd1243dSDimitry Andric if (IsLargeFunction) 155bdd1243dSDimitry Andric ScavSlotsNum = 1; 156bdd1243dSDimitry Andric 157bdd1243dSDimitry Andric // estimateStackSize has been observed to under-estimate the final stack 158bdd1243dSDimitry Andric // size, so give ourselves wiggle-room by checking for stack size 159bdd1243dSDimitry Andric // representable an 11-bit signed field rather than 12-bits. 160bdd1243dSDimitry Andric if (!isInt<11>(MFI.estimateStackSize(MF))) 161bdd1243dSDimitry Andric ScavSlotsNum = std::max(ScavSlotsNum, 1u); 162bdd1243dSDimitry Andric 163bdd1243dSDimitry Andric // For CFR spill. 164bdd1243dSDimitry Andric if (needScavSlotForCFR(MF)) 165bdd1243dSDimitry Andric ++ScavSlotsNum; 166bdd1243dSDimitry Andric 167bdd1243dSDimitry Andric // Create emergency spill slots. 168bdd1243dSDimitry Andric for (unsigned i = 0; i < ScavSlotsNum; ++i) { 169bdd1243dSDimitry Andric int FI = MFI.CreateStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC), 170bdd1243dSDimitry Andric false); 171bdd1243dSDimitry Andric RS->addScavengingFrameIndex(FI); 172bdd1243dSDimitry Andric if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1) 173bdd1243dSDimitry Andric LAFI->setBranchRelaxationSpillFrameIndex(FI); 174bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Allocated FI(" << FI 175bdd1243dSDimitry Andric << ") as the emergency spill slot.\n"); 176bdd1243dSDimitry Andric } 177bdd1243dSDimitry Andric } 178bdd1243dSDimitry Andric 17981ad6265SDimitry Andric void LoongArchFrameLowering::emitPrologue(MachineFunction &MF, 18081ad6265SDimitry Andric MachineBasicBlock &MBB) const { 181753f127fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 182bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 183753f127fSDimitry Andric const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); 184753f127fSDimitry Andric const LoongArchInstrInfo *TII = STI.getInstrInfo(); 185753f127fSDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 186bdd1243dSDimitry Andric bool IsLA64 = STI.is64Bit(); 187753f127fSDimitry Andric 188753f127fSDimitry Andric Register SPReg = LoongArch::R3; 189753f127fSDimitry Andric Register FPReg = LoongArch::R22; 190753f127fSDimitry Andric 191753f127fSDimitry Andric // Debug location must be unknown since the first debug location is used 192753f127fSDimitry Andric // to determine the end of the prologue. 193753f127fSDimitry Andric DebugLoc DL; 194bdd1243dSDimitry Andric // All calls are tail calls in GHC calling conv, and functions have no 195bdd1243dSDimitry Andric // prologue/epilogue. 196bdd1243dSDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC) 197bdd1243dSDimitry Andric return; 198753f127fSDimitry Andric // Determine the correct frame layout 199753f127fSDimitry Andric determineFrameLayout(MF); 200753f127fSDimitry Andric 201753f127fSDimitry Andric // First, compute final stack size. 202753f127fSDimitry Andric uint64_t StackSize = MFI.getStackSize(); 203bdd1243dSDimitry Andric uint64_t RealStackSize = StackSize; 204753f127fSDimitry Andric 205753f127fSDimitry Andric // Early exit if there is no need to allocate space in the stack. 206753f127fSDimitry Andric if (StackSize == 0 && !MFI.adjustsStack()) 207753f127fSDimitry Andric return; 208753f127fSDimitry Andric 209bdd1243dSDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF, true); 210bdd1243dSDimitry Andric uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount; 211bdd1243dSDimitry Andric // Split the SP adjustment to reduce the offsets of callee saved spill. 212bdd1243dSDimitry Andric if (FirstSPAdjustAmount) 213bdd1243dSDimitry Andric StackSize = FirstSPAdjustAmount; 214bdd1243dSDimitry Andric 215753f127fSDimitry Andric // Adjust stack. 216753f127fSDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); 217bdd1243dSDimitry Andric if (FirstSPAdjustAmount != 2048 || SecondSPAdjustAmount == 0) { 218753f127fSDimitry Andric // Emit ".cfi_def_cfa_offset StackSize". 219753f127fSDimitry Andric unsigned CFIIndex = 220753f127fSDimitry Andric MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); 221753f127fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 222753f127fSDimitry Andric .addCFIIndex(CFIIndex) 223753f127fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 224bdd1243dSDimitry Andric } 225753f127fSDimitry Andric 226753f127fSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 227753f127fSDimitry Andric 228753f127fSDimitry Andric // The frame pointer is callee-saved, and code has been generated for us to 229753f127fSDimitry Andric // save it to the stack. We need to skip over the storing of callee-saved 230753f127fSDimitry Andric // registers as the frame pointer must be modified after it has been saved 231753f127fSDimitry Andric // to the stack, not before. 232753f127fSDimitry Andric std::advance(MBBI, CSI.size()); 233753f127fSDimitry Andric 234753f127fSDimitry Andric // Iterate over list of callee-saved registers and emit .cfi_offset 235753f127fSDimitry Andric // directives. 236753f127fSDimitry Andric for (const auto &Entry : CSI) { 237753f127fSDimitry Andric int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); 238753f127fSDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 239753f127fSDimitry Andric nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset)); 240753f127fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 241753f127fSDimitry Andric .addCFIIndex(CFIIndex) 242753f127fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 243753f127fSDimitry Andric } 244753f127fSDimitry Andric 245753f127fSDimitry Andric // Generate new FP. 246753f127fSDimitry Andric if (hasFP(MF)) { 247bdd1243dSDimitry Andric adjustReg(MBB, MBBI, DL, FPReg, SPReg, 248bdd1243dSDimitry Andric StackSize - LoongArchFI->getVarArgsSaveSize(), 249bdd1243dSDimitry Andric MachineInstr::FrameSetup); 250753f127fSDimitry Andric 251bdd1243dSDimitry Andric // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()" 252bdd1243dSDimitry Andric unsigned CFIIndex = MF.addFrameInst( 253bdd1243dSDimitry Andric MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true), 254bdd1243dSDimitry Andric LoongArchFI->getVarArgsSaveSize())); 255753f127fSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 256753f127fSDimitry Andric .addCFIIndex(CFIIndex) 257753f127fSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 258753f127fSDimitry Andric } 259bdd1243dSDimitry Andric 260bdd1243dSDimitry Andric // Emit the second SP adjustment after saving callee saved registers. 261bdd1243dSDimitry Andric if (FirstSPAdjustAmount && SecondSPAdjustAmount) { 262bdd1243dSDimitry Andric if (hasFP(MF)) { 263bdd1243dSDimitry Andric assert(SecondSPAdjustAmount > 0 && 264bdd1243dSDimitry Andric "SecondSPAdjustAmount should be greater than zero"); 265bdd1243dSDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, 266bdd1243dSDimitry Andric MachineInstr::FrameSetup); 267bdd1243dSDimitry Andric } else { 268bdd1243dSDimitry Andric // FIXME: RegScavenger will place the spill instruction before the 269bdd1243dSDimitry Andric // prologue if a VReg is created in the prologue. This will pollute the 270bdd1243dSDimitry Andric // caller's stack data. Therefore, until there is better way, we just use 271bdd1243dSDimitry Andric // the `addi.w/d` instruction for stack adjustment to ensure that VReg 272bdd1243dSDimitry Andric // will not be created. 273bdd1243dSDimitry Andric for (int Val = SecondSPAdjustAmount; Val > 0; Val -= 2048) 274bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, 275bdd1243dSDimitry Andric TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), SPReg) 276bdd1243dSDimitry Andric .addReg(SPReg) 277bdd1243dSDimitry Andric .addImm(Val < 2048 ? -Val : -2048) 278bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 279bdd1243dSDimitry Andric 280bdd1243dSDimitry Andric // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", 281bdd1243dSDimitry Andric // don't emit an sp-based .cfi_def_cfa_offset 282bdd1243dSDimitry Andric // Emit ".cfi_def_cfa_offset RealStackSize" 283bdd1243dSDimitry Andric unsigned CFIIndex = MF.addFrameInst( 284bdd1243dSDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize)); 285bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 286bdd1243dSDimitry Andric .addCFIIndex(CFIIndex) 287bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 288bdd1243dSDimitry Andric } 289bdd1243dSDimitry Andric } 290bdd1243dSDimitry Andric 291bdd1243dSDimitry Andric if (hasFP(MF)) { 292bdd1243dSDimitry Andric // Realign stack. 293bdd1243dSDimitry Andric if (RI->hasStackRealignment(MF)) { 294bdd1243dSDimitry Andric unsigned ShiftAmount = Log2(MFI.getMaxAlign()); 295bdd1243dSDimitry Andric Register VR = 296bdd1243dSDimitry Andric MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); 297bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, 298bdd1243dSDimitry Andric TII->get(IsLA64 ? LoongArch::SRLI_D : LoongArch::SRLI_W), VR) 299bdd1243dSDimitry Andric .addReg(SPReg) 300bdd1243dSDimitry Andric .addImm(ShiftAmount) 301bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 302bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, 303bdd1243dSDimitry Andric TII->get(IsLA64 ? LoongArch::SLLI_D : LoongArch::SLLI_W), SPReg) 304bdd1243dSDimitry Andric .addReg(VR) 305bdd1243dSDimitry Andric .addImm(ShiftAmount) 306bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 307bdd1243dSDimitry Andric // FP will be used to restore the frame in the epilogue, so we need 308bdd1243dSDimitry Andric // another base register BP to record SP after re-alignment. SP will 309bdd1243dSDimitry Andric // track the current stack after allocating variable sized objects. 310bdd1243dSDimitry Andric if (hasBP(MF)) { 311bdd1243dSDimitry Andric // move BP, $sp 312bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR), 313bdd1243dSDimitry Andric LoongArchABI::getBPReg()) 314bdd1243dSDimitry Andric .addReg(SPReg) 315bdd1243dSDimitry Andric .addReg(LoongArch::R0) 316bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 317bdd1243dSDimitry Andric } 318bdd1243dSDimitry Andric } 319bdd1243dSDimitry Andric } 32081ad6265SDimitry Andric } 32181ad6265SDimitry Andric 32281ad6265SDimitry Andric void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF, 32381ad6265SDimitry Andric MachineBasicBlock &MBB) const { 324753f127fSDimitry Andric const LoongArchRegisterInfo *RI = STI.getRegisterInfo(); 325753f127fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 326bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 327753f127fSDimitry Andric Register SPReg = LoongArch::R3; 328bdd1243dSDimitry Andric // All calls are tail calls in GHC calling conv, and functions have no 329bdd1243dSDimitry Andric // prologue/epilogue. 330bdd1243dSDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::GHC) 331bdd1243dSDimitry Andric return; 332753f127fSDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); 333753f127fSDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 334753f127fSDimitry Andric 335753f127fSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 336753f127fSDimitry Andric // Skip to before the restores of callee-saved registers. 337753f127fSDimitry Andric auto LastFrameDestroy = MBBI; 338753f127fSDimitry Andric if (!CSI.empty()) 339753f127fSDimitry Andric LastFrameDestroy = std::prev(MBBI, CSI.size()); 340753f127fSDimitry Andric 341753f127fSDimitry Andric // Get the number of bytes from FrameInfo. 342753f127fSDimitry Andric uint64_t StackSize = MFI.getStackSize(); 343753f127fSDimitry Andric 344753f127fSDimitry Andric // Restore the stack pointer. 345753f127fSDimitry Andric if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) { 346753f127fSDimitry Andric assert(hasFP(MF) && "frame pointer should not have been eliminated"); 347bdd1243dSDimitry Andric adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, 348bdd1243dSDimitry Andric -StackSize + LoongArchFI->getVarArgsSaveSize(), 349753f127fSDimitry Andric MachineInstr::FrameDestroy); 350753f127fSDimitry Andric } 351753f127fSDimitry Andric 352bdd1243dSDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 353bdd1243dSDimitry Andric if (FirstSPAdjustAmount) { 354bdd1243dSDimitry Andric uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount; 355bdd1243dSDimitry Andric assert(SecondSPAdjustAmount > 0 && 356bdd1243dSDimitry Andric "SecondSPAdjustAmount should be greater than zero"); 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, 359bdd1243dSDimitry Andric MachineInstr::FrameDestroy); 360bdd1243dSDimitry Andric StackSize = FirstSPAdjustAmount; 361bdd1243dSDimitry Andric } 362bdd1243dSDimitry Andric 363753f127fSDimitry Andric // Deallocate stack 364753f127fSDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); 365753f127fSDimitry Andric } 366753f127fSDimitry Andric 367bdd1243dSDimitry Andric // We would like to split the SP adjustment to reduce prologue/epilogue 368bdd1243dSDimitry Andric // as following instructions. In this way, the offset of the callee saved 369bdd1243dSDimitry Andric // register could fit in a single store. 370bdd1243dSDimitry Andric // e.g. 371bdd1243dSDimitry Andric // addi.d $sp, $sp, -2032 372bdd1243dSDimitry Andric // st.d $ra, $sp, 2024 373bdd1243dSDimitry Andric // st.d $fp, $sp, 2016 374bdd1243dSDimitry Andric // addi.d $sp, $sp, -16 375bdd1243dSDimitry Andric uint64_t 376bdd1243dSDimitry Andric LoongArchFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF, 377bdd1243dSDimitry Andric bool IsPrologue) const { 378bdd1243dSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 379bdd1243dSDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 380bdd1243dSDimitry Andric 381bdd1243dSDimitry Andric // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed 382bdd1243dSDimitry Andric // 12-bit and there exists a callee-saved register needing to be pushed. 383bdd1243dSDimitry Andric if (!isInt<12>(MFI.getStackSize())) { 384bdd1243dSDimitry Andric // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will 385bdd1243dSDimitry Andric // cause sp = sp + 2048 in the epilogue to be split into multiple 386bdd1243dSDimitry Andric // instructions. Offsets smaller than 2048 can fit in a single load/store 387bdd1243dSDimitry Andric // instruction, and we have to stick with the stack alignment. 388bdd1243dSDimitry Andric // So (2048 - StackAlign) will satisfy the stack alignment. 389bdd1243dSDimitry Andric // 390bdd1243dSDimitry Andric // FIXME: This place may seem odd. When using multiple ADDI instructions to 391bdd1243dSDimitry Andric // adjust the stack in Prologue, and there are no callee-saved registers, we 392bdd1243dSDimitry Andric // can take advantage of the logic of split sp ajustment to reduce code 393bdd1243dSDimitry Andric // changes. 394bdd1243dSDimitry Andric return CSI.size() > 0 ? 2048 - getStackAlign().value() 395bdd1243dSDimitry Andric : (IsPrologue ? 2048 : 0); 396bdd1243dSDimitry Andric } 397bdd1243dSDimitry Andric return 0; 398bdd1243dSDimitry Andric } 399bdd1243dSDimitry Andric 400753f127fSDimitry Andric void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF, 401753f127fSDimitry Andric BitVector &SavedRegs, 402753f127fSDimitry Andric RegScavenger *RS) const { 403753f127fSDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 404753f127fSDimitry Andric // Unconditionally spill RA and FP only if the function uses a frame 405753f127fSDimitry Andric // pointer. 406753f127fSDimitry Andric if (hasFP(MF)) { 407753f127fSDimitry Andric SavedRegs.set(LoongArch::R1); 408753f127fSDimitry Andric SavedRegs.set(LoongArch::R22); 409753f127fSDimitry Andric } 410753f127fSDimitry Andric // Mark BP as used if function has dedicated base pointer. 411753f127fSDimitry Andric if (hasBP(MF)) 412753f127fSDimitry Andric SavedRegs.set(LoongArchABI::getBPReg()); 413753f127fSDimitry Andric } 414753f127fSDimitry Andric 415bdd1243dSDimitry Andric // Do not preserve stack space within prologue for outgoing variables if the 416bdd1243dSDimitry Andric // function contains variable size objects. 417bdd1243dSDimitry Andric // Let eliminateCallFramePseudoInstr preserve stack space for it. 418bdd1243dSDimitry Andric bool LoongArchFrameLowering::hasReservedCallFrame( 419bdd1243dSDimitry Andric const MachineFunction &MF) const { 420bdd1243dSDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 421bdd1243dSDimitry Andric } 422bdd1243dSDimitry Andric 423bdd1243dSDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 424bdd1243dSDimitry Andric MachineBasicBlock::iterator 425bdd1243dSDimitry Andric LoongArchFrameLowering::eliminateCallFramePseudoInstr( 426bdd1243dSDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 427bdd1243dSDimitry Andric MachineBasicBlock::iterator MI) const { 428bdd1243dSDimitry Andric Register SPReg = LoongArch::R3; 429bdd1243dSDimitry Andric DebugLoc DL = MI->getDebugLoc(); 430bdd1243dSDimitry Andric 431bdd1243dSDimitry Andric if (!hasReservedCallFrame(MF)) { 432bdd1243dSDimitry Andric // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 433bdd1243dSDimitry Andric // ADJCALLSTACKUP must be converted to instructions manipulating the stack 434bdd1243dSDimitry Andric // pointer. This is necessary when there is a variable length stack 435bdd1243dSDimitry Andric // allocation (e.g. alloca), which means it's not possible to allocate 436bdd1243dSDimitry Andric // space for outgoing arguments from within the function prologue. 437bdd1243dSDimitry Andric int64_t Amount = MI->getOperand(0).getImm(); 438bdd1243dSDimitry Andric 439bdd1243dSDimitry Andric if (Amount != 0) { 440bdd1243dSDimitry Andric // Ensure the stack remains aligned after adjustment. 441bdd1243dSDimitry Andric Amount = alignSPAdjust(Amount); 442bdd1243dSDimitry Andric 443bdd1243dSDimitry Andric if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN) 444bdd1243dSDimitry Andric Amount = -Amount; 445bdd1243dSDimitry Andric 446bdd1243dSDimitry Andric adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 447bdd1243dSDimitry Andric } 448bdd1243dSDimitry Andric } 449bdd1243dSDimitry Andric 450bdd1243dSDimitry Andric return MBB.erase(MI); 451bdd1243dSDimitry Andric } 452bdd1243dSDimitry Andric 453bdd1243dSDimitry Andric bool LoongArchFrameLowering::spillCalleeSavedRegisters( 454bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 455bdd1243dSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 456bdd1243dSDimitry Andric if (CSI.empty()) 457bdd1243dSDimitry Andric return true; 458bdd1243dSDimitry Andric 459bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent(); 460bdd1243dSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 461bdd1243dSDimitry Andric 462bdd1243dSDimitry Andric // Insert the spill to the stack frame. 463bdd1243dSDimitry Andric for (auto &CS : CSI) { 464bdd1243dSDimitry Andric Register Reg = CS.getReg(); 465bdd1243dSDimitry Andric // If the register is RA and the return address is taken by method 466bdd1243dSDimitry Andric // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag. 467bdd1243dSDimitry Andric bool IsKill = 468bdd1243dSDimitry Andric !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken()); 469bdd1243dSDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 470bdd1243dSDimitry Andric TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC, TRI, 471bdd1243dSDimitry Andric Register()); 472bdd1243dSDimitry Andric } 473bdd1243dSDimitry Andric 474bdd1243dSDimitry Andric return true; 475bdd1243dSDimitry Andric } 476bdd1243dSDimitry Andric 477753f127fSDimitry Andric StackOffset LoongArchFrameLowering::getFrameIndexReference( 478753f127fSDimitry Andric const MachineFunction &MF, int FI, Register &FrameReg) const { 479753f127fSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 480753f127fSDimitry Andric const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 481bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 482bdd1243dSDimitry Andric uint64_t StackSize = MFI.getStackSize(); 483bdd1243dSDimitry Andric uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); 484753f127fSDimitry Andric 485753f127fSDimitry Andric // Callee-saved registers should be referenced relative to the stack 486753f127fSDimitry Andric // pointer (positive offset), otherwise use the frame pointer (negative 487753f127fSDimitry Andric // offset). 488753f127fSDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 489753f127fSDimitry Andric int MinCSFI = 0; 490753f127fSDimitry Andric int MaxCSFI = -1; 491753f127fSDimitry Andric StackOffset Offset = 492753f127fSDimitry Andric StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + 493753f127fSDimitry Andric MFI.getOffsetAdjustment()); 494753f127fSDimitry Andric 495753f127fSDimitry Andric if (CSI.size()) { 496753f127fSDimitry Andric MinCSFI = CSI[0].getFrameIdx(); 497753f127fSDimitry Andric MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 498753f127fSDimitry Andric } 499753f127fSDimitry Andric 500bdd1243dSDimitry Andric if (FI >= MinCSFI && FI <= MaxCSFI) { 501753f127fSDimitry Andric FrameReg = LoongArch::R3; 502bdd1243dSDimitry Andric if (FirstSPAdjustAmount) 503bdd1243dSDimitry Andric Offset += StackOffset::getFixed(FirstSPAdjustAmount); 504bdd1243dSDimitry Andric else 505bdd1243dSDimitry Andric Offset += StackOffset::getFixed(StackSize); 506bdd1243dSDimitry Andric } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { 507bdd1243dSDimitry Andric // If the stack was realigned, the frame pointer is set in order to allow 508bdd1243dSDimitry Andric // SP to be restored, so we need another base register to record the stack 509bdd1243dSDimitry Andric // after realignment. 510bdd1243dSDimitry Andric FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3; 511bdd1243dSDimitry Andric Offset += StackOffset::getFixed(StackSize); 512bdd1243dSDimitry Andric } else { 513bdd1243dSDimitry Andric FrameReg = RI->getFrameRegister(MF); 514bdd1243dSDimitry Andric if (hasFP(MF)) 515bdd1243dSDimitry Andric Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize()); 516bdd1243dSDimitry Andric else 517bdd1243dSDimitry Andric Offset += StackOffset::getFixed(StackSize); 518753f127fSDimitry Andric } 519753f127fSDimitry Andric 520753f127fSDimitry Andric return Offset; 52181ad6265SDimitry Andric } 522*06c3fb27SDimitry Andric 523*06c3fb27SDimitry Andric bool LoongArchFrameLowering::enableShrinkWrapping( 524*06c3fb27SDimitry Andric const MachineFunction &MF) const { 525*06c3fb27SDimitry Andric // Keep the conventional code flow when not optimizing. 526*06c3fb27SDimitry Andric if (MF.getFunction().hasOptNone()) 527*06c3fb27SDimitry Andric return false; 528*06c3fb27SDimitry Andric 529*06c3fb27SDimitry Andric return true; 530*06c3fb27SDimitry Andric } 531