513 lines · cpp
1//===-- LoongArchFrameLowering.cpp - LoongArch Frame Information -*- C++ -*-==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the LoongArch implementation of TargetFrameLowering class.10//11//===----------------------------------------------------------------------===//12 13#include "LoongArchFrameLowering.h"14#include "LoongArchMachineFunctionInfo.h"15#include "LoongArchSubtarget.h"16#include "MCTargetDesc/LoongArchBaseInfo.h"17#include "MCTargetDesc/LoongArchMCTargetDesc.h"18#include "llvm/CodeGen/MachineFrameInfo.h"19#include "llvm/CodeGen/MachineFunction.h"20#include "llvm/CodeGen/MachineInstrBuilder.h"21#include "llvm/CodeGen/MachineRegisterInfo.h"22#include "llvm/CodeGen/RegisterScavenging.h"23#include "llvm/IR/DiagnosticInfo.h"24#include "llvm/MC/MCDwarf.h"25 26using namespace llvm;27 28#define DEBUG_TYPE "loongarch-frame-lowering"29 30// Return true if the specified function should have a dedicated frame31// pointer register. This is true if frame pointer elimination is32// disabled, if it needs dynamic stack realignment, if the function has33// variable sized allocas, or if the frame address is taken.34bool LoongArchFrameLowering::hasFPImpl(const MachineFunction &MF) const {35 const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();36 37 const MachineFrameInfo &MFI = MF.getFrameInfo();38 return MF.getTarget().Options.DisableFramePointerElim(MF) ||39 RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||40 MFI.isFrameAddressTaken();41}42 43bool LoongArchFrameLowering::hasBP(const MachineFunction &MF) const {44 const MachineFrameInfo &MFI = MF.getFrameInfo();45 const TargetRegisterInfo *TRI = STI.getRegisterInfo();46 47 return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);48}49 50void LoongArchFrameLowering::adjustReg(MachineBasicBlock &MBB,51 MachineBasicBlock::iterator MBBI,52 const DebugLoc &DL, Register DestReg,53 Register SrcReg, int64_t Val,54 MachineInstr::MIFlag Flag) const {55 const LoongArchInstrInfo *TII = STI.getInstrInfo();56 bool IsLA64 = STI.is64Bit();57 unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;58 59 if (DestReg == SrcReg && Val == 0)60 return;61 62 if (isInt<12>(Val)) {63 // addi.w/d $DstReg, $SrcReg, Val64 BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)65 .addReg(SrcReg)66 .addImm(Val)67 .setMIFlag(Flag);68 return;69 }70 71 // Try to split the offset across two ADDIs. We need to keep the stack pointer72 // aligned after each ADDI. We need to determine the maximum value we can put73 // in each ADDI. In the negative direction, we can use -2048 which is always74 // sufficiently aligned. In the positive direction, we need to find the75 // largest 12-bit immediate that is aligned. Exclude -4096 since it can be76 // created with LU12I.W.77 assert(getStackAlign().value() < 2048 && "Stack alignment too large");78 int64_t MaxPosAdjStep = 2048 - getStackAlign().value();79 if (Val > -4096 && Val <= (2 * MaxPosAdjStep)) {80 int64_t FirstAdj = Val < 0 ? -2048 : MaxPosAdjStep;81 Val -= FirstAdj;82 BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)83 .addReg(SrcReg)84 .addImm(FirstAdj)85 .setMIFlag(Flag);86 BuildMI(MBB, MBBI, DL, TII->get(Addi), DestReg)87 .addReg(DestReg, RegState::Kill)88 .addImm(Val)89 .setMIFlag(Flag);90 return;91 }92 93 unsigned Opc = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;94 if (Val < 0) {95 Val = -Val;96 Opc = IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W;97 }98 99 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();100 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);101 TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag);102 BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)103 .addReg(SrcReg)104 .addReg(ScratchReg, RegState::Kill)105 .setMIFlag(Flag);106}107 108// Determine the size of the frame and maximum call frame size.109void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {110 MachineFrameInfo &MFI = MF.getFrameInfo();111 112 // Get the number of bytes to allocate from the FrameInfo.113 uint64_t FrameSize = MFI.getStackSize();114 115 // Make sure the frame is aligned.116 FrameSize = alignTo(FrameSize, getStackAlign());117 118 // Update frame info.119 MFI.setStackSize(FrameSize);120}121 122static uint64_t estimateFunctionSizeInBytes(const LoongArchInstrInfo *TII,123 const MachineFunction &MF) {124 uint64_t FuncSize = 0;125 for (auto &MBB : MF)126 for (auto &MI : MBB)127 FuncSize += TII->getInstSizeInBytes(MI);128 return FuncSize;129}130 131static bool needScavSlotForCFR(MachineFunction &MF) {132 if (!MF.getSubtarget<LoongArchSubtarget>().hasBasicF())133 return false;134 for (auto &MBB : MF)135 for (auto &MI : MBB)136 if (MI.getOpcode() == LoongArch::PseudoST_CFR)137 return true;138 return false;139}140 141void LoongArchFrameLowering::processFunctionBeforeFrameFinalized(142 MachineFunction &MF, RegScavenger *RS) const {143 const LoongArchRegisterInfo *RI = STI.getRegisterInfo();144 const TargetRegisterClass &RC = LoongArch::GPRRegClass;145 const LoongArchInstrInfo *TII = STI.getInstrInfo();146 LoongArchMachineFunctionInfo *LAFI =147 MF.getInfo<LoongArchMachineFunctionInfo>();148 MachineFrameInfo &MFI = MF.getFrameInfo();149 150 unsigned ScavSlotsNum = 0;151 152 // Far branches beyond 27-bit offset require a spill slot for scratch153 // register.154 bool IsLargeFunction = !isInt<27>(estimateFunctionSizeInBytes(TII, MF));155 if (IsLargeFunction)156 ScavSlotsNum = 1;157 158 // estimateStackSize has been observed to under-estimate the final stack159 // size, so give ourselves wiggle-room by checking for stack size160 // representable an 11-bit signed field rather than 12-bits.161 // For [x]vstelm.{b/h/w/d} memory instructions with 8 imm offset, 7-bit162 // signed field is fine.163 unsigned EstimateStackSize = MFI.estimateStackSize(MF);164 if (!isInt<11>(EstimateStackSize) ||165 (MF.getSubtarget<LoongArchSubtarget>().hasExtLSX() &&166 !isInt<7>(EstimateStackSize)))167 ScavSlotsNum = std::max(ScavSlotsNum, 1u);168 169 // For CFR spill.170 if (needScavSlotForCFR(MF))171 ++ScavSlotsNum;172 173 // Create emergency spill slots.174 for (unsigned i = 0; i < ScavSlotsNum; ++i) {175 int FI =176 MFI.CreateSpillStackObject(RI->getSpillSize(RC), RI->getSpillAlign(RC));177 RS->addScavengingFrameIndex(FI);178 if (IsLargeFunction && LAFI->getBranchRelaxationSpillFrameIndex() == -1)179 LAFI->setBranchRelaxationSpillFrameIndex(FI);180 LLVM_DEBUG(dbgs() << "Allocated FI(" << FI181 << ") as the emergency spill slot.\n");182 }183}184 185void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,186 MachineBasicBlock &MBB) const {187 MachineFrameInfo &MFI = MF.getFrameInfo();188 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();189 const LoongArchRegisterInfo *RI = STI.getRegisterInfo();190 const LoongArchInstrInfo *TII = STI.getInstrInfo();191 MachineBasicBlock::iterator MBBI = MBB.begin();192 bool IsLA64 = STI.is64Bit();193 194 Register SPReg = LoongArch::R3;195 Register FPReg = LoongArch::R22;196 197 // Debug location must be unknown since the first debug location is used198 // to determine the end of the prologue.199 DebugLoc DL;200 // All calls are tail calls in GHC calling conv, and functions have no201 // prologue/epilogue.202 if (MF.getFunction().getCallingConv() == CallingConv::GHC)203 return;204 // Determine the correct frame layout205 determineFrameLayout(MF);206 207 // First, compute final stack size.208 uint64_t StackSize = MFI.getStackSize();209 uint64_t RealStackSize = StackSize;210 211 // Early exit if there is no need to allocate space in the stack.212 if (StackSize == 0 && !MFI.adjustsStack())213 return;214 215 uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);216 // Split the SP adjustment to reduce the offsets of callee saved spill.217 if (FirstSPAdjustAmount)218 StackSize = FirstSPAdjustAmount;219 220 // Adjust stack.221 adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);222 // Emit ".cfi_def_cfa_offset StackSize".223 unsigned CFIIndex =224 MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));225 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))226 .addCFIIndex(CFIIndex)227 .setMIFlag(MachineInstr::FrameSetup);228 229 const auto &CSI = MFI.getCalleeSavedInfo();230 231 // The frame pointer is callee-saved, and code has been generated for us to232 // save it to the stack. We need to skip over the storing of callee-saved233 // registers as the frame pointer must be modified after it has been saved234 // to the stack, not before.235 std::advance(MBBI, CSI.size());236 237 // Iterate over list of callee-saved registers and emit .cfi_offset238 // directives.239 for (const auto &Entry : CSI) {240 int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());241 unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(242 nullptr, RI->getDwarfRegNum(Entry.getReg(), true), Offset));243 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))244 .addCFIIndex(CFIIndex)245 .setMIFlag(MachineInstr::FrameSetup);246 }247 248 // Generate new FP.249 if (hasFP(MF)) {250 adjustReg(MBB, MBBI, DL, FPReg, SPReg,251 StackSize - LoongArchFI->getVarArgsSaveSize(),252 MachineInstr::FrameSetup);253 254 // Emit ".cfi_def_cfa $fp, LoongArchFI->getVarArgsSaveSize()"255 unsigned CFIIndex = MF.addFrameInst(256 MCCFIInstruction::cfiDefCfa(nullptr, RI->getDwarfRegNum(FPReg, true),257 LoongArchFI->getVarArgsSaveSize()));258 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))259 .addCFIIndex(CFIIndex)260 .setMIFlag(MachineInstr::FrameSetup);261 }262 263 // Emit the second SP adjustment after saving callee saved registers.264 if (FirstSPAdjustAmount) {265 uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;266 assert(SecondSPAdjustAmount > 0 &&267 "SecondSPAdjustAmount should be greater than zero");268 adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,269 MachineInstr::FrameSetup);270 271 if (!hasFP(MF)) {272 // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",273 // don't emit an sp-based .cfi_def_cfa_offset274 // Emit ".cfi_def_cfa_offset RealStackSize"275 unsigned CFIIndex = MF.addFrameInst(276 MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));277 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))278 .addCFIIndex(CFIIndex)279 .setMIFlag(MachineInstr::FrameSetup);280 }281 }282 283 if (hasFP(MF)) {284 // Realign stack.285 if (RI->hasStackRealignment(MF)) {286 unsigned Align = Log2(MFI.getMaxAlign());287 assert(Align > 0 && "The stack realignment size is invalid!");288 BuildMI(MBB, MBBI, DL,289 TII->get(IsLA64 ? LoongArch::BSTRINS_D : LoongArch::BSTRINS_W),290 SPReg)291 .addReg(SPReg)292 .addReg(LoongArch::R0)293 .addImm(Align - 1)294 .addImm(0)295 .setMIFlag(MachineInstr::FrameSetup);296 // FP will be used to restore the frame in the epilogue, so we need297 // another base register BP to record SP after re-alignment. SP will298 // track the current stack after allocating variable sized objects.299 if (hasBP(MF)) {300 // move BP, $sp301 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::OR),302 LoongArchABI::getBPReg())303 .addReg(SPReg)304 .addReg(LoongArch::R0)305 .setMIFlag(MachineInstr::FrameSetup);306 }307 }308 }309}310 311void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,312 MachineBasicBlock &MBB) const {313 const LoongArchRegisterInfo *RI = STI.getRegisterInfo();314 MachineFrameInfo &MFI = MF.getFrameInfo();315 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();316 Register SPReg = LoongArch::R3;317 // All calls are tail calls in GHC calling conv, and functions have no318 // prologue/epilogue.319 if (MF.getFunction().getCallingConv() == CallingConv::GHC)320 return;321 MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();322 DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();323 324 const auto &CSI = MFI.getCalleeSavedInfo();325 // Skip to before the restores of callee-saved registers.326 auto LastFrameDestroy = MBBI;327 if (!CSI.empty())328 LastFrameDestroy = std::prev(MBBI, CSI.size());329 330 // Get the number of bytes from FrameInfo.331 uint64_t StackSize = MFI.getStackSize();332 333 // Restore the stack pointer.334 if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {335 assert(hasFP(MF) && "frame pointer should not have been eliminated");336 adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22,337 -StackSize + LoongArchFI->getVarArgsSaveSize(),338 MachineInstr::FrameDestroy);339 }340 341 uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);342 if (FirstSPAdjustAmount) {343 uint64_t SecondSPAdjustAmount = StackSize - FirstSPAdjustAmount;344 assert(SecondSPAdjustAmount > 0 &&345 "SecondSPAdjustAmount should be greater than zero");346 347 adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount,348 MachineInstr::FrameDestroy);349 StackSize = FirstSPAdjustAmount;350 }351 352 // Deallocate stack353 adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);354}355 356// We would like to split the SP adjustment to reduce prologue/epilogue357// as following instructions. In this way, the offset of the callee saved358// register could fit in a single store.359// e.g.360// addi.d $sp, $sp, -2032361// st.d $ra, $sp, 2024362// st.d $fp, $sp, 2016363// addi.d $sp, $sp, -16364uint64_t LoongArchFrameLowering::getFirstSPAdjustAmount(365 const MachineFunction &MF) const {366 const MachineFrameInfo &MFI = MF.getFrameInfo();367 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();368 369 // Return the FirstSPAdjustAmount if the StackSize can not fit in a signed370 // 12-bit and there exists a callee-saved register needing to be pushed.371 if (!isInt<12>(MFI.getStackSize()) && (CSI.size() > 0)) {372 // FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will373 // cause sp = sp + 2048 in the epilogue to be split into multiple374 // instructions. Offsets smaller than 2048 can fit in a single load/store375 // instruction, and we have to stick with the stack alignment.376 // So (2048 - StackAlign) will satisfy the stack alignment.377 return 2048 - getStackAlign().value();378 }379 return 0;380}381 382void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,383 BitVector &SavedRegs,384 RegScavenger *RS) const {385 TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);386 // Unconditionally spill RA and FP only if the function uses a frame387 // pointer.388 if (hasFP(MF)) {389 SavedRegs.set(LoongArch::R1);390 SavedRegs.set(LoongArch::R22);391 }392 // Mark BP as used if function has dedicated base pointer.393 if (hasBP(MF))394 SavedRegs.set(LoongArchABI::getBPReg());395}396 397// Do not preserve stack space within prologue for outgoing variables if the398// function contains variable size objects.399// Let eliminateCallFramePseudoInstr preserve stack space for it.400bool LoongArchFrameLowering::hasReservedCallFrame(401 const MachineFunction &MF) const {402 return !MF.getFrameInfo().hasVarSizedObjects();403}404 405// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.406MachineBasicBlock::iterator407LoongArchFrameLowering::eliminateCallFramePseudoInstr(408 MachineFunction &MF, MachineBasicBlock &MBB,409 MachineBasicBlock::iterator MI) const {410 Register SPReg = LoongArch::R3;411 DebugLoc DL = MI->getDebugLoc();412 413 if (!hasReservedCallFrame(MF)) {414 // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and415 // ADJCALLSTACKUP must be converted to instructions manipulating the stack416 // pointer. This is necessary when there is a variable length stack417 // allocation (e.g. alloca), which means it's not possible to allocate418 // space for outgoing arguments from within the function prologue.419 int64_t Amount = MI->getOperand(0).getImm();420 421 if (Amount != 0) {422 // Ensure the stack remains aligned after adjustment.423 Amount = alignSPAdjust(Amount);424 425 if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN)426 Amount = -Amount;427 428 adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);429 }430 }431 432 return MBB.erase(MI);433}434 435bool LoongArchFrameLowering::spillCalleeSavedRegisters(436 MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,437 ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {438 if (CSI.empty())439 return true;440 441 MachineFunction *MF = MBB.getParent();442 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();443 444 // Insert the spill to the stack frame.445 for (auto &CS : CSI) {446 MCRegister Reg = CS.getReg();447 // If the register is RA and the return address is taken by method448 // LoongArchTargetLowering::lowerRETURNADDR, don't set kill flag.449 bool IsKill =450 !(Reg == LoongArch::R1 && MF->getFrameInfo().isReturnAddressTaken());451 const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);452 TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, CS.getFrameIdx(), RC,453 Register());454 }455 456 return true;457}458 459StackOffset LoongArchFrameLowering::getFrameIndexReference(460 const MachineFunction &MF, int FI, Register &FrameReg) const {461 const MachineFrameInfo &MFI = MF.getFrameInfo();462 const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();463 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();464 uint64_t StackSize = MFI.getStackSize();465 uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);466 467 // Callee-saved registers should be referenced relative to the stack468 // pointer (positive offset), otherwise use the frame pointer (negative469 // offset).470 const auto &CSI = MFI.getCalleeSavedInfo();471 int MinCSFI = 0;472 int MaxCSFI = -1;473 StackOffset Offset =474 StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +475 MFI.getOffsetAdjustment());476 477 if (CSI.size()) {478 MinCSFI = CSI[0].getFrameIdx();479 MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();480 }481 482 if (FI >= MinCSFI && FI <= MaxCSFI) {483 FrameReg = LoongArch::R3;484 if (FirstSPAdjustAmount)485 Offset += StackOffset::getFixed(FirstSPAdjustAmount);486 else487 Offset += StackOffset::getFixed(StackSize);488 } else if (RI->hasStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {489 // If the stack was realigned, the frame pointer is set in order to allow490 // SP to be restored, so we need another base register to record the stack491 // after realignment.492 FrameReg = hasBP(MF) ? LoongArchABI::getBPReg() : LoongArch::R3;493 Offset += StackOffset::getFixed(StackSize);494 } else {495 FrameReg = RI->getFrameRegister(MF);496 if (hasFP(MF))497 Offset += StackOffset::getFixed(LoongArchFI->getVarArgsSaveSize());498 else499 Offset += StackOffset::getFixed(StackSize);500 }501 502 return Offset;503}504 505bool LoongArchFrameLowering::enableShrinkWrapping(506 const MachineFunction &MF) const {507 // Keep the conventional code flow when not optimizing.508 if (MF.getFunction().hasOptNone())509 return false;510 511 return true;512}513