[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