#include "LoongArchFrameLowering.h"
#include "LoongArchMachineFunctionInfo.h"
#include "LoongArchSubtarget.h"
#include "MCTargetDesc/LoongArchBaseInfo.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"
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();
if (DestReg == SrcReg && Val == 0)
return;
if (isInt<12>(Val)) {
BuildMI(MBB, MBBI, DL,
TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), DestReg)
.addReg(SrcReg)
.addImm(Val)
.setMIFlag(Flag);
return;
}
report_fatal_error("adjustReg cannot yet handle adjustments >12 bits");
}
void LoongArchFrameLowering::determineFrameLayout(MachineFunction &MF) const {
MachineFrameInfo &MFI = MF.getFrameInfo();
uint64_t FrameSize = MFI.getStackSize();
FrameSize = alignTo(FrameSize, getStackAlign());
MFI.setStackSize(FrameSize);
}
void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineFrameInfo &MFI = MF.getFrameInfo();
const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
const LoongArchInstrInfo *TII = STI.getInstrInfo();
MachineBasicBlock::iterator MBBI = MBB.begin();
Register SPReg = LoongArch::R3;
Register FPReg = LoongArch::R22;
DebugLoc DL;
determineFrameLayout(MF);
uint64_t StackSize = MFI.getStackSize();
if (StackSize == 0 && !MFI.adjustsStack())
return;
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
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();
std::advance(MBBI, CSI.size());
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);
}
if (hasFP(MF)) {
adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize, MachineInstr::FrameSetup);
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
nullptr, RI->getDwarfRegNum(FPReg, true), 0));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);
}
}
void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
const LoongArchRegisterInfo *RI = STI.getRegisterInfo();
MachineFrameInfo &MFI = MF.getFrameInfo();
Register SPReg = LoongArch::R3;
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
const auto &CSI = MFI.getCalleeSavedInfo();
auto LastFrameDestroy = MBBI;
if (!CSI.empty())
LastFrameDestroy = std::prev(MBBI, CSI.size());
uint64_t StackSize = MFI.getStackSize();
if (RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects()) {
assert(hasFP(MF) && "frame pointer should not have been eliminated");
adjustReg(MBB, LastFrameDestroy, DL, SPReg, LoongArch::R22, -StackSize,
MachineInstr::FrameDestroy);
}
adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
}
void LoongArchFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
if (hasFP(MF)) {
SavedRegs.set(LoongArch::R1);
SavedRegs.set(LoongArch::R22);
}
if (hasBP(MF))
SavedRegs.set(LoongArchABI::getBPReg());
}
StackOffset LoongArchFrameLowering::getFrameIndexReference(
const MachineFunction &MF, int FI, Register &FrameReg) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
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();
}
FrameReg = RI->getFrameRegister(MF);
if ((FI >= MinCSFI && FI <= MaxCSFI) || !hasFP(MF)) {
FrameReg = LoongArch::R3;
Offset += StackOffset::getFixed(MFI.getStackSize());
}
return Offset;
}