aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp')
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp226
1 files changed, 213 insertions, 13 deletions
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
index a85b054a85d7..903ee76fbc8d 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
@@ -17,6 +17,7 @@
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "MCTargetDesc/LoongArchMatInt.h"
#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/CodeGen/StackMaps.h"
#include "llvm/MC/MCInstBuilder.h"
using namespace llvm;
@@ -39,7 +40,9 @@ MCInst LoongArchInstrInfo::getNop() const {
void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, MCRegister DstReg,
- MCRegister SrcReg, bool KillSrc) const {
+ MCRegister SrcReg, bool KillSrc,
+ bool RenamableDest,
+ bool RenamableSrc) const {
if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {
BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)
.addReg(SrcReg, getKillRegState(KillSrc))
@@ -110,7 +113,8 @@ void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
void LoongArchInstrInfo::storeRegToStackSlot(
MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,
bool IsKill, int FI, const TargetRegisterClass *RC,
- const TargetRegisterInfo *TRI, Register VReg) const {
+ const TargetRegisterInfo *TRI, Register VReg,
+ MachineInstr::MIFlag Flags) const {
MachineFunction *MF = MBB.getParent();
MachineFrameInfo &MFI = MF->getFrameInfo();
@@ -143,14 +147,15 @@ void LoongArchInstrInfo::storeRegToStackSlot(
.addMemOperand(MMO);
}
-void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I,
- Register DstReg, int FI,
- const TargetRegisterClass *RC,
- const TargetRegisterInfo *TRI,
- Register VReg) const {
+void LoongArchInstrInfo::loadRegFromStackSlot(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DstReg,
+ int FI, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI,
+ Register VReg, MachineInstr::MIFlag Flags) const {
MachineFunction *MF = MBB.getParent();
MachineFrameInfo &MFI = MF->getFrameInfo();
+ DebugLoc DL;
+ if (I != MBB.end())
+ DL = I->getDebugLoc();
unsigned Opcode;
if (LoongArch::GPRRegClass.hasSubClassEq(RC))
@@ -174,7 +179,7 @@ void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
- BuildMI(MBB, I, DebugLoc(), get(Opcode), DstReg)
+ BuildMI(MBB, I, DL, get(Opcode), DstReg)
.addFrameIndex(FI)
.addImm(0)
.addMemOperand(MMO);
@@ -208,6 +213,14 @@ void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
.addImm(Inst.Imm)
.setMIFlag(Flag);
break;
+ case LoongArch::BSTRINS_D:
+ BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
+ .addReg(SrcReg, RegState::Kill)
+ .addReg(SrcReg, RegState::Kill)
+ .addImm(Inst.Imm >> 32)
+ .addImm(Inst.Imm & 0xFF)
+ .setMIFlag(Flag);
+ break;
default:
assert(false && "Unknown insn emitted by LoongArchMatInt");
}
@@ -226,7 +239,25 @@ unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
}
- return MI.getDesc().getSize();
+
+ unsigned NumBytes = 0;
+ const MCInstrDesc &Desc = MI.getDesc();
+
+ // Size should be preferably set in
+ // llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).
+ // Specific cases handle instructions of variable sizes.
+ switch (Desc.getOpcode()) {
+ default:
+ return Desc.getSize();
+ case TargetOpcode::STATEPOINT:
+ NumBytes = StatepointOpers(&MI).getNumPatchBytes();
+ assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
+ // No patch bytes means a normal call inst (i.e. `bl`) is emitted.
+ if (NumBytes == 0)
+ NumBytes = 4;
+ break;
+ }
+ return NumBytes;
}
bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {
@@ -347,6 +378,162 @@ bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
}
}
+bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
+ const MachineBasicBlock *MBB,
+ const MachineFunction &MF) const {
+ if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
+ return true;
+
+ auto MII = MI.getIterator();
+ auto MIE = MBB->end();
+
+ // According to psABI v2.30:
+ //
+ // https://github.com/loongson/la-abi-specs/releases/tag/v2.30
+ //
+ // The following instruction patterns are prohibited from being reordered:
+ //
+ // * pcalau12i $a0, %pc_hi20(s)
+ // addi.d $a1, $zero, %pc_lo12(s)
+ // lu32i.d $a1, %pc64_lo20(s)
+ // lu52i.d $a1, $a1, %pc64_hi12(s)
+ //
+ // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s)
+ // addi.d $a1, $zero, %got_pc_lo12(s)
+ // lu32i.d $a1, %got64_pc_lo20(s)
+ // lu52i.d $a1, $a1, %got64_pc_hi12(s)
+ //
+ // * pcalau12i $a0, %ie_pc_hi20(s)
+ // addi.d $a1, $zero, %ie_pc_lo12(s)
+ // lu32i.d $a1, %ie64_pc_lo20(s)
+ // lu52i.d $a1, $a1, %ie64_pc_hi12(s)
+ //
+ // * pcalau12i $a0, %desc_pc_hi20(s)
+ // addi.d $a1, $zero, %desc_pc_lo12(s)
+ // lu32i.d $a1, %desc64_pc_lo20(s)
+ // lu52i.d $a1, $a1, %desc64_pc_hi12(s)
+ //
+ // For simplicity, only pcalau12i and lu52i.d are marked as scheduling
+ // boundaries, and the instructions between them are guaranteed to be
+ // ordered according to data dependencies.
+ switch (MI.getOpcode()) {
+ case LoongArch::PCALAU12I: {
+ auto AddI = std::next(MII);
+ if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)
+ break;
+ auto Lu32I = std::next(AddI);
+ if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D)
+ break;
+ auto MO0 = MI.getOperand(1).getTargetFlags();
+ auto MO1 = AddI->getOperand(2).getTargetFlags();
+ auto MO2 = Lu32I->getOperand(2).getTargetFlags();
+ if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&
+ MO2 == LoongArchII::MO_PCREL64_LO)
+ return true;
+ if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||
+ MO0 == LoongArchII::MO_GD_PC_HI) &&
+ MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)
+ return true;
+ if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&
+ MO2 == LoongArchII::MO_IE_PC64_LO)
+ return true;
+ if (MO0 == LoongArchII::MO_DESC_PC_HI &&
+ MO1 == LoongArchII::MO_DESC_PC_LO &&
+ MO2 == LoongArchII::MO_DESC64_PC_LO)
+ return true;
+ break;
+ }
+ case LoongArch::LU52I_D: {
+ auto MO = MI.getOperand(2).getTargetFlags();
+ if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||
+ MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)
+ return true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ const auto &STI = MF.getSubtarget<LoongArchSubtarget>();
+ if (STI.hasFeature(LoongArch::FeatureRelax)) {
+ // When linker relaxation enabled, the following instruction patterns are
+ // prohibited from being reordered:
+ //
+ // * pcalau12i $a0, %pc_hi20(s)
+ // addi.w/d $a0, $a0, %pc_lo12(s)
+ //
+ // * pcalau12i $a0, %got_pc_hi20(s)
+ // ld.w/d $a0, $a0, %got_pc_lo12(s)
+ //
+ // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)
+ // addi.w/d $a0, $a0, %got_pc_lo12(s)
+ //
+ // * pcalau12i $a0, %desc_pc_hi20(s)
+ // addi.w/d $a0, $a0, %desc_pc_lo12(s)
+ // ld.w/d $ra, $a0, %desc_ld(s)
+ // jirl $ra, $ra, %desc_call(s)
+ unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
+ unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
+ switch (MI.getOpcode()) {
+ case LoongArch::PCALAU12I: {
+ auto MO0 = LoongArchII::getDirectFlags(MI.getOperand(1));
+ auto SecondOp = std::next(MII);
+ if (MO0 == LoongArchII::MO_DESC_PC_HI) {
+ if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)
+ break;
+ auto Ld = std::next(SecondOp);
+ if (Ld == MIE || Ld->getOpcode() != LdOp)
+ break;
+ auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
+ auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));
+ if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
+ return true;
+ break;
+ }
+ if (SecondOp == MIE ||
+ (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))
+ break;
+ auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
+ if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
+ MO1 == LoongArchII::MO_PCREL_LO)
+ return true;
+ if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
+ MO1 == LoongArchII::MO_GOT_PC_LO)
+ return true;
+ if ((MO0 == LoongArchII::MO_LD_PC_HI ||
+ MO0 == LoongArchII::MO_GD_PC_HI) &&
+ SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
+ return true;
+ break;
+ }
+ case LoongArch::ADDI_W:
+ case LoongArch::ADDI_D: {
+ auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
+ if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
+ return true;
+ break;
+ }
+ case LoongArch::LD_W:
+ case LoongArch::LD_D: {
+ auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
+ if (MO == LoongArchII::MO_GOT_PC_LO)
+ return true;
+ break;
+ }
+ case LoongArch::PseudoDESC_CALL: {
+ auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
+ if (MO == LoongArchII::MO_DESC_CALL)
+ return true;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved) const {
if (BytesRemoved)
@@ -519,7 +706,8 @@ bool LoongArchInstrInfo::reverseBranchCondition(
std::pair<unsigned, unsigned>
LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
- return std::make_pair(TF, 0u);
+ const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;
+ return std::make_pair(TF & Mask, TF & ~Mask);
}
ArrayRef<std::pair<unsigned, const char *>>
@@ -545,14 +733,26 @@ LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
{MO_IE_PC_LO, "loongarch-ie-pc-lo"},
{MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
{MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
+ {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
+ {MO_GD_PC_HI, "loongarch-gd-pc-hi"},
+ {MO_CALL36, "loongarch-call36"},
{MO_DESC_PC_HI, "loongarch-desc-pc-hi"},
{MO_DESC_PC_LO, "loongarch-desc-pc-lo"},
{MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},
{MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},
{MO_DESC_LD, "loongarch-desc-ld"},
{MO_DESC_CALL, "loongarch-desc-call"},
- {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
- {MO_GD_PC_HI, "loongarch-gd-pc-hi"}};
+ {MO_LE_HI_R, "loongarch-le-hi-r"},
+ {MO_LE_ADD_R, "loongarch-le-add-r"},
+ {MO_LE_LO_R, "loongarch-le-lo-r"}};
+ return ArrayRef(TargetFlags);
+}
+
+ArrayRef<std::pair<unsigned, const char *>>
+LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
+ using namespace LoongArchII;
+ static const std::pair<unsigned, const char *> TargetFlags[] = {
+ {MO_RELAX, "loongarch-relax"}};
return ArrayRef(TargetFlags);
}