[llvm] 0288d06 - [LoongArch] Avoid scheduling relaxable code sequence and attach relax relocs (#121330)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 19 18:00:08 PST 2025
Author: ZhaoQi
Date: 2025-01-20T10:00:05+08:00
New Revision: 0288d065eecb1208971dc4cdcc71731e34c6fca0
URL: https://github.com/llvm/llvm-project/commit/0288d065eecb1208971dc4cdcc71731e34c6fca0
DIFF: https://github.com/llvm/llvm-project/commit/0288d065eecb1208971dc4cdcc71731e34c6fca0.diff
LOG: [LoongArch] Avoid scheduling relaxable code sequence and attach relax relocs (#121330)
If linker relaxation enabled, relaxable code sequence expanded from
pseudos should avoid being separated by instruction scheduling. This
commit tags scheduling boundary for them to avoid being scheduled.
(Except for `tls_le/tls_ie` and `call36/tail36`. Because `tls_le/tls_ie`
can be scheduled and have no influence to relax, `call36/tail36` are
expanded later in `LoongArchExpandPseudo` pass.)
A new mask target-flag is added to attach relax relocs to the relaxable
code sequence. (No need to add it for `tls_le` and `call36/tail36`
because we can simply add relax relocs for them according to their
relocs. But for other code sequence, such as `PCALA_{HI20/LO12}`, we
must use the mask flag, mainly because relax should not be added when
code model is large.)
Because of the new mask target-flag, get "direct" flags is necessary
when using their target-flags. In addition, code sequence after being
optimized by `MergeBaseOffset` pass may not relaxable any more, so the
relax "bitmask" flag should be removed.
Added:
llvm/test/CodeGen/LoongArch/linker-relaxation.ll
llvm/test/CodeGen/LoongArch/mir-relax-flags.ll
Modified:
llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp
llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
llvm/test/CodeGen/LoongArch/mir-target-flags.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
index 0218934ea3344a..c2d73a260b1c1b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
@@ -187,18 +187,21 @@ bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(
MachineInstr &MI = *MBBI;
DebugLoc DL = MI.getDebugLoc();
+ const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
+ bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
+
Register DestReg = MI.getOperand(0).getReg();
Register ScratchReg =
MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
MachineOperand &Symbol = MI.getOperand(1);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
- .addDisp(Symbol, 0, FlagsHi);
+ .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax));
MachineInstr *SecondMI =
BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
.addReg(ScratchReg)
- .addDisp(Symbol, 0, FlagsLo);
+ .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsLo, EnableRelax));
if (MI.hasOneMemOperand())
SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
@@ -481,6 +484,7 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
+ bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
Register DestReg = MI.getOperand(0).getReg();
Register Tmp1Reg =
@@ -488,7 +492,9 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), Tmp1Reg)
- .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI);
+ .addDisp(Symbol, 0,
+ LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_HI,
+ EnableRelax && !Large));
if (Large) {
// Code Sequence:
@@ -526,19 +532,25 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
// pcalau12i $a0, %desc_pc_hi20(sym)
// addi.w/d $a0, $a0, %desc_pc_lo12(sym)
// ld.w/d $ra, $a0, %desc_ld(sym)
- // jirl $ra, $ra, %desc_ld(sym)
- // add.d $dst, $a0, $tp
+ // jirl $ra, $ra, %desc_call(sym)
+ // add.w/d $dst, $a0, $tp
BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
.addReg(Tmp1Reg)
- .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);
+ .addDisp(
+ Symbol, 0,
+ LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_LO, EnableRelax));
}
BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)
.addReg(LoongArch::R4)
- .addDisp(Symbol, 0, LoongArchII::MO_DESC_LD);
+ .addDisp(Symbol, 0,
+ LoongArchII::encodeFlags(LoongArchII::MO_DESC_LD,
+ EnableRelax && !Large));
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
.addReg(LoongArch::R1)
- .addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL);
+ .addDisp(Symbol, 0,
+ LoongArchII::encodeFlags(LoongArchII::MO_DESC_CALL,
+ EnableRelax && !Large));
BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)
.addReg(LoongArch::R4)
.addReg(LoongArch::R2);
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
index 32bc8bb8012957..4e49ba6e339a6c 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
@@ -455,6 +455,83 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
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;
}
@@ -630,7 +707,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 *>>
@@ -656,20 +734,29 @@ 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);
+}
+
// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.
bool LoongArch::isSEXT_W(const MachineInstr &MI) {
return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() &&
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
index ef9970783107ea..a5b31878bfa1c2 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
@@ -91,6 +91,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
ArrayRef<std::pair<unsigned, const char *>>
getSerializableDirectMachineOperandTargetFlags() const override;
+ ArrayRef<std::pair<unsigned, const char *>>
+ getSerializableBitmaskMachineOperandTargetFlags() const override;
+
protected:
const LoongArchSubtarget &STI;
};
diff --git a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
index d1de0609f24ce2..d87ed068ebff8a 100644
--- a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
@@ -27,7 +27,7 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
MCContext &Ctx = AP.OutContext;
LoongArchMCExpr::VariantKind Kind;
- switch (MO.getTargetFlags()) {
+ switch (LoongArchII::getDirectFlags(MO)) {
default:
llvm_unreachable("Unknown target flag on GV operand");
case LoongArchII::MO_None:
@@ -134,7 +134,7 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
if (Kind != LoongArchMCExpr::VK_LoongArch_None)
- ME = LoongArchMCExpr::create(ME, Kind, Ctx);
+ ME = LoongArchMCExpr::create(ME, Kind, Ctx, LoongArchII::hasRelaxFlag(MO));
return MCOperand::createExpr(ME);
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp b/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp
index e9455fdd23ba54..7f98f7718a538d 100644
--- a/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp
@@ -105,7 +105,7 @@ bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20,
return false;
const MachineOperand &Hi20Op1 = Hi20.getOperand(1);
- if (Hi20Op1.getTargetFlags() != LoongArchII::MO_PCREL_HI)
+ if (LoongArchII::getDirectFlags(Hi20Op1) != LoongArchII::MO_PCREL_HI)
return false;
auto isGlobalOrCPIOrBlockAddress = [](const MachineOperand &Op) {
@@ -157,7 +157,7 @@ bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20,
const MachineOperand &Lo12Op2 = Lo12->getOperand(2);
assert(Hi20.getOpcode() == LoongArch::PCALAU12I);
- if (Lo12Op2.getTargetFlags() != LoongArchII::MO_PCREL_LO ||
+ if (LoongArchII::getDirectFlags(Lo12Op2) != LoongArchII::MO_PCREL_LO ||
!(isGlobalOrCPIOrBlockAddress(Lo12Op2) || Lo12Op2.isMCSymbol()) ||
Lo12Op2.getOffset() != 0)
return false;
@@ -597,9 +597,28 @@ bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
if (!isInt<32>(NewOffset))
return false;
+ // If optimized by this pass successfully, MO_RELAX bitmask target-flag should
+ // be removed from the code sequence.
+ //
+ // For example:
+ // pcalau12i $a0, %pc_hi20(symbol)
+ // addi.d $a0, $a0, %pc_lo12(symbol)
+ // ld.w $a0, $a0, 0
+ //
+ // =>
+ //
+ // pcalau12i $a0, %pc_hi20(symbol)
+ // ld.w $a0, $a0, %pc_lo12(symbol)
+ //
+ // Code sequence optimized before can be relax by linker. But after being
+ // optimized, it cannot be relaxed any more. So MO_RELAX flag should not be
+ // carried by them.
Hi20.getOperand(1).setOffset(NewOffset);
+ Hi20.getOperand(1).setTargetFlags(
+ LoongArchII::getDirectFlags(Hi20.getOperand(1)));
MachineOperand &ImmOp = Lo12.getOperand(2);
ImmOp.setOffset(NewOffset);
+ ImmOp.setTargetFlags(LoongArchII::getDirectFlags(ImmOp));
if (Lo20 && Hi12) {
Lo20->getOperand(2).setOffset(NewOffset);
Hi12->getOperand(2).setOffset(NewOffset);
@@ -617,15 +636,16 @@ bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
switch (ImmOp.getType()) {
case MachineOperand::MO_GlobalAddress:
MO.ChangeToGA(ImmOp.getGlobal(), ImmOp.getOffset(),
- ImmOp.getTargetFlags());
+ LoongArchII::getDirectFlags(ImmOp));
break;
case MachineOperand::MO_MCSymbol:
- MO.ChangeToMCSymbol(ImmOp.getMCSymbol(), ImmOp.getTargetFlags());
+ MO.ChangeToMCSymbol(ImmOp.getMCSymbol(),
+ LoongArchII::getDirectFlags(ImmOp));
MO.setOffset(ImmOp.getOffset());
break;
case MachineOperand::MO_BlockAddress:
MO.ChangeToBA(ImmOp.getBlockAddress(), ImmOp.getOffset(),
- ImmOp.getTargetFlags());
+ LoongArchII::getDirectFlags(ImmOp));
break;
default:
report_fatal_error("unsupported machine operand type");
diff --git a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
index b611365f608af9..62b08be5435cda 100644
--- a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
@@ -38,6 +38,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTarget() {
initializeLoongArchMergeBaseOffsetOptPass(*PR);
initializeLoongArchOptWInstrsPass(*PR);
initializeLoongArchPreRAExpandPseudoPass(*PR);
+ initializeLoongArchExpandPseudoPass(*PR);
initializeLoongArchDAGToDAGISelLegacyPass(*PR);
}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
index 23699043b9926a..833cd062616244 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
@@ -17,6 +17,7 @@
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/TargetParser/SubtargetFeature.h"
@@ -58,8 +59,31 @@ enum {
MO_LE_ADD_R,
MO_LE_LO_R,
// TODO: Add more flags.
+
+ // Used to
diff erentiate between target-specific "direct" flags and "bitmask"
+ // flags. A machine operand can only have one "direct" flag, but can have
+ // multiple "bitmask" flags.
+ MO_DIRECT_FLAG_MASK = 0x3f,
+
+ MO_RELAX = 0x40
};
+// Given a MachineOperand that may carry out "bitmask" flags, such as MO_RELAX,
+// return LoongArch target-specific "direct" flags.
+static inline unsigned getDirectFlags(const MachineOperand &MO) {
+ return MO.getTargetFlags() & MO_DIRECT_FLAG_MASK;
+}
+
+// Add MO_RELAX "bitmask" flag when FeatureRelax is enabled.
+static inline unsigned encodeFlags(unsigned Flags, bool Relax) {
+ return Flags | (Relax ? MO_RELAX : 0);
+}
+
+// \returns true if the given MachineOperand has MO_RELAX "bitmask" flag.
+static inline bool hasRelaxFlag(const MachineOperand &MO) {
+ return MO.getTargetFlags() & MO_RELAX;
+}
+
// Target-specific flags of LAInst.
// All definitions must match LoongArchInstrFormats.td.
enum {
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
index 04d57f0fe74573..02ec321857e576 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
@@ -249,6 +249,7 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
break;
case LoongArchMCExpr::VK_LoongArch_CALL36:
FixupKind = LoongArch::fixup_loongarch_call36;
+ RelaxCandidate = true;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20:
FixupKind = LoongArch::fixup_loongarch_tls_desc_pc_hi20;
diff --git a/llvm/test/CodeGen/LoongArch/linker-relaxation.ll b/llvm/test/CodeGen/LoongArch/linker-relaxation.ll
new file mode 100644
index 00000000000000..2827a95547903b
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/linker-relaxation.ll
@@ -0,0 +1,102 @@
+; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=-relax \
+; RUN: --relocation-model=pic --code-model=medium < %s \
+; RUN: | llvm-readobj -r - | FileCheck --check-prefixes=CHECK-RELOC,PCALA-RELOC %s
+; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=+relax \
+; RUN: --relocation-model=pic --code-model=medium < %s \
+; RUN: | llvm-readobj -r - | FileCheck --check-prefixes=CHECK-RELOC,RELAX %s
+
+; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=-relax --enable-tlsdesc \
+; RUN: --relocation-model=pic --code-model=medium < %s \
+; RUN: | llvm-readobj -r - | FileCheck --check-prefix=DESC-RELOC %s
+; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=+relax --enable-tlsdesc \
+; RUN: --relocation-model=pic --code-model=medium < %s \
+; RUN: | llvm-readobj -r - | FileCheck --check-prefixes=DESC-RELOC,DESC-RELAX %s
+
+;; Check relocations when disable or enable linker relaxation.
+;; This tests are also able to test for removing relax mask flags
+;; after loongarch-merge-base-offset pass because no relax relocs
+;; are emitted after being optimized by it.
+
+ at g_e = external global i32
+ at g_i = internal global i32 0
+ at g_i1 = internal global i32 1
+ at t_un = external thread_local global i32
+ at t_ld = external thread_local(localdynamic) global i32
+ at t_ie = external thread_local(initialexec) global i32
+ at t_le = external thread_local(localexec) global i32
+
+declare void @callee1() nounwind
+declare dso_local void @callee2() nounwind
+declare dso_local void @callee3() nounwind
+
+define ptr @caller() nounwind {
+; RELAX: R_LARCH_ALIGN - 0x1C
+; CHECK-RELOC: R_LARCH_GOT_PC_HI20 g_e 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_GOT_PC_LO12 g_e 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; PCALA-RELOC: R_LARCH_PCALA_HI20 .bss 0x0
+; RELAX-NEXT: R_LARCH_PCALA_HI20 g_i 0x0
+; PCALA-RELOC: R_LARCH_PCALA_LO12 .bss 0x0
+; RELAX-NEXT: R_LARCH_PCALA_LO12 g_i 0x0
+; CHECK-RELOC: R_LARCH_TLS_GD_PC_HI20 t_un 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_GOT_PC_LO12 t_un 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_CALL36 __tls_get_addr 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC: R_LARCH_TLS_DESC_PC_HI20 t_un 0x0
+; DESC-RELAX: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_PC_LO12 t_un 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_LD t_un 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_CALL t_un 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_TLS_LD_PC_HI20 t_ld 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_GOT_PC_LO12 t_ld 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_CALL36 __tls_get_addr 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_PC_HI20 t_ld 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_PC_LO12 t_ld 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_LD t_ld 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_CALL t_ld 0x0
+; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_TLS_IE_PC_HI20 t_ie 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_TLS_IE_PC_LO12 t_ie 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_TLS_LE_HI20_R t_le 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_TLS_LE_ADD_R t_le 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_TLS_LE_LO12_R t_le 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_CALL36 callee1 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_CALL36 callee2 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; CHECK-RELOC-NEXT: R_LARCH_CALL36 callee3 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; PCALA-RELOC: R_LARCH_PCALA_HI20 .data 0x0
+; RELAX-NEXT: R_LARCH_PCALA_HI20 g_i1 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+; PCALA-RELOC: R_LARCH_PCALA_LO12 .data 0x0
+; RELAX-NEXT: R_LARCH_PCALA_LO12 g_i1 0x0
+; RELAX-NEXT: R_LARCH_RELAX - 0x0
+ %a = load volatile i32, ptr @g_e
+ %b = load volatile i32, ptr @g_i
+ %c = load volatile i32, ptr @t_un
+ %d = load volatile i32, ptr @t_ld
+ %e = load volatile i32, ptr @t_ie
+ %f = load volatile i32, ptr @t_le
+ call i32 @callee1()
+ call i32 @callee2()
+ tail call i32 @callee3()
+ ret ptr @g_i1
+}
diff --git a/llvm/test/CodeGen/LoongArch/mir-relax-flags.ll b/llvm/test/CodeGen/LoongArch/mir-relax-flags.ll
new file mode 100644
index 00000000000000..b894de50eed29a
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/mir-relax-flags.ll
@@ -0,0 +1,64 @@
+; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --stop-after loongarch-prera-expand-pseudo \
+; RUN: --relocation-model=pic --code-model=medium %s -o %t.mir
+; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --run-pass loongarch-prera-expand-pseudo \
+; RUN: --code-model=medium %t.mir -o - | FileCheck %s --check-prefixes=CHECK,MEDCALL
+; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --run-pass loongarch-expand-pseudo \
+; RUN: --code-model=medium %t.mir -o - | FileCheck %s --check-prefixes=CHECK,CALL36
+
+; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --stop-after loongarch-prera-expand-pseudo \
+; RUN: --relocation-model=pic --enable-tlsdesc --code-model=medium %s -o %t.desc.mir
+; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --run-pass loongarch-prera-expand-pseudo \
+; RUN: --code-model=medium %t.desc.mir -o - | FileCheck %s --check-prefix=DESC
+
+;; Check target-flags after expand-pseudo pass.
+
+ at g_e = external global i32
+ at g_i = internal global i32 0
+ at t_un = external thread_local global i32
+ at t_ld = external thread_local(localdynamic) global i32
+ at t_ie = external thread_local(initialexec) global i32
+ at t_le = external thread_local(localexec) global i32
+
+declare void @callee1() nounwind
+declare dso_local void @callee2() nounwind
+declare dso_local void @callee3() nounwind
+
+define void @caller() nounwind {
+; CHECK: target-flags(loongarch-got-pc-hi, loongarch-relax) @g_e
+; CHECK-NEXT: target-flags(loongarch-got-pc-lo, loongarch-relax) @g_e
+; CHECK: target-flags(loongarch-pcrel-hi, loongarch-relax) @g_i
+; CHECK-NEXT: target-flags(loongarch-pcrel-lo, loongarch-relax) @g_i
+; CHECK: target-flags(loongarch-gd-pc-hi, loongarch-relax) @t_un
+; CHECK-NEXT: target-flags(loongarch-got-pc-lo, loongarch-relax) @t_un
+; DESC: target-flags(loongarch-desc-pc-hi, loongarch-relax) @t_un
+; DESC-NEXT: target-flags(loongarch-desc-pc-lo, loongarch-relax) @t_un
+; DESC-NEXT: target-flags(loongarch-desc-ld, loongarch-relax) @t_un
+; DESC-NEXT: target-flags(loongarch-desc-call, loongarch-relax) @t_un
+; CHECK: target-flags(loongarch-ld-pc-hi, loongarch-relax) @t_ld
+; CHECK-NEXT: target-flags(loongarch-got-pc-lo, loongarch-relax) @t_ld
+; DESC: target-flags(loongarch-desc-pc-hi, loongarch-relax) @t_ld
+; DESC-NEXT: target-flags(loongarch-desc-pc-lo, loongarch-relax) @t_ld
+; DESC-NEXT: target-flags(loongarch-desc-ld, loongarch-relax) @t_ld
+; DESC-NEXT: target-flags(loongarch-desc-call, loongarch-relax) @t_ld
+; CHECK: target-flags(loongarch-ie-pc-hi, loongarch-relax) @t_ie
+; CHECK-NEXT: target-flags(loongarch-ie-pc-lo, loongarch-relax) @t_ie
+; CHECK: target-flags(loongarch-le-hi-r) @t_le
+; CHECK-NEXT: target-flags(loongarch-le-add-r) @t_le
+; CHECK-NEXT: target-flags(loongarch-le-lo-r) @t_le
+; MEDCALL: target-flags(loongarch-call-plt) @callee1
+; CALL36: target-flags(loongarch-call36) @callee1
+; MEDCALL: target-flags(loongarch-call) @callee2
+; CALL36: target-flags(loongarch-call36) @callee2
+; MEDCALL: target-flags(loongarch-call) @callee3
+; CALL36: target-flags(loongarch-call36) @callee3
+ %a = load volatile i32, ptr @g_e
+ %b = load volatile i32, ptr @g_i
+ %c = load volatile i32, ptr @t_un
+ %d = load volatile i32, ptr @t_ld
+ %e = load volatile i32, ptr @t_ie
+ %f = load volatile i32, ptr @t_le
+ call i32 @callee1()
+ call i32 @callee2()
+ tail call i32 @callee3()
+ ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/mir-target-flags.ll b/llvm/test/CodeGen/LoongArch/mir-target-flags.ll
index 3bc8a8d3095868..51c2a19da80e3c 100644
--- a/llvm/test/CodeGen/LoongArch/mir-target-flags.ll
+++ b/llvm/test/CodeGen/LoongArch/mir-target-flags.ll
@@ -1,7 +1,18 @@
-; RUN: llc --mtriple=loongarch64 -mattr=+d --stop-after loongarch-prera-expand-pseudo \
-; RUN: --relocation-model=pic %s -o %t.mir
-; RUN: llc --mtriple=loongarch64 -mattr=+d --run-pass loongarch-prera-expand-pseudo \
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --stop-after loongarch-prera-expand-pseudo \
+; RUN: --relocation-model=pic --code-model=small %s -o %t.mir
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-prera-expand-pseudo \
; RUN: %t.mir -o - | FileCheck %s
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --stop-after loongarch-prera-expand-pseudo \
+; RUN: --relocation-model=pic --enable-tlsdesc --code-model=small %s -o %t.desc.mir
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-prera-expand-pseudo \
+; RUN: %t.desc.mir -o - | FileCheck %s --check-prefix=DESC
+
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --stop-after loongarch-prera-expand-pseudo \
+; RUN: --relocation-model=pic --code-model=medium %s -o %t.med.mir
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-prera-expand-pseudo \
+; RUN: --code-model=medium %t.med.mir -o - | FileCheck %s
+; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-expand-pseudo \
+; RUN: --code-model=medium %t.med.mir -o - | FileCheck %s --check-prefixes=CALL36
;; This tests the LoongArch-specific serialization and deserialization of
;; `target-flags(...)`
@@ -15,6 +26,7 @@
declare void @callee1() nounwind
declare dso_local void @callee2() nounwind
+declare dso_local void @callee3() nounwind
define void @caller() nounwind {
; CHECK-LABEL: name: caller
@@ -24,15 +36,27 @@ define void @caller() nounwind {
; CHECK-NEXT: target-flags(loongarch-pcrel-lo) @g_i
; CHECK: target-flags(loongarch-gd-pc-hi) @t_un
; CHECK-NEXT: target-flags(loongarch-got-pc-lo) @t_un
+; DESC: target-flags(loongarch-desc-pc-hi) @t_un
+; DESC-NEXT: target-flags(loongarch-desc-pc-lo) @t_un
+; DESC-NEXT: target-flags(loongarch-desc-ld) @t_un
+; DESC-NEXT: target-flags(loongarch-desc-call) @t_un
; CHECK: target-flags(loongarch-ld-pc-hi) @t_ld
; CHECK-NEXT: target-flags(loongarch-got-pc-lo) @t_ld
+; DESC: target-flags(loongarch-desc-pc-hi) @t_ld
+; DESC-NEXT: target-flags(loongarch-desc-pc-lo) @t_ld
+; DESC-NEXT: target-flags(loongarch-desc-ld) @t_ld
+; DESC-NEXT: target-flags(loongarch-desc-call) @t_ld
; CHECK: target-flags(loongarch-ie-pc-hi) @t_ie
; CHECK-NEXT: target-flags(loongarch-ie-pc-lo) @t_ie
; CHECK: target-flags(loongarch-le-hi-r) @t_le
; CHECK-NEXT: target-flags(loongarch-le-add-r) @t_le
; CHECK-NEXT: target-flags(loongarch-le-lo-r) @t_le
; CHECK: target-flags(loongarch-call-plt) @callee1
+; CALL36: target-flags(loongarch-call36) @callee1
; CHECK: target-flags(loongarch-call) @callee2
+; CALL36: target-flags(loongarch-call36) @callee2
+; CHECK: target-flags(loongarch-call) @callee3
+; CALL36: target-flags(loongarch-call36) @callee3
%a = load volatile i32, ptr @g_e
%b = load volatile i32, ptr @g_i
%c = load volatile i32, ptr @t_un
@@ -41,5 +65,6 @@ define void @caller() nounwind {
%f = load volatile i32, ptr @t_le
call i32 @callee1()
call i32 @callee2()
+ tail call i32 @callee3()
ret void
}
More information about the llvm-commits
mailing list