blob: 4037c4d370bb8e43b529b49c274d14f2d78a894c [file] [log] [blame]
//===- LoongArchRegisterInfo.cpp - LoongArch Register 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 the TargetRegisterInfo
// class.
//
//===----------------------------------------------------------------------===//
#include "LoongArchRegisterInfo.h"
#include "LoongArch.h"
#include "LoongArchInstrInfo.h"
#include "LoongArchSubtarget.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
#define GET_REGINFO_TARGET_DESC
#include "LoongArchGenRegisterInfo.inc"
LoongArchRegisterInfo::LoongArchRegisterInfo(unsigned HwMode)
: LoongArchGenRegisterInfo(LoongArch::R1, /*DwarfFlavour*/ 0,
/*EHFlavor*/ 0,
/*PC*/ 0, HwMode) {}
const MCPhysReg *
LoongArchRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
auto &Subtarget = MF->getSubtarget<LoongArchSubtarget>();
if (MF->getFunction().getCallingConv() == CallingConv::GHC)
return CSR_NoRegs_SaveList;
switch (Subtarget.getTargetABI()) {
default:
llvm_unreachable("Unrecognized ABI");
case LoongArchABI::ABI_ILP32S:
case LoongArchABI::ABI_LP64S:
return CSR_ILP32S_LP64S_SaveList;
case LoongArchABI::ABI_ILP32F:
case LoongArchABI::ABI_LP64F:
return CSR_ILP32F_LP64F_SaveList;
case LoongArchABI::ABI_ILP32D:
case LoongArchABI::ABI_LP64D:
return CSR_ILP32D_LP64D_SaveList;
}
}
const uint32_t *
LoongArchRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
auto &Subtarget = MF.getSubtarget<LoongArchSubtarget>();
if (CC == CallingConv::GHC)
return CSR_NoRegs_RegMask;
switch (Subtarget.getTargetABI()) {
default:
llvm_unreachable("Unrecognized ABI");
case LoongArchABI::ABI_ILP32S:
case LoongArchABI::ABI_LP64S:
return CSR_ILP32S_LP64S_RegMask;
case LoongArchABI::ABI_ILP32F:
case LoongArchABI::ABI_LP64F:
return CSR_ILP32F_LP64F_RegMask;
case LoongArchABI::ABI_ILP32D:
case LoongArchABI::ABI_LP64D:
return CSR_ILP32D_LP64D_RegMask;
}
}
const uint32_t *LoongArchRegisterInfo::getNoPreservedMask() const {
return CSR_NoRegs_RegMask;
}
BitVector
LoongArchRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
const LoongArchFrameLowering *TFI = getFrameLowering(MF);
BitVector Reserved(getNumRegs());
// Use markSuperRegs to ensure any register aliases are also reserved
markSuperRegs(Reserved, LoongArch::R0); // zero
markSuperRegs(Reserved, LoongArch::R2); // tp
markSuperRegs(Reserved, LoongArch::R3); // sp
markSuperRegs(Reserved, LoongArch::R21); // non-allocatable
if (TFI->hasFP(MF))
markSuperRegs(Reserved, LoongArch::R22); // fp
// Reserve the base register if we need to realign the stack and allocate
// variable-sized objects at runtime.
if (TFI->hasBP(MF))
markSuperRegs(Reserved, LoongArchABI::getBPReg()); // bp
// FIXME: To avoid generating COPY instructions between CFRs, only use $fcc0.
// This is required to work around the fact that COPY instruction between CFRs
// is not provided in LoongArch.
if (MF.getSubtarget<LoongArchSubtarget>().hasBasicF())
for (size_t Reg = LoongArch::FCC1; Reg <= LoongArch::FCC7; ++Reg)
markSuperRegs(Reserved, Reg);
assert(checkAllSuperRegsMarked(Reserved));
return Reserved;
}
Register
LoongArchRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
const TargetFrameLowering *TFI = getFrameLowering(MF);
return TFI->hasFP(MF) ? LoongArch::R22 : LoongArch::R3;
}
bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj,
unsigned FIOperandNum,
RegScavenger *RS) const {
// TODO: this implementation is a temporary placeholder which does just
// enough to allow other aspects of code generation to be tested.
assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");
MachineInstr &MI = *II;
assert(MI.getOperand(FIOperandNum + 1).isImm() &&
"Unexpected FI-consuming insn");
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MI.getParent()->getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();
const LoongArchSubtarget &STI = MF.getSubtarget<LoongArchSubtarget>();
const LoongArchInstrInfo *TII = STI.getInstrInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
DebugLoc DL = MI.getDebugLoc();
bool IsLA64 = STI.is64Bit();
unsigned MIOpc = MI.getOpcode();
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
Register FrameReg;
StackOffset Offset =
TFI->getFrameIndexReference(MF, FrameIndex, FrameReg) +
StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm());
bool FrameRegIsKill = false;
if (!isInt<12>(Offset.getFixed())) {
unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
unsigned Add = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
// The offset won't fit in an immediate, so use a scratch register instead.
// Modify Offset and FrameReg appropriately.
Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
TII->movImm(MBB, II, DL, ScratchReg, Offset.getFixed());
if (MIOpc == Addi) {
BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg())
.addReg(FrameReg)
.addReg(ScratchReg, RegState::Kill);
MI.eraseFromParent();
return true;
}
BuildMI(MBB, II, DL, TII->get(Add), ScratchReg)
.addReg(FrameReg)
.addReg(ScratchReg, RegState::Kill);
Offset = StackOffset::getFixed(0);
FrameReg = ScratchReg;
FrameRegIsKill = true;
}
// Spill CFRs.
if (MIOpc == LoongArch::PseudoST_CFR) {
Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
BuildMI(MBB, II, DL, TII->get(LoongArch::MOVCF2GR), ScratchReg)
.add(MI.getOperand(0));
BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
.addReg(ScratchReg, RegState::Kill)
.addReg(FrameReg)
.addImm(Offset.getFixed());
MI.eraseFromParent();
return true;
}
// Reload CFRs.
if (MIOpc == LoongArch::PseudoLD_CFR) {
Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::LD_D : LoongArch::LD_W),
ScratchReg)
.addReg(FrameReg)
.addImm(Offset.getFixed());
BuildMI(MBB, II, DL, TII->get(LoongArch::MOVGR2CF))
.add(MI.getOperand(0))
.addReg(ScratchReg, RegState::Kill);
MI.eraseFromParent();
return true;
}
MI.getOperand(FIOperandNum)
.ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getFixed());
return false;
}