[lld] [lld][LoongArch] Relax R_LARCH_PCALA_HI20 and R_LARCH_PCALA_LO12 (PR #112696)

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 18 19:08:21 PST 2024


https://github.com/ywgrit updated https://github.com/llvm/llvm-project/pull/112696

>From cf61f100d89e069ba98c2fa7f800658d3aa001d7 Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Thu, 17 Oct 2024 11:45:06 +0800
Subject: [PATCH 1/7] [lld][LoongArch] Define macros to operate insns and
 registers

---
 lld/ELF/Arch/LoongArch.cpp | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 5923cda2298b4e..8c3901d641428a 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -22,6 +22,40 @@ using namespace lld;
 using namespace lld::elf;
 
 namespace {
+#define LARCH_GET_RD(insn) (insn & 0x1f)
+#define LARCH_GET_RJ(insn) ((insn >> 5) & 0x1f)
+#define LARCH_MK_ADDI_D 0xffc00000
+#define LARCH_OP_ADDI_D 0x02c00000
+#define LARCH_MK_PCADDI 0xfe000000
+#define LARCH_OP_PCADDI 0x18000000
+#define LARCH_MK_PCALAU12I 0xfe000000
+#define LARCH_OP_PCALAU12I 0x1a000000
+#define LARCH_MK_LD_D 0xffc00000
+#define LARCH_OP_LD_D 0x28c00000
+#define LARCH_MK_LD_W 0xffc00000
+#define LARCH_OP_LD_W 0x28800000
+#define LARCH_MK_LU12I_W 0xfe000000
+#define LARCH_OP_LU12I_W 0x14000000
+#define LARCH_MK_ORI 0xffc00000
+#define LARCH_OP_ORI 0x03800000
+#define LARCH_MK_B 0xfc000000
+#define LARCH_OP_B 0x50000000
+#define LARCH_MK_BL 0xfc000000
+#define LARCH_OP_BL 0x54000000
+#define LARCH_MK_JIRL 0xfc000000
+#define LARCH_OP_JIRL 0x4c000000
+#define LARCH_INSN_OPS(insn, op) ((insn & LARCH_MK_##op) == LARCH_OP_##op)
+#define LARCH_INSN_ADDI_D(insn) LARCH_INSN_OPS((insn), ADDI_D)
+#define LARCH_INSN_PCADDI(insn) LARCH_INSN_OPS((insn), PCADDI)
+#define LARCH_INSN_PCALAU12I(insn) LARCH_INSN_OPS((insn), PCALAU12I)
+#define LARCH_INSN_LD_D(insn) LARCH_INSN_OPS((insn), LD_D)
+#define LARCH_INSN_LD_W(insn) LARCH_INSN_OPS((insn), LD_W)
+#define LARCH_INSN_LU12I_W(insn) LARCH_INSN_OPS((insn), LU12I_W)
+#define LARCH_INSN_ORI(insn) LARCH_INSN_OPS((insn), ORI)
+#define LARCH_INSN_B(insn) LARCH_INSN_OPS((insn), B)
+#define LARCH_INSN_BL(insn) LARCH_INSN_OPS((insn), BL)
+#define LARCH_INSN_JIRL(insn) LARCH_INSN_OPS((insn), JIRL)
+
 class LoongArch final : public TargetInfo {
 public:
   LoongArch(Ctx &);
@@ -63,6 +97,7 @@ enum Reg {
   R_ZERO = 0,
   R_RA = 1,
   R_TP = 2,
+  R_A0 = 4,
   R_T0 = 12,
   R_T1 = 13,
   R_T2 = 14,

>From 8f9e9c8e264b72ab161e2963da1bc82059d5a551 Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Thu, 17 Oct 2024 19:47:07 +0800
Subject: [PATCH 2/7] [lld][loongArch] Relax R_LARCH_PCALA_HI20 and
 R_LARCH_PCALA_LO12

A pair of pcalau12i+addi.d relocated by R_LARCH_PCALA_HI20 and
R_LARCH_PCALA_LO12 can be converted to pcaddi.
---
 lld/ELF/Arch/LoongArch.cpp                 |  93 +++++++++-
 lld/ELF/InputSection.cpp                   |  11 ++
 lld/test/ELF/loongarch-relax-align.s       | 194 ++++++++++++++++-----
 lld/test/ELF/loongarch-relax-emit-relocs.s |  85 +++++----
 4 files changed, 311 insertions(+), 72 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 8c3901d641428a..e7276c23d0ab88 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -72,11 +72,16 @@ class LoongArch final : public TargetInfo {
   bool usesOnlyLowPageBits(RelType type) const override;
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
+  void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
   bool relaxOnce(int pass) const override;
   void finalizeRelax(int passes) const override;
 };
 } // end anonymous namespace
 
+// The internal relocation number for local got relaxation which isn't part
+// of the psABI spec.
+#define INTERNAL_R_LARCH_PCALA_LO12 256
+
 namespace {
 enum Op {
   SUB_W = 0x00110000,
@@ -779,6 +784,69 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   }
 }
 
+static bool relaxable(ArrayRef<Relocation> relocs, size_t i) {
+  return i + 1 != relocs.size() && relocs[i + 1].type == R_LARCH_RELAX;
+}
+
+// Returns true if the two instructions corresponding to the i-th reloc
+// entry and the i+2-th reloc entry can apply relaxation. For scenarios
+// with fewer than four reloc entries, e.g., R_ALRCH_CALL36, this function
+// should not be used to make a judgment.
+static bool isPair(ArrayRef<Relocation> relocs, size_t i) {
+  return relaxable(relocs, i) && relaxable(relocs, i + 2) &&
+         relocs[i].offset + 4 == relocs[i + 2].offset;
+}
+
+void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
+  const unsigned bits = ctx.arg.is64 ? 64 : 32;
+  uint64_t secAddr = sec.getOutputSection()->addr;
+  if (auto *s = dyn_cast<InputSection>(&sec))
+    secAddr += s->outSecOff;
+  else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
+    secAddr += ehIn->getParent()->outSecOff;
+  const ArrayRef<Relocation> relocs = sec.relocs();
+  for (size_t i = 0, size = relocs.size(); i != size; ++i) {
+    const Relocation &rel = relocs[i];
+    uint8_t *loc = buf + rel.offset;
+    uint64_t val = SignExtend64(
+        sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset), bits);
+
+    switch (rel.expr) {
+    case R_RELAX_HINT:
+      continue;
+    default:
+      break;
+    }
+    relocate(loc, rel, val);
+  }
+}
+
+// Relax pcalau12i,addi.d => pcaddi.
+static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
+        Relocation &r_hi, uint32_t &remove) {
+  const uint64_t symval =
+      (r_hi.expr == R_LOONGARCH_PLT_PAGE_PC ? r_hi.sym->getPltVA(ctx) : r_hi.sym->getVA()) + r_hi.addend;
+  const int64_t dist = symval - loc;
+  uint32_t pca = read32le(sec.content().data() + r_hi.offset);
+  uint32_t add = read32le(sec.content().data() + r_hi.offset + 4);
+  uint32_t rd = LARCH_GET_RD(pca);
+
+  if (!LARCH_INSN_ADDI_D(add)
+      // Is pcalau12i $rd + addi.d $rd, $rd?
+      || LARCH_GET_RD(add) != rd
+      || LARCH_GET_RJ(add) != rd
+      // 4 bytes align
+      || symval & 0x3
+      || !isInt<22>(dist))
+    return;
+
+  // remove the first insn
+  sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
+  sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
+  sec.relaxAux->writes.push_back(LARCH_OP_PCADDI | rd); // pcaddi
+  remove = 4;
+}
+
 static bool relax(Ctx &ctx, InputSection &sec) {
   const uint64_t secAddr = sec.getVA();
   const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -817,6 +885,11 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       }
       break;
     }
+    case R_LARCH_PCALA_HI20:
+      if (isPair(relocs, i)
+          && relocs[i + 2].type == R_LARCH_PCALA_LO12)
+        relaxPcalaAddi(sec, i, loc, r, remove);
+      break;
     }
 
     // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -887,6 +960,7 @@ void LoongArch::finalizeRelax(int passes) const {
       MutableArrayRef<Relocation> rels = sec->relocs();
       ArrayRef<uint8_t> old = sec->content();
       size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1];
+      size_t writesIdx = 0;
       uint8_t *p = context().bAlloc.Allocate<uint8_t>(newSize);
       uint64_t offset = 0;
       int64_t delta = 0;
@@ -907,7 +981,24 @@ void LoongArch::finalizeRelax(int passes) const {
         uint64_t size = r.offset - offset;
         memcpy(p, old.data() + offset, size);
         p += size;
-        offset = r.offset + remove;
+
+        int64_t skip = 0;
+        if (r.type != R_LARCH_ALIGN) {
+          RelType newType = aux.relocTypes[i];
+          switch (newType) {
+          case R_LARCH_RELAX:
+            break;
+          case R_LARCH_PCREL20_S2:
+            skip = 4;
+            write32le(p, aux.writes[writesIdx++]);
+            break;
+          default:
+            llvm_unreachable("unsupported type");
+          }
+        }
+
+        p += skip;
+        offset = r.offset + remove + skip;
       }
       memcpy(p, old.data() + offset, old.size() - offset);
 
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 2e9e8a7007bbf8..b093a8790ef1a7 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -737,6 +737,17 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   int64_t a = r.addend;
   switch (r.expr) {
   case R_ABS:
+    // pcalau12i,addi.d => pcaddi
+    // With relaxation applied, the relocation type of the third
+    // reloc entry which corresponds to the addi.d insn is converted
+    // from R_LARCH_PCALA_LO12 to R_LARCH_PCREL20_S2.
+    if (r.type == R_LARCH_PCREL20_S2) {
+      if (r.sym->hasFlag(NEEDS_PLT))
+        return r.sym->getPltVA(ctx) + a - p;
+      else
+        return r.sym->getVA(a) - p;
+    }
+    [[fallthrough]];
   case R_DTPREL:
   case R_RELAX_TLS_LD_TO_LE_ABS:
   case R_RELAX_GOT_PC_NOPIC:
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index ab61e15d5caca2..9cbbc69b91c1cb 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -6,56 +6,170 @@
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s --check-prefix=RELAX32
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s --check-prefixes=RELAX64,SRELAX64
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s --check-prefix=NORELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s --check-prefix=NORELAX
 
 ## Test the R_LARCH_ALIGN without symbol index.
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n
-# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s --check-prefixes=RELAX64,ORELAX64
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s --check-prefix=ONORELAX
 
 ## -r keeps section contents unchanged.
 # RUN: ld.lld -r %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR
 
-# CHECK-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
-# CHECK-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
-# CHECK-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
-# CHECK-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
-
-# CHECK:      <.Ltext_start>:
-# CHECK-NEXT:   break 1
-# CHECK-NEXT:   break 2
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   break 3
-# CHECK-NEXT:   break 4
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   pcalau12i     $a0, 0
-# CHECK-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# CHECK-NEXT:   pcalau12i     $a0, 0
-# CHECK-NEXT:   addi.{{[dw]}} $a0, $a0, 56
-# CHECK-NEXT:   pcalau12i     $a0, 0
-# CHECK-NEXT:   addi.{{[dw]}} $a0, $a0, 64
-# CHECK-EMPTY:
-# CHECK-NEXT: <.L1>:
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   nop
-# CHECK-EMPTY:
-# CHECK-NEXT: <.L2>:
-# CHECK-NEXT:   break 5
-
-# CHECK:      <.Ltext2_start>:
-# CHECK-NEXT:   pcalau12i     $a0, 0
-# CHECK-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   break 6
+# RELAX32-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# RELAX32-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
+# RELAX32-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
+# RELAX32-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
+# RELAX32-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# RELAX32:      <.Ltext_start>:
+# RELAX32-NEXT:   break 1
+# RELAX32-NEXT:   break 2
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   break 3
+# RELAX32-NEXT:   break 4
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   pcalau12i     $a0, 0
+# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# RELAX32-NEXT:   pcalau12i     $a0, 0
+# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 56
+# RELAX32-NEXT:   pcalau12i     $a0, 0
+# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 64
+# RELAX32-EMPTY:
+# RELAX32-NEXT: <.L1>:
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   nop
+# RELAX32-EMPTY:
+# RELAX32-NEXT: <.L2>:
+# RELAX32-NEXT:   break 5
+
+# RELAX32:      <.Ltext2_start>:
+# RELAX32-NEXT:   pcalau12i     $a0, 0
+# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   nop
+# RELAX32-NEXT:   break 6
+
+# NORELAX-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# NORELAX-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
+# NORELAX-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
+# NORELAX-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
+# NORELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# NORELAX:      <.Ltext_start>:
+# NORELAX-NEXT:   break 1
+# NORELAX-NEXT:   break 2
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   break 3
+# NORELAX-NEXT:   break 4
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   pcalau12i     $a0, 0
+# NORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# NORELAX-NEXT:   pcalau12i     $a0, 0
+# NORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 56
+# NORELAX-NEXT:   pcalau12i     $a0, 0
+# NORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 64
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <.L1>:
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   nop
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <.L2>:
+# NORELAX-NEXT:   break 5
+
+# NORELAX:      <.Ltext2_start>:
+# NORELAX-NEXT:   pcalau12i     $a0, 0
+# NORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   break 6
+
+
+
+# ORELAX64-DAG: {{0*}}00001 l *ABS*  {{0*}}00 old
+# SRELAX64-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# RELAX64-DAG: {{0*}}10000 l .text  {{0*}}34 .Ltext_start
+# RELAX64-DAG: {{0*}}1002c l .text  {{0*}}08 .L1
+# RELAX64-DAG: {{0*}}10030 l .text  {{0*}}04 .L2
+# RELAX64-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# RELAX64:      <.Ltext_start>:
+# RELAX64-NEXT:   break 1
+# RELAX64-NEXT:   break 2
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   break 3
+# RELAX64-NEXT:   break 4
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   pcaddi  $a0, -8
+# RELAX64-NEXT:   pcaddi  $a0, 2
+# RELAX64-NEXT:   pcaddi  $a0, 2
+# RELAX64-EMPTY:
+# RELAX64-NEXT: <.L1>:
+# RELAX64-NEXT:   nop
+# RELAX64-EMPTY:
+# RELAX64-NEXT: <.L2>:
+# RELAX64-NEXT:   break 5
+
+# RELAX64:      <.Ltext2_start>:
+# RELAX64-NEXT:   pcaddi     $a0, 0
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   nop
+# RELAX64-NEXT:   break 6
+
+
+# ONORELAX-DAG: {{0*}}00001 l *ABS*  {{0*}}00 old
+# ONORELAX-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
+# ONORELAX-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
+# ONORELAX-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
+# ONORELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# ONORELAX:      <.Ltext_start>:
+# ONORELAX-NEXT:   break 1
+# ONORELAX-NEXT:   break 2
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   break 3
+# ONORELAX-NEXT:   break 4
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   pcalau12i     $a0, 0
+# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# ONORELAX-NEXT:   pcalau12i     $a0, 0
+# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 56
+# ONORELAX-NEXT:   pcalau12i     $a0, 0
+# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 64
+# ONORELAX-EMPTY:
+# ONORELAX-NEXT: <.L1>:
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   nop
+# ONORELAX-EMPTY:
+# ONORELAX-NEXT: <.L2>:
+# ONORELAX-NEXT:   break 5
+
+# ONORELAX:      <.Ltext2_start>:
+# ONORELAX-NEXT:   pcalau12i     $a0, 0
+# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   nop
+# ONORELAX-NEXT:   break 6
+
+
+
+
+
 
 # CHECKR:      <.Ltext2_start>:
 # CHECKR-NEXT:   pcalau12i $a0, 0
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index ba414e8c93f0fb..8784bf57e7ff33 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -5,42 +5,65 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
 # RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32
 # RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
-# RUN: llvm-objdump -dr %t.32 | FileCheck %s
-# RUN: llvm-objdump -dr %t.64 | FileCheck %s
+# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=LA32RELOC
+# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=LA64RELOC
 
 ## -r should keep original relocations.
 # RUN: ld.lld -r %t.64.o -o %t.64.r
-# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
+# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=RELAX
 
-## --no-relax should keep original relocations.
-## TODO Due to R_LARCH_RELAX is not relaxed, it plays same as --relax now.
 # RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
-# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s
-
-# CHECK:      00010000 <_start>:
-# CHECK-NEXT:   pcalau12i $a0, 0
-# CHECK-NEXT:     R_LARCH_PCALA_HI20 _start
-# CHECK-NEXT:     R_LARCH_RELAX *ABS*
-# CHECK-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# CHECK-NEXT:     R_LARCH_PCALA_LO12 _start
-# CHECK-NEXT:     R_LARCH_RELAX *ABS*
-# CHECK-NEXT:   nop
-# CHECK-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# CHECK-NEXT:   nop
-# CHECK-NEXT:   ret
-
-# CHECKR:      <_start>:
-# CHECKR-NEXT:   pcalau12i $a0, 0
-# CHECKR-NEXT:     R_LARCH_PCALA_HI20 _start
-# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
-# CHECKR-NEXT:   addi.d $a0, $a0, 0
-# CHECKR-NEXT:     R_LARCH_PCALA_LO12 _start
-# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
-# CHECKR-NEXT:   nop
-# CHECKR-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# CHECKR-NEXT:   nop
-# CHECKR-NEXT:   nop
-# CHECKR-NEXT:   ret
+# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
+
+# LA32RELOC:      00010000 <_start>:
+# LA32RELOC-NEXT:   pcalau12i $a0, 0
+# LA32RELOC-NEXT:     R_LARCH_PCALA_HI20 _start
+# LA32RELOC-NEXT:     R_LARCH_RELAX *ABS*
+# LA32RELOC-NEXT:   addi.{{[dw]}} $a0, $a0, 0
+# LA32RELOC-NEXT:     R_LARCH_PCALA_LO12 _start
+# LA32RELOC-NEXT:     R_LARCH_RELAX *ABS*
+# LA32RELOC-NEXT:   nop
+# LA32RELOC-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# LA32RELOC-NEXT:   nop
+# LA32RELOC-NEXT:   ret
+
+# LA64RELOC:      00010000 <_start>:
+# LA64RELOC-NEXT:   pcaddi $a0, 0
+# LA64RELOC-NEXT:     R_LARCH_RELAX _start
+# LA64RELOC-NEXT:     R_LARCH_RELAX *ABS*
+# LA64RELOC-NEXT:     R_LARCH_PCREL20_S2 _start
+# LA64RELOC-NEXT:     R_LARCH_RELAX *ABS*
+# LA64RELOC-NEXT:   nop
+# LA64RELOC-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# LA64RELOC-NEXT:   nop
+# LA64RELOC-NEXT:   nop
+# LA64RELOC-NEXT:   ret
+
+
+# RELAX:      <_start>:
+# RELAX-NEXT:   pcalau12i $a0, 0
+# RELAX-NEXT:     R_LARCH_PCALA_HI20 _start
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   addi.d $a0, $a0, 0
+# RELAX-NEXT:     R_LARCH_PCALA_LO12 _start
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   nop
+# RELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   ret
+
+# NORELAX:      <_start>:
+# NORELAX-NEXT:   pcalau12i $a0, 0
+# NORELAX-NEXT:     R_LARCH_PCALA_HI20 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   addi.d $a0, $a0, 0
+# NORELAX-NEXT:     R_LARCH_PCALA_LO12 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   ret
 
 .global _start
 _start:

>From daea555d1a4828274424f6e3862f22e4d1ca5747 Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Fri, 18 Oct 2024 09:27:48 +0800
Subject: [PATCH 3/7] [lld][LoongArch] clang-format code

---
 lld/ELF/Arch/LoongArch.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index e7276c23d0ab88..ca3a7fe0108826 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -823,9 +823,11 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
 
 // Relax pcalau12i,addi.d => pcaddi.
 static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
-        Relocation &r_hi, uint32_t &remove) {
+                           Relocation &r_hi, uint32_t &remove) {
   const uint64_t symval =
-      (r_hi.expr == R_LOONGARCH_PLT_PAGE_PC ? r_hi.sym->getPltVA(ctx) : r_hi.sym->getVA()) + r_hi.addend;
+      (r_hi.expr == R_LOONGARCH_PLT_PAGE_PC ? r_hi.sym->getPltVA(ctx)
+                                            : r_hi.sym->getVA()) +
+      r_hi.addend;
   const int64_t dist = symval - loc;
   uint32_t pca = read32le(sec.content().data() + r_hi.offset);
   uint32_t add = read32le(sec.content().data() + r_hi.offset + 4);
@@ -833,11 +835,10 @@ static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
 
   if (!LARCH_INSN_ADDI_D(add)
       // Is pcalau12i $rd + addi.d $rd, $rd?
-      || LARCH_GET_RD(add) != rd
-      || LARCH_GET_RJ(add) != rd
+      || LARCH_GET_RD(add) != rd ||
+      LARCH_GET_RJ(add) != rd
       // 4 bytes align
-      || symval & 0x3
-      || !isInt<22>(dist))
+      || symval & 0x3 || !isInt<22>(dist))
     return;
 
   // remove the first insn
@@ -886,8 +887,7 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       break;
     }
     case R_LARCH_PCALA_HI20:
-      if (isPair(relocs, i)
-          && relocs[i + 2].type == R_LARCH_PCALA_LO12)
+      if (isPair(relocs, i) && relocs[i + 2].type == R_LARCH_PCALA_LO12)
         relaxPcalaAddi(sec, i, loc, r, remove);
       break;
     }

>From 289963686ad9cda99fead49ef489847c58b53d89 Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Tue, 22 Oct 2024 19:19:01 +0800
Subject: [PATCH 4/7] [lld][LoongArch] remove unused code and determine the
 boundaries of relocs correctly

---
 lld/ELF/Arch/LoongArch.cpp | 41 ++++----------------------------------
 1 file changed, 4 insertions(+), 37 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index ca3a7fe0108826..dbe3f447eb3fe0 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -23,38 +23,14 @@ using namespace lld::elf;
 
 namespace {
 #define LARCH_GET_RD(insn) (insn & 0x1f)
-#define LARCH_GET_RJ(insn) ((insn >> 5) & 0x1f)
+#define LARCH_GET_RJ(insn) (insn >> 5 & 0x1f)
 #define LARCH_MK_ADDI_D 0xffc00000
 #define LARCH_OP_ADDI_D 0x02c00000
 #define LARCH_MK_PCADDI 0xfe000000
 #define LARCH_OP_PCADDI 0x18000000
-#define LARCH_MK_PCALAU12I 0xfe000000
-#define LARCH_OP_PCALAU12I 0x1a000000
-#define LARCH_MK_LD_D 0xffc00000
-#define LARCH_OP_LD_D 0x28c00000
-#define LARCH_MK_LD_W 0xffc00000
-#define LARCH_OP_LD_W 0x28800000
-#define LARCH_MK_LU12I_W 0xfe000000
-#define LARCH_OP_LU12I_W 0x14000000
-#define LARCH_MK_ORI 0xffc00000
-#define LARCH_OP_ORI 0x03800000
-#define LARCH_MK_B 0xfc000000
-#define LARCH_OP_B 0x50000000
-#define LARCH_MK_BL 0xfc000000
-#define LARCH_OP_BL 0x54000000
-#define LARCH_MK_JIRL 0xfc000000
-#define LARCH_OP_JIRL 0x4c000000
 #define LARCH_INSN_OPS(insn, op) ((insn & LARCH_MK_##op) == LARCH_OP_##op)
 #define LARCH_INSN_ADDI_D(insn) LARCH_INSN_OPS((insn), ADDI_D)
 #define LARCH_INSN_PCADDI(insn) LARCH_INSN_OPS((insn), PCADDI)
-#define LARCH_INSN_PCALAU12I(insn) LARCH_INSN_OPS((insn), PCALAU12I)
-#define LARCH_INSN_LD_D(insn) LARCH_INSN_OPS((insn), LD_D)
-#define LARCH_INSN_LD_W(insn) LARCH_INSN_OPS((insn), LD_W)
-#define LARCH_INSN_LU12I_W(insn) LARCH_INSN_OPS((insn), LU12I_W)
-#define LARCH_INSN_ORI(insn) LARCH_INSN_OPS((insn), ORI)
-#define LARCH_INSN_B(insn) LARCH_INSN_OPS((insn), B)
-#define LARCH_INSN_BL(insn) LARCH_INSN_OPS((insn), BL)
-#define LARCH_INSN_JIRL(insn) LARCH_INSN_OPS((insn), JIRL)
 
 class LoongArch final : public TargetInfo {
 public:
@@ -77,11 +53,6 @@ class LoongArch final : public TargetInfo {
   void finalizeRelax(int passes) const override;
 };
 } // end anonymous namespace
-
-// The internal relocation number for local got relaxation which isn't part
-// of the psABI spec.
-#define INTERNAL_R_LARCH_PCALA_LO12 256
-
 namespace {
 enum Op {
   SUB_W = 0x00110000,
@@ -785,7 +756,7 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
 }
 
 static bool relaxable(ArrayRef<Relocation> relocs, size_t i) {
-  return i + 1 != relocs.size() && relocs[i + 1].type == R_LARCH_RELAX;
+  return i + 1 < relocs.size() && relocs[i + 1].type == R_LARCH_RELAX;
 }
 
 // Returns true if the two instructions corresponding to the i-th reloc
@@ -833,12 +804,8 @@ static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
   uint32_t add = read32le(sec.content().data() + r_hi.offset + 4);
   uint32_t rd = LARCH_GET_RD(pca);
 
-  if (!LARCH_INSN_ADDI_D(add)
-      // Is pcalau12i $rd + addi.d $rd, $rd?
-      || LARCH_GET_RD(add) != rd ||
-      LARCH_GET_RJ(add) != rd
-      // 4 bytes align
-      || symval & 0x3 || !isInt<22>(dist))
+  if (!LARCH_INSN_ADDI_D(add) || LARCH_GET_RJ(add) != rd ||
+      symval & 0x3 /* 4 bytes align */ || !isInt<22>(dist))
     return;
 
   // remove the first insn

>From 84b666d5056beb7ea1f64ec6cef73ffb22056316 Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Mon, 28 Oct 2024 15:13:20 +0800
Subject: [PATCH 5/7] [lld][LoongArch] support relaxation on LoongArch32

---
 lld/ELF/Arch/LoongArch.cpp                 |  10 +-
 lld/ELF/InputSection.cpp                   |   4 +-
 lld/test/ELF/loongarch-relax-align.s       | 157 ++++++---------------
 lld/test/ELF/loongarch-relax-emit-relocs.s |  66 +++------
 4 files changed, 70 insertions(+), 167 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index dbe3f447eb3fe0..d854c29f56a0ad 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -24,11 +24,14 @@ using namespace lld::elf;
 namespace {
 #define LARCH_GET_RD(insn) (insn & 0x1f)
 #define LARCH_GET_RJ(insn) (insn >> 5 & 0x1f)
+#define LARCH_MK_ADDI_W 0xffc00000
+#define LARCH_OP_ADDI_W 0x02800000
 #define LARCH_MK_ADDI_D 0xffc00000
 #define LARCH_OP_ADDI_D 0x02c00000
 #define LARCH_MK_PCADDI 0xfe000000
 #define LARCH_OP_PCADDI 0x18000000
 #define LARCH_INSN_OPS(insn, op) ((insn & LARCH_MK_##op) == LARCH_OP_##op)
+#define LARCH_INSN_ADDI_W(insn) LARCH_INSN_OPS((insn), ADDI_W)
 #define LARCH_INSN_ADDI_D(insn) LARCH_INSN_OPS((insn), ADDI_D)
 #define LARCH_INSN_PCADDI(insn) LARCH_INSN_OPS((insn), PCADDI)
 
@@ -792,7 +795,7 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
   }
 }
 
-// Relax pcalau12i,addi.d => pcaddi.
+// Relax pcalau12i,addi.[wd] => pcaddi.
 static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
                            Relocation &r_hi, uint32_t &remove) {
   const uint64_t symval =
@@ -804,8 +807,9 @@ static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
   uint32_t add = read32le(sec.content().data() + r_hi.offset + 4);
   uint32_t rd = LARCH_GET_RD(pca);
 
-  if (!LARCH_INSN_ADDI_D(add) || LARCH_GET_RJ(add) != rd ||
-      symval & 0x3 /* 4 bytes align */ || !isInt<22>(dist))
+  if ((!LARCH_INSN_ADDI_W(add) && !LARCH_INSN_ADDI_D(add)) ||
+      LARCH_GET_RJ(add) != rd || symval & 0x3 /* 4 bytes align */ ||
+      !isInt<22>(dist))
     return;
 
   // remove the first insn
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index b093a8790ef1a7..1d5f53dfecb8ab 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -737,9 +737,9 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   int64_t a = r.addend;
   switch (r.expr) {
   case R_ABS:
-    // pcalau12i,addi.d => pcaddi
+    // pcalau12i,addi.[wd] => pcaddi
     // With relaxation applied, the relocation type of the third
-    // reloc entry which corresponds to the addi.d insn is converted
+    // reloc entry which corresponds to the addi.[wd] insn is converted
     // from R_LARCH_PCALA_LO12 to R_LARCH_PCREL20_S2.
     if (r.type == R_LARCH_PCREL20_S2) {
       if (r.sym->hasFlag(NEEDS_PLT))
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index 9cbbc69b91c1cb..cbe3e629b81dee 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -6,59 +6,24 @@
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s --check-prefix=RELAX32
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s --check-prefixes=RELAX64,SRELAX64
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s --check-prefix=NORELAX
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s --check-prefix=NORELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s --check-prefix=RELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s --check-prefixes=RELAX,NOABSRELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s --check-prefixes=NORELAX,NOABSNORELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s --check-prefixes=NORELAX,NOABSNORELAX
 
 ## Test the R_LARCH_ALIGN without symbol index.
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n
-# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s --check-prefixes=RELAX64,ORELAX64
-# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s --check-prefix=ONORELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s --check-prefixes=RELAX,ABSRELAX
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s --check-prefixes=NORELAX,ABSNORELAX
 
 ## -r keeps section contents unchanged.
 # RUN: ld.lld -r %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR
 
-# RELAX32-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
-# RELAX32-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
-# RELAX32-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
-# RELAX32-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
-# RELAX32-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
-
-# RELAX32:      <.Ltext_start>:
-# RELAX32-NEXT:   break 1
-# RELAX32-NEXT:   break 2
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   break 3
-# RELAX32-NEXT:   break 4
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   pcalau12i     $a0, 0
-# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# RELAX32-NEXT:   pcalau12i     $a0, 0
-# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 56
-# RELAX32-NEXT:   pcalau12i     $a0, 0
-# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 64
-# RELAX32-EMPTY:
-# RELAX32-NEXT: <.L1>:
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   nop
-# RELAX32-EMPTY:
-# RELAX32-NEXT: <.L2>:
-# RELAX32-NEXT:   break 5
-
-# RELAX32:      <.Ltext2_start>:
-# RELAX32-NEXT:   pcalau12i     $a0, 0
-# RELAX32-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   nop
-# RELAX32-NEXT:   break 6
-
-# NORELAX-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# NOABSNORELAX-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# ABSNORELAX-DAG: {{0*}}00001 l *ABS*  {{0*}}00 old
 # NORELAX-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
 # NORELAX-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
 # NORELAX-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
@@ -95,80 +60,38 @@
 # NORELAX-NEXT:   break 6
 
 
-
-# ORELAX64-DAG: {{0*}}00001 l *ABS*  {{0*}}00 old
-# SRELAX64-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
-# RELAX64-DAG: {{0*}}10000 l .text  {{0*}}34 .Ltext_start
-# RELAX64-DAG: {{0*}}1002c l .text  {{0*}}08 .L1
-# RELAX64-DAG: {{0*}}10030 l .text  {{0*}}04 .L2
-# RELAX64-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
-
-# RELAX64:      <.Ltext_start>:
-# RELAX64-NEXT:   break 1
-# RELAX64-NEXT:   break 2
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   break 3
-# RELAX64-NEXT:   break 4
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   pcaddi  $a0, -8
-# RELAX64-NEXT:   pcaddi  $a0, 2
-# RELAX64-NEXT:   pcaddi  $a0, 2
-# RELAX64-EMPTY:
-# RELAX64-NEXT: <.L1>:
-# RELAX64-NEXT:   nop
-# RELAX64-EMPTY:
-# RELAX64-NEXT: <.L2>:
-# RELAX64-NEXT:   break 5
-
-# RELAX64:      <.Ltext2_start>:
-# RELAX64-NEXT:   pcaddi     $a0, 0
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   nop
-# RELAX64-NEXT:   break 6
-
-
-# ONORELAX-DAG: {{0*}}00001 l *ABS*  {{0*}}00 old
-# ONORELAX-DAG: {{0*}}10000 l .text  {{0*}}44 .Ltext_start
-# ONORELAX-DAG: {{0*}}10038 l .text  {{0*}}0c .L1
-# ONORELAX-DAG: {{0*}}10040 l .text  {{0*}}04 .L2
-# ONORELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
-
-# ONORELAX:      <.Ltext_start>:
-# ONORELAX-NEXT:   break 1
-# ONORELAX-NEXT:   break 2
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   break 3
-# ONORELAX-NEXT:   break 4
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   pcalau12i     $a0, 0
-# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# ONORELAX-NEXT:   pcalau12i     $a0, 0
-# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 56
-# ONORELAX-NEXT:   pcalau12i     $a0, 0
-# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 64
-# ONORELAX-EMPTY:
-# ONORELAX-NEXT: <.L1>:
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   nop
-# ONORELAX-EMPTY:
-# ONORELAX-NEXT: <.L2>:
-# ONORELAX-NEXT:   break 5
-
-# ONORELAX:      <.Ltext2_start>:
-# ONORELAX-NEXT:   pcalau12i     $a0, 0
-# ONORELAX-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   nop
-# ONORELAX-NEXT:   break 6
-
-
-
-
+# NOABSRELAX-DAG: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# ABSRELAX-DAG: {{0*}}00001 l *ABS*  {{0*}}00 old
+# RELAX-DAG: {{0*}}10000 l .text  {{0*}}34 .Ltext_start
+# RELAX-DAG: {{0*}}1002c l .text  {{0*}}08 .L1
+# RELAX-DAG: {{0*}}10030 l .text  {{0*}}04 .L2
+# RELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# RELAX:      <.Ltext_start>:
+# RELAX-NEXT:   break 1
+# RELAX-NEXT:   break 2
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   break 3
+# RELAX-NEXT:   break 4
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   pcaddi  $a0, -8
+# RELAX-NEXT:   pcaddi  $a0, 2
+# RELAX-NEXT:   pcaddi  $a0, 2
+# RELAX-EMPTY:
+# RELAX-NEXT: <.L1>:
+# RELAX-NEXT:   nop
+# RELAX-EMPTY:
+# RELAX-NEXT: <.L2>:
+# RELAX-NEXT:   break 5
+
+# RELAX:      <.Ltext2_start>:
+# RELAX-NEXT:   pcaddi     $a0, 0
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   break 6
 
 
 # CHECKR:      <.Ltext2_start>:
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 8784bf57e7ff33..056262026e8d1d 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -5,47 +5,21 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
 # RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32
 # RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
-# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=LA32RELOC
-# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=LA64RELOC
+# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
+# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
 
 ## -r should keep original relocations.
 # RUN: ld.lld -r %t.64.o -o %t.64.r
-# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=RELAX
+# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefixes=CHECKR,CHECKR-RELAX
 
 # RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
-# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
+# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=CHECKR
 
-# LA32RELOC:      00010000 <_start>:
-# LA32RELOC-NEXT:   pcalau12i $a0, 0
-# LA32RELOC-NEXT:     R_LARCH_PCALA_HI20 _start
-# LA32RELOC-NEXT:     R_LARCH_RELAX *ABS*
-# LA32RELOC-NEXT:   addi.{{[dw]}} $a0, $a0, 0
-# LA32RELOC-NEXT:     R_LARCH_PCALA_LO12 _start
-# LA32RELOC-NEXT:     R_LARCH_RELAX *ABS*
-# LA32RELOC-NEXT:   nop
-# LA32RELOC-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# LA32RELOC-NEXT:   nop
-# LA32RELOC-NEXT:   ret
-
-# LA64RELOC:      00010000 <_start>:
-# LA64RELOC-NEXT:   pcaddi $a0, 0
-# LA64RELOC-NEXT:     R_LARCH_RELAX _start
-# LA64RELOC-NEXT:     R_LARCH_RELAX *ABS*
-# LA64RELOC-NEXT:     R_LARCH_PCREL20_S2 _start
-# LA64RELOC-NEXT:     R_LARCH_RELAX *ABS*
-# LA64RELOC-NEXT:   nop
-# LA64RELOC-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# LA64RELOC-NEXT:   nop
-# LA64RELOC-NEXT:   nop
-# LA64RELOC-NEXT:   ret
-
-
-# RELAX:      <_start>:
-# RELAX-NEXT:   pcalau12i $a0, 0
-# RELAX-NEXT:     R_LARCH_PCALA_HI20 _start
+# RELAX:      00010000 <_start>:
+# RELAX-NEXT:   pcaddi $a0, 0
+# RELAX-NEXT:     R_LARCH_RELAX _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   addi.d $a0, $a0, 0
-# RELAX-NEXT:     R_LARCH_PCALA_LO12 _start
+# RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:   nop
 # RELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
@@ -53,17 +27,19 @@
 # RELAX-NEXT:   nop
 # RELAX-NEXT:   ret
 
-# NORELAX:      <_start>:
-# NORELAX-NEXT:   pcalau12i $a0, 0
-# NORELAX-NEXT:     R_LARCH_PCALA_HI20 _start
-# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
-# NORELAX-NEXT:   addi.d $a0, $a0, 0
-# NORELAX-NEXT:     R_LARCH_PCALA_LO12 _start
-# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
-# NORELAX-NEXT:   nop
-# NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# NORELAX-NEXT:   nop
-# NORELAX-NEXT:   ret
+
+# CHECKR:      <_start>:
+# CHECKR-NEXT:   pcalau12i $a0, 0
+# CHECKR-NEXT:     R_LARCH_PCALA_HI20 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   addi.d $a0, $a0, 0
+# CHECKR-NEXT:     R_LARCH_PCALA_LO12 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   nop
+# CHECKR-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# CHECKR-NEXT:   nop
+# CHECKR-RELAX-NEXT:   nop
+# CHECKR-NEXT:   ret
 
 .global _start
 _start:

>From c40c9310c120893e491e169a19f094aed2085a0f Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Mon, 18 Nov 2024 10:47:25 +0800
Subject: [PATCH 6/7] [lld][LoongArch] Replace macros which operate insns and
 registers with functions

---
 lld/ELF/Arch/LoongArch.cpp | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index d854c29f56a0ad..6d33f90dd8000c 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -22,19 +22,6 @@ using namespace lld;
 using namespace lld::elf;
 
 namespace {
-#define LARCH_GET_RD(insn) (insn & 0x1f)
-#define LARCH_GET_RJ(insn) (insn >> 5 & 0x1f)
-#define LARCH_MK_ADDI_W 0xffc00000
-#define LARCH_OP_ADDI_W 0x02800000
-#define LARCH_MK_ADDI_D 0xffc00000
-#define LARCH_OP_ADDI_D 0x02c00000
-#define LARCH_MK_PCADDI 0xfe000000
-#define LARCH_OP_PCADDI 0x18000000
-#define LARCH_INSN_OPS(insn, op) ((insn & LARCH_MK_##op) == LARCH_OP_##op)
-#define LARCH_INSN_ADDI_W(insn) LARCH_INSN_OPS((insn), ADDI_W)
-#define LARCH_INSN_ADDI_D(insn) LARCH_INSN_OPS((insn), ADDI_D)
-#define LARCH_INSN_PCADDI(insn) LARCH_INSN_OPS((insn), PCADDI)
-
 class LoongArch final : public TargetInfo {
 public:
   LoongArch(Ctx &);
@@ -67,6 +54,7 @@ enum Op {
   ADDI_D = 0x02c00000,
   ANDI = 0x03400000,
   PCADDU12I = 0x1c000000,
+  PCADDI = 0x18000000,
   LD_W = 0x28800000,
   LD_D = 0x28c00000,
   JIRL = 0x4c000000,
@@ -76,7 +64,6 @@ enum Reg {
   R_ZERO = 0,
   R_RA = 1,
   R_TP = 2,
-  R_A0 = 4,
   R_T0 = 12,
   R_T1 = 13,
   R_T2 = 14,
@@ -173,6 +160,17 @@ static bool isJirl(uint32_t insn) {
   return (insn & 0xfc000000) == JIRL;
 }
 
+static bool isAddi_w(uint32_t insn) { return (insn & 0xffc00000) == ADDI_W; }
+
+static bool isAddi_d(uint32_t insn) { return (insn & 0xffc00000) == ADDI_D; }
+
+// LoongArch instructions could be divided into a number of kinds based on
+// the width of imm and the number of registers. get_rd/get_rj only applies
+// to those kinds of instructions that could do relocation.
+static uint8_t get_rd(uint32_t insn) { return insn & 0x1f; }
+
+static uint8_t get_rj(uint32_t insn) { return insn >> 5 & 0x1f; }
+
 static void handleUleb128(Ctx &ctx, uint8_t *loc, uint64_t val) {
   const uint32_t maxcount = 1 + 64 / 7;
   uint32_t count;
@@ -805,17 +803,16 @@ static void relaxPcalaAddi(const InputSection &sec, size_t i, uint64_t loc,
   const int64_t dist = symval - loc;
   uint32_t pca = read32le(sec.content().data() + r_hi.offset);
   uint32_t add = read32le(sec.content().data() + r_hi.offset + 4);
-  uint32_t rd = LARCH_GET_RD(pca);
+  uint8_t rd = get_rd(pca);
 
-  if ((!LARCH_INSN_ADDI_W(add) && !LARCH_INSN_ADDI_D(add)) ||
-      LARCH_GET_RJ(add) != rd || symval & 0x3 /* 4 bytes align */ ||
-      !isInt<22>(dist))
+  if ((!isAddi_w(add) && !isAddi_d(add)) || get_rj(add) != rd ||
+      symval & 0x3 /* not 4 bytes align */ || !isInt<22>(dist))
     return;
 
   // remove the first insn
   sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
   sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
-  sec.relaxAux->writes.push_back(LARCH_OP_PCADDI | rd); // pcaddi
+  sec.relaxAux->writes.push_back(PCADDI | rd); // pcaddi rd, 0
   remove = 4;
 }
 

>From 3f7cf3367ae2bbd6711cba1d70cd2dd64c20c315 Mon Sep 17 00:00:00 2001
From: Xin Wang <wangxin03 at loongson.cn>
Date: Tue, 19 Nov 2024 10:22:04 +0800
Subject: [PATCH 7/7] [lld][LoongArch] Adjust RelExpr after relaxation is
 applied

---
 lld/ELF/Arch/LoongArch.cpp |  4 +++-
 lld/ELF/InputSection.cpp   | 11 -----------
 2 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 6d33f90dd8000c..46a06803fafb34 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -945,7 +945,7 @@ void LoongArch::finalizeRelax(int passes) const {
           continue;
 
         // Copy from last location to the current relocated location.
-        const Relocation &r = rels[i];
+        Relocation &r = rels[i];
         uint64_t size = r.offset - offset;
         memcpy(p, old.data() + offset, size);
         p += size;
@@ -959,6 +959,8 @@ void LoongArch::finalizeRelax(int passes) const {
           case R_LARCH_PCREL20_S2:
             skip = 4;
             write32le(p, aux.writes[writesIdx++]);
+            // RelExpr is needed for relocating.
+            r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
             break;
           default:
             llvm_unreachable("unsupported type");
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 1d5f53dfecb8ab..2e9e8a7007bbf8 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -737,17 +737,6 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   int64_t a = r.addend;
   switch (r.expr) {
   case R_ABS:
-    // pcalau12i,addi.[wd] => pcaddi
-    // With relaxation applied, the relocation type of the third
-    // reloc entry which corresponds to the addi.[wd] insn is converted
-    // from R_LARCH_PCALA_LO12 to R_LARCH_PCREL20_S2.
-    if (r.type == R_LARCH_PCREL20_S2) {
-      if (r.sym->hasFlag(NEEDS_PLT))
-        return r.sym->getPltVA(ctx) + a - p;
-      else
-        return r.sym->getVA(a) - p;
-    }
-    [[fallthrough]];
   case R_DTPREL:
   case R_RELAX_TLS_LD_TO_LE_ABS:
   case R_RELAX_GOT_PC_NOPIC:



More information about the llvm-commits mailing list