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

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 22 05:49:32 PDT 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/4] [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/4] [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/4] [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/4] [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



More information about the llvm-commits mailing list