[lld] [lld][LoongArch] Relax TLS LE/GD/LD (PR #123600)

Zhaoxin Yang via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 9 20:58:44 PDT 2025


https://github.com/ylzsx updated https://github.com/llvm/llvm-project/pull/123600

>From ea9fea20110021eb5095564f5c4b46e07974deeb Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 27 Dec 2024 15:32:34 +0800
Subject: [PATCH 01/20] Relax PCHi20Lo12.

Support relaxation optimization for two types of code sequences.
```
From:
  pcalau12i $a0, %pc_hi20(sym)
    R_LARCH_PCALA_HI20, R_LARCH_RELAX
  addi.w/d $a0, $a0, %pc_lo12(sym)
    R_LARCH_PCALA_LO12, R_LARCH_RELAX
To:
  pcaddi $a0, %pc_lo12(sym)
    R_LARCH_PCREL20_S2

From:
  pcalau12i $a0, %got_pc_hi20(sym_got)
    R_LARCH_GOT_PC_HI20, R_LARCH_RELAX
  ld.w/d $a0, $a0, %got_pc_lo12(sym_got)
    R_LARCH_GOT_PC_LO12, R_LARCH_RELAX
To:
  pcaddi $a0, %got_pc_hi20(sym_got)
    R_LARCH_PCREL20_S2
```
---
 lld/ELF/Arch/LoongArch.cpp | 110 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 2 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 3280c34cb6ed0..07ca66700f648 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -53,6 +53,7 @@ enum Op {
   ADDI_W = 0x02800000,
   ADDI_D = 0x02c00000,
   ANDI = 0x03400000,
+  PCADDI = 0x18000000,
   PCADDU12I = 0x1c000000,
   LD_W = 0x28800000,
   LD_D = 0x28c00000,
@@ -131,6 +132,8 @@ static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
   return begin == 63 ? v >> end : (v & ((1ULL << (begin + 1)) - 1)) >> end;
 }
 
+static uint32_t getD5(uint64_t v) { return extractBits(v, 4, 0); }
+
 static uint32_t setD5k16(uint32_t insn, uint32_t imm) {
   uint32_t immLo = extractBits(imm, 15, 0);
   uint32_t immHi = extractBits(imm, 20, 16);
@@ -743,6 +746,84 @@ 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;
+}
+
+static bool isPairRelaxable(ArrayRef<Relocation> relocs, size_t i) {
+  return relaxable(relocs, i) && relaxable(relocs, i + 2) &&
+         relocs[i].offset + 4 == relocs[i + 2].offset;
+}
+
+// Relax code sequence.
+// From:
+//   pcalau12i $a0, %pc_hi20(sym)
+//   addi.w/d $a0, $a0, %pc_lo12(sym)
+// To:
+//   pcaddi $a0, %pc_lo12(sym)
+//
+// From:
+//   pcalau12i $a0, %got_pc_hi20(sym_got)
+//   ld.w/d $a0, $a0, %got_pc_lo12(sym_got)
+// To:
+//   pcaddi $a0, %got_pc_hi20(sym_got)
+static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
+                            uint64_t loc, Relocation &rHi20, Relocation &rLo12,
+                            uint32_t &remove) {
+  // check if the relocations are relaxable sequences.
+  if (!((rHi20.type == R_LARCH_PCALA_HI20 &&
+         rLo12.type == R_LARCH_PCALA_LO12) ||
+        (rHi20.type == R_LARCH_GOT_PC_HI20 &&
+         rLo12.type == R_LARCH_GOT_PC_LO12)))
+    return;
+
+  // GOT references to absolute symbols can't be relaxed to use pcaddi in
+  // position-independent code, because these instructions produce a relative
+  // address.
+  // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because
+  // these symbols may be resolve in runtime.
+  if (rHi20.type == R_LARCH_GOT_PC_HI20 &&
+      (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible ||
+       rHi20.sym->isGnuIFunc() ||
+       (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section)))
+    return;
+
+  uint64_t symBase = 0;
+  if (rHi20.expr == RE_LOONGARCH_PLT_PAGE_PC)
+    symBase = rHi20.sym->getPltVA(ctx);
+  else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
+           rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
+    symBase = rHi20.sym->getVA(ctx);
+  else {
+    Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr ("
+             << rHi20.expr << ") against symbol " << rHi20.sym
+             << "in relaxPCHi20Lo12";
+    return;
+  }
+  const uint64_t symLocal = symBase + rHi20.addend;
+
+  const int64_t distance = symLocal - loc;
+  // Check if the distance aligns 4 bytes or exceeds the range of pcaddi.
+  if ((distance & 0x3) != 0 || !isInt<22>(distance))
+    return;
+
+  // Note: If we can ensure that the .o files generated by LLVM only contain
+  // relaxable instruction sequences with R_LARCH_RELAX, then we do not need to
+  // decode instructions. The relaxable instruction sequences imply the
+  // following constraints:
+  // * For relocation pairs related to got_pc, the opcodes of instructions
+  // must be pcalau12i + ld.w/d. In other cases, the opcodes must be pcalau12i +
+  // addi.w/d.
+  // * The destination register of pcalau12i is guaranteed to be used only by
+  // the immediately following instruction.
+  const uint32_t nextInsn = read32le(sec.content().data() + rLo12.offset);
+
+  sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
+  sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
+  sec.relaxAux->writes.push_back(insn(PCADDI, getD5(nextInsn), 0, 0));
+  remove = 4;
+}
+
 static bool relax(Ctx &ctx, InputSection &sec) {
   const uint64_t secAddr = sec.getVA();
   const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -781,6 +862,12 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       }
       break;
     }
+    case R_LARCH_PCALA_HI20:
+    case R_LARCH_GOT_PC_HI20:
+      // The overflow check for i+2 will be carried out in isPairRelaxable.
+      if (isPairRelaxable(relocs, i))
+        relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
+      break;
     }
 
     // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -851,6 +938,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 = ctx.bAlloc.Allocate<uint8_t>(newSize);
       uint64_t offset = 0;
       int64_t delta = 0;
@@ -867,11 +955,29 @@ 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;
-        offset = r.offset + remove;
+
+        int64_t skip = 0;
+        if (RelType newType = aux.relocTypes[i]) {
+          switch (newType) {
+          case R_LARCH_RELAX:
+            break;
+          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");
+          }
+        }
+
+        p += skip;
+        offset = r.offset + skip + remove;
       }
       memcpy(p, old.data() + offset, old.size() - offset);
 

>From 95f454086ea7766adeef4ae1e65b7689824ec7df Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Tue, 24 Dec 2024 08:57:29 +0800
Subject: [PATCH 02/20] la.pcrel relax test modify.

---
 lld/test/ELF/loongarch-relax-align.s       | 115 ++++++++++++++-------
 lld/test/ELF/loongarch-relax-emit-relocs.s |  41 +++++---
 2 files changed, 101 insertions(+), 55 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index ab61e15d5caca..9eaff9144d85e 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -6,56 +6,91 @@
 # 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 --check-prefixes=RELAX,NOOLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,NOOLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck --check-prefixes=NORELAX,NOOLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck --check-prefixes=NORELAX,NOOLD %s
 
 ## 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 --check-prefixes=RELAX,OLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s
 
 ## -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
+# NOOLD: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
+# OLD: {{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
+# 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
+
+
+# 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>:
 # 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 ba414e8c93f0f..7bc1f2d29c319 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -5,29 +5,40 @@
 # 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=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=CHECKR
 
 ## --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
+# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
 
-# 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
+# RELAX:      00010000 <_start>:
+# RELAX-NEXT:   pcaddi $a0, 0
+# RELAX-NEXT:     R_LARCH_RELAX _start
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:     R_LARCH_PCREL20_S2 _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
 
 # CHECKR:      <_start>:
 # CHECKR-NEXT:   pcalau12i $a0, 0

>From 7b133c25913598143b2975553cf119b6bee97af2 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 27 Dec 2024 17:33:47 +0800
Subject: [PATCH 03/20] Add test for PCHi20Lo12

---
 lld/test/ELF/loongarch-relax-emit-relocs.s  | 33 ++++++++---
 lld/test/ELF/loongarch-relax-pc-hi20-lo12.s | 62 +++++++++++++++++++++
 2 files changed, 86 insertions(+), 9 deletions(-)
 create mode 100644 lld/test/ELF/loongarch-relax-pc-hi20-lo12.s

diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 7bc1f2d29c319..9f3206b7ce54c 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -3,8 +3,8 @@
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
 # 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: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
 # RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
 # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
 
@@ -13,7 +13,7 @@
 # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
 
 ## --no-relax should keep original relocations.
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
 # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
 
 # RELAX:      00010000 <_start>:
@@ -22,31 +22,45 @@
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   pcaddi $a0, -1
+# RELAX-NEXT:     R_LARCH_RELAX _start
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:     R_LARCH_PCREL20_S2 _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:   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:   pcalau12i $a0, 16
+# NORELAX-NEXT:     R_LARCH_GOT_PC_HI20 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   ld.d      $a0, $a0, 0
+# NORELAX-NEXT:     R_LARCH_GOT_PC_LO12 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
 # NORELAX-NEXT:   ret
+# NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
 
 # 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:   addi.d    $a0, $a0, 0
 # CHECKR-NEXT:     R_LARCH_PCALA_LO12 _start
 # CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   pcalau12i $a0, 0
+# CHECKR-NEXT:     R_LARCH_GOT_PC_HI20 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   ld.d    $a0, $a0, 0
+# CHECKR-NEXT:     R_LARCH_GOT_PC_LO12 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
 # CHECKR-NEXT:   nop
 # CHECKR-NEXT:     R_LARCH_ALIGN *ABS*+0xc
 # CHECKR-NEXT:   nop
@@ -56,5 +70,6 @@
 .global _start
 _start:
   la.pcrel $a0, _start
+  la.got   $a0, _start
   .p2align 4
   ret
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
new file mode 100644
index 0000000000000..a417d89e9fa2e
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -0,0 +1,62 @@
+# REQUIRES: loongarch
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
+
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
+
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s
+
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s
+
+# RELAX-LABEL: <_start>:
+## offset = 0x14000 - 0x10000 = 4096<<2
+# RELAX-NEXT:      10000:  pcaddi $a0, 4096
+# RELAX-NEXT:              pcaddi $a0, 4095
+# RELAX-NEXT:              pcaddi $a0, 4094
+# RELAX-NEXT:              pcaddi $a0, 4093
+
+# NORELAX32-LABEL: <_start>:
+## offset exceed range of pcaddi
+## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0
+# NORELAX32-NEXT:  10000:  pcalau12i     $a0, 1024
+# NORELAX32-NEXT:          addi.w        $a0, $a0, 0
+# NORELAX32-NEXT:          pcalau12i     $a0, 1024
+# NORELAX32-NEXT:          ld.w          $a0, $a0, 4
+# NORELAX32-NEXT:          pcalau12i     $a0, 1024
+# NORELAX32-NEXT:          addi.w        $a0, $a0, 0
+# NORELAX32-NEXT:          pcalau12i     $a0, 1024
+# NORELAX32-NEXT:          ld.w          $a0, $a0, 4
+
+# NORELAX64-LABEL: <_start>:
+## offset exceed range of pcaddi
+## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0
+# NORELAX64-NEXT:  10000:  pcalau12i     $a0, 1024
+# NORELAX64-NEXT:          addi.d        $a0, $a0, 0
+# NORELAX64-NEXT:          pcalau12i     $a0, 1024
+# NORELAX64-NEXT:          ld.d          $a0, $a0, 8
+# NORELAX64-NEXT:          pcalau12i     $a0, 1024
+# NORELAX64-NEXT:          addi.d        $a0, $a0, 0
+# NORELAX64-NEXT:          pcalau12i     $a0, 1024
+# NORELAX64-NEXT:          ld.d          $a0, $a0, 8
+
+.section .text
+.global _start
+_start:
+  la.local  $a0, sym
+  la.global $a0, sym
+  la.pcrel  $a0, sym
+  la.got    $a0, sym
+
+.section .data
+sym:
+  .zero 4

>From abc1a458c7edc2d44e4f9295aa6654b4cd6ac9d8 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Mon, 30 Dec 2024 19:29:43 +0800
Subject: [PATCH 04/20] Add test for got symbols relaxation.

Similar to aarch64-adrp-ldr-got-symbols.s.
---
 ...loongarch-relax-pc-hi20-lo12-got-symbols.s | 90 +++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s

diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
new file mode 100644
index 0000000000000..bafb631bccb91
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
@@ -0,0 +1,90 @@
+## This test verifies that the pair pcalau12i + ld.w/d is relaxed/not relaxed
+## depending on the target symbol properties.
+
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax symbols.s -o symbols.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax symbols.s -o symbols.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o
+
+# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
+# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s
+
+# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
+# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s
+
+
+## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied.
+LIB:      pcaddi      $a0, {{[0-9]+}}
+## Symbol 'global_sym' is preemptible, no relaxations should be applied.
+LIB-NEXT: pcalau12i   $a1, 4
+LIB-NEXT: ld.{{[wd]}} $a1, $a1, {{[0-9]+}}
+## Symbol 'undefined_sym' is undefined, no relaxations should be applied.
+LIB-NEXT: pcalau12i   $a2, 4
+LIB-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}}
+## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied.
+LIB-NEXT: pcalau12i   $a3, 4
+LIB-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}}
+## Symbol 'abs_sym' is absolute, no relaxations should be applied.
+LIB-NEXT: pcalau12i   $a4, 4
+LIB-NEXT: ld.{{[wd]}} $a4, $a4, {{[0-9]+}}
+
+
+## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied.
+EXE:      pcaddi      $a0, {{[0-9]+}}
+## Symbol 'global_sym' is nonpreemptible, the relaxation should be applied.
+EXE-NEXT: pcaddi      $a1, {{[0-9]+}}
+## Symbol 'undefined_sym' is undefined, no relaxations should be applied.
+EXE-NEXT: pcalau12i   $a2, 4
+EXE-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}}
+## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied.
+EXE-NEXT: pcalau12i   $a3, 4
+EXE-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}}
+## Symbol 'abs_sym' is absolute, relaxations may be applied in -no-pie mode.
+EXE-NEXT: pcaddi      $a4, -{{[0-9]+}}
+
+
+## The linker script ensures that .rodata and .text are near (>4M) so that
+## the pcalau12i+ld.w/d pair can be relaxed to pcaddi.
+#--- linker.t
+SECTIONS {
+ .text   0x10000: { *(.text) }
+ .rodata 0x14000: { *(.rodata) }
+}
+
+# This symbol is defined in a separate file to prevent the definition from
+# being folded into the instructions that reference it.
+#--- abs.s
+.global abs_sym
+.hidden abs_sym
+abs_sym = 0x1000
+
+#--- symbols.s
+.rodata
+.hidden hidden_sym
+hidden_sym:
+.word 10
+
+.global global_sym
+global_sym:
+.word 10
+
+.text
+.type ifunc_sym STT_GNU_IFUNC
+.hidden ifunc_sym
+ifunc_sym:
+  nop
+
+.global _start
+_start:
+  la.got    $a0, hidden_sym
+  la.got    $a1, global_sym
+  la.got    $a2, undefined_sym
+  la.got    $a3, ifunc_sym
+  la.got    $a4, abs_sym

>From 1b1804e3e26970cdf92ff1998d33a3f6ec59581d Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Wed, 15 Jan 2025 13:56:26 +0800
Subject: [PATCH 05/20] Modify test. NFC

Dependency on https://github.com/llvm/llvm-project/pull/123017
---
 lld/test/ELF/loongarch-relax-align.s               | 14 +++++++-------
 lld/test/ELF/loongarch-relax-emit-relocs.s         |  8 ++++----
 .../ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s |  8 ++++----
 lld/test/ELF/loongarch-relax-pc-hi20-lo12.s        | 12 ++++++------
 4 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index 9eaff9144d85e..66a8ed3abf71e 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -2,10 +2,10 @@
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32
-# 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: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.64.o -o %t.64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.32.o -o %t.32n
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.64.o -o %t.64n
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,NOOLD %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck --check-prefixes=NORELAX,NOOLD %s
@@ -13,13 +13,13 @@
 
 ## 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: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.o64.o -o %t.o64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.o64.o -o %t.o64n
 # RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s
 
 ## -r keeps section contents unchanged.
-# RUN: ld.lld -r %t.64.o -o %t.64.r
+# RUN: ld.lld -r --relax %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR
 
 # NOOLD: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 9f3206b7ce54c..a02cd272aba5b 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -3,13 +3,13 @@
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
-# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64
 # 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: ld.lld --relax -r %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
 
 ## --no-relax should keep original relocations.
@@ -58,7 +58,7 @@
 # CHECKR-NEXT:   pcalau12i $a0, 0
 # CHECKR-NEXT:     R_LARCH_GOT_PC_HI20 _start
 # CHECKR-NEXT:     R_LARCH_RELAX *ABS*
-# CHECKR-NEXT:   ld.d    $a0, $a0, 0
+# CHECKR-NEXT:   ld.d      $a0, $a0, 0
 # CHECKR-NEXT:     R_LARCH_GOT_PC_LO12 _start
 # CHECKR-NEXT:     R_LARCH_RELAX *ABS*
 # CHECKR-NEXT:   nop
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
index bafb631bccb91..0a75d2289209c 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
@@ -9,13 +9,13 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o
 
-# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
-# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
+# RUN: ld.lld --shared --relax -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
+# RUN: ld.lld --shared --relax -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s
 
-# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
-# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
+# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
+# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s
 
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index a417d89e9fa2e..760fe77d774e3 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -3,18 +3,18 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
 
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -o %t.64
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
 
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -shared -o %t.32s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -shared -o %t.64s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s
 
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.32.o -o %t.32o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.64.o -o %t.64o
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s
 

>From 30cb3827458cf4fc585aa72f62f77971d8b47a36 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Mon, 20 Jan 2025 08:51:15 +0800
Subject: [PATCH 06/20] Add check for register.

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

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 07ca66700f648..b999e7fd27ae9 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -134,6 +134,8 @@ static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
 
 static uint32_t getD5(uint64_t v) { return extractBits(v, 4, 0); }
 
+static uint32_t getJ5(uint64_t v) { return extractBits(v, 9, 5); }
+
 static uint32_t setD5k16(uint32_t insn, uint32_t imm) {
   uint32_t immLo = extractBits(imm, 15, 0);
   uint32_t immHi = extractBits(imm, 20, 16);
@@ -816,7 +818,11 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
   // addi.w/d.
   // * The destination register of pcalau12i is guaranteed to be used only by
   // the immediately following instruction.
+  const uint32_t currInsn = read32le(sec.content().data() + rHi20.offset);
   const uint32_t nextInsn = read32le(sec.content().data() + rLo12.offset);
+  // Check if use the same register.
+  if (getD5(currInsn) != getJ5(nextInsn) || getJ5(nextInsn) != getD5(nextInsn))
+    return;
 
   sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
   sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;

>From f1f995b5fc8e90126b5825d52b9c75cd45d27cfc Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Thu, 26 Dec 2024 11:32:33 +0800
Subject: [PATCH 07/20] Relax call36/tail36.

Instructions with relocation `R_LARCH_CALL36` may be relax as follows:
```
From:
  pcaddu18i $dest, %call36(foo)
    R_LARCH_CALL36, R_LARCH_RELAX
  jirl $r, $dest, 0
To:
  b/bl foo  # bl if r=$ra, b if r=$zero
    R_LARCH_B26
```
---
 lld/ELF/Arch/LoongArch.cpp | 41 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index b999e7fd27ae9..0aa0cf5b657a0 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -58,6 +58,8 @@ enum Op {
   LD_W = 0x28800000,
   LD_D = 0x28c00000,
   JIRL = 0x4c000000,
+  B = 0x50000000,
+  BL = 0x54000000,
 };
 
 enum Reg {
@@ -830,6 +832,37 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
   remove = 4;
 }
 
+// Relax code sequence.
+// From:
+//   pcaddu18i $ra, %call36(foo)
+//   jirl $ra, $ra, 0
+// To:
+//   b/bl foo
+static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
+                        uint64_t loc, Relocation &r, uint32_t &remove) {
+  const uint64_t symLocal =
+      (r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) +
+      r.addend;
+
+  const int64_t distance = symLocal - loc;
+  // Check if the distance aligns 4 bytes or exceeds the range of b[l].
+  if ((distance & 0x3) != 0 || !isInt<28>(distance))
+    return;
+
+  const uint32_t nextInsn = read32le(sec.content().data() + r.offset + 4);
+  if (getD5(nextInsn) == R_RA) {
+    // convert jirl to bl
+    sec.relaxAux->relocTypes[i] = R_LARCH_B26;
+    sec.relaxAux->writes.push_back(insn(BL, 0, 0, 0));
+    remove = 4;
+  } else if (getD5(nextInsn) == R_ZERO) {
+    // convert jirl to b
+    sec.relaxAux->relocTypes[i] = R_LARCH_B26;
+    sec.relaxAux->writes.push_back(insn(B, 0, 0, 0));
+    remove = 4;
+  }
+}
+
 static bool relax(Ctx &ctx, InputSection &sec) {
   const uint64_t secAddr = sec.getVA();
   const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -874,6 +907,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       if (isPairRelaxable(relocs, i))
         relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
       break;
+    case R_LARCH_CALL36:
+      if (relaxable(relocs, i))
+        relaxCall36(ctx, sec, i, loc, r, remove);
+      break;
     }
 
     // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -977,6 +1014,10 @@ void LoongArch::finalizeRelax(int passes) const {
             // RelExpr is needed for relocating.
             r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
             break;
+          case R_LARCH_B26:
+            skip = 4;
+            write32le(p, aux.writes[writesIdx++]);
+            break;
           default:
             llvm_unreachable("unsupported type");
           }

>From f227ae532236e20148a872c811721a8de4e16318 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 27 Dec 2024 14:37:40 +0800
Subject: [PATCH 08/20] modify test for call36/tail36.

---
 lld/test/ELF/loongarch-relax-call36-2.s      |  63 +++++++++
 lld/test/ELF/loongarch-relax-call36.s        | 135 +++++++++++++++++++
 lld/test/ELF/loongarch-relax-emit-relocs-2.s |  61 +++++++++
 3 files changed, 259 insertions(+)
 create mode 100644 lld/test/ELF/loongarch-relax-call36-2.s
 create mode 100644 lld/test/ELF/loongarch-relax-call36.s
 create mode 100644 lld/test/ELF/loongarch-relax-emit-relocs-2.s

diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s
new file mode 100644
index 0000000000000..1c216a9bdc35e
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-call36-2.s
@@ -0,0 +1,63 @@
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o
+
+# RUN: ld.lld -T lds a.o -o a
+# RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s --check-prefixes=RELAX,RELAX-MID
+
+## Unsure whether this needs a diagnostic. GNU ld allows this.
+# RUN: ld.lld -T lds -pie a.o -o a.pie
+# RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s --check-prefixes=RELAX,RELAX-MID
+
+# RUN: ld.lld -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
+# RUN: llvm-objdump -d --no-show-raw-insn a.ifunc-noplt | FileCheck %s --check-prefixes=RELAX,NORELAX-MID
+
+# RELAX-LABEL:  <_start>:
+## offset = 0x10000000 - 0x8000000 = 0x8000000(134217728), hi=512, lo18=0
+# RELAX-NEXT:    8000000:  pcaddu18i $ra, 512
+# RELAX-NEXT:              jirl   $ra, $ra, 0
+# RELAX-NEXT:              bl     134217720
+# RELAX-NEXT:              bl     -134217728
+## offset = 12 - 0x8000010 = -0x8000004(-134217732), hi=512, lo18=-4
+# RELAX-NEXT:    8000010:  pcaddu18i $ra, -512
+# RELAX-NEXT:              jirl   $ra, $ra, -4
+# RELAX-EMPTY:
+
+# RELAX-MID-LABEL:  <.mid>:
+## offset = 0x8010000 - 0x8008000 = 32768
+# RELAX-MID-NEXT:    8008000:  bl     32768
+# RELAX-MID-NEXT:              b      32764
+# RELAX-MID-EMPTY:
+
+# NORELAX-MID-LABEL: <.mid>:
+# NORELAX-MID-NEXT:  8008000:  pcaddu18i $ra, 0
+# NORELAX-MID-NEXT:            jirl   $ra, $ra, 0
+# NORELAX-MID-NEXT:            pcaddu18i $t0, 0
+# NORELAX-MID-NEXT:            jr     $t0
+# NORELAX-MID-EMPTY:
+
+#--- a.s
+.global _start, ifunc
+_start:
+  call36 pos       # exceed positive range (.text+0x7fffffc), not relaxed
+  call36 pos       # relaxed
+  call36 neg       # relaxed
+  call36 neg       # exceed negative range (.text+16-0x8000000), not relaxed
+
+.section .mid,"ax", at progbits
+.balign 16
+  call36 ifunc at plt      # enable ifunc, not relaxed
+  tail36 $t0, ifunc at plt # enable ifunc, not relaxed
+
+.type ifunc, @gnu_indirect_function
+ifunc:
+  ret
+
+#--- lds
+SECTIONS {
+  .text 0x8000000 : { *(.text) }
+  .mid  0x8008000 : { *(.mid) }
+  .iplt 0x8010000 : { *(.iplt) }
+}
+neg = 12;
+pos = 0x10000000;
diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s
new file mode 100644
index 0000000000000..57ed214c9eb2e
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-call36.s
@@ -0,0 +1,135 @@
+# REQUIRES: loongarch
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o
+# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so
+# RUN: ld.lld -T lds a.64.o b.64.so -o 64
+# RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX
+
+## --no-relax disables relaxation.
+# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax
+# RUN: llvm-objdump -td --no-show-raw-insn 64.norelax | FileCheck %s --check-prefix=NORELAX
+
+# RELAX:       {{0*}}00010000 g       .text  {{0*}}0000001c _start
+# RELAX:       {{0*}}0001001c g       .text  {{0*}}00000000 _start_end
+# RELAX:       {{0*}}00010808 g       .mid   {{0*}}00000000 mid_end
+# RELAX:       {{0*}}10010010 g       .high  {{0*}}00000000 high_end
+
+# RELAX-LABEL: <_start>:
+## offset = 0x10018 - 0x10000 = 24
+# RELAX-NEXT:      10000:  bl     24 <a>
+# RELAX-NEXT:              b      20 <a>
+# RELAX-NEXT:              nop
+# RELAX-NEXT:              nop
+## offset = .plt(0x10400)+32 - 0x10010 = 1040
+# RELAX-NEXT:      10010:  bl     1040 <bar+0x10420>
+# RELAX-NEXT:              b      1036 <bar+0x10420>
+# RELAX-EMPTY:
+# RELAX-NEXT: <a>:
+# RELAX-NEXT:      10018:  ret
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.mid>:
+## offset = 0x10000 - 0x10800 = -2048
+# RELAX-NEXT:      10800:  bl     -2048 <_start>
+# RELAX-NEXT:              b      -2052 <_start>
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.mid2>:
+## offset = 0x10000 - 0x1010000 = -16777216
+# RELAX-NEXT:    1010000:  bl     -16777216 <_start>
+# RELAX-NEXT:              b      -16777220 <_start>
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.high>:
+## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
+# RELAX-NEXT:   10010000:  pcaddu18i $ra, -1024
+# RELAX-NEXT:              jirl   $ra, $ra, 0
+# RELAX-NEXT:              pcaddu18i $t0, -1024
+# RELAX-NEXT:              jirl   $zero, $t0, -8
+# RELAX-EMPTY:
+
+
+# NORELAX-LABEL: <_start>:
+## offset = 0x10020 - 0x10000 = 0x20, hi=0, lo18=32
+# NORELAX-NEXT:    10000:  pcaddu18i $ra, 0
+# NORELAX-NEXT:            jirl   $ra, $ra, 32
+## offset = 0x10020 - 0x10008 = 0x18, hi=0, lo18=24
+# NORELAX-NEXT:    10008:  pcaddu18i $t0, 0
+# NORELAX-NEXT:            jirl   $zero, $t0, 24
+## offset = .plt(0x10400)+32 - 0x10010 = 0x410, hi=0, lo18=1040
+# NORELAX-NEXT:    10010:  pcaddu18i $ra, 0
+# NORELAX-NEXT:            jirl   $ra, $ra, 1040
+## offset = .plt(0x10400)+32 - 0x10018 = 0x408, hi=0, lo18=1032
+# NORELAX-NEXT:    10018:  pcaddu18i $t0, 0
+# NORELAX-NEXT:            jirl   $zero, $t0, 1032
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <a>:
+# NORELAX-NEXT:      10020:  ret
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.mid>:
+## offset = 0x10000 - 0x10800 = -0x800, hi=0, lo18=-2048
+# NORELAX-NEXT:    10800:  pcaddu18i $ra, 0
+# NORELAX-NEXT:            jirl   $ra, $ra, -2048
+# NORELAX-NEXT:            pcaddu18i $t0, 0
+# NORELAX-NEXT:            jirl   $zero, $t0, -2056
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.mid2>:
+## offset = 0x10000 - 0x1010000 = -0x1000000, hi=-64, lo18=0
+# NORELAX-NEXT:  1010000:  pcaddu18i $ra, -64
+# NORELAX-NEXT:            jirl   $ra, $ra, 0
+# NORELAX-NEXT:            pcaddu18i $t0, -64
+# NORELAX-NEXT:            jirl   $zero, $t0, -8
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.high>:
+## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
+# NORELAX-NEXT: 10010000:  pcaddu18i $ra, -1024
+# NORELAX-NEXT:            jirl   $ra, $ra, 0
+# NORELAX-NEXT:            pcaddu18i $t0, -1024
+# NORELAX-NEXT:            jirl   $zero, $t0, -8
+# NORELAX-EMPTY:
+
+#--- a.s
+.global _start, _start_end
+_start:
+  call36 a          # relaxed. la64: bl
+  tail36 $t0, a at plt # relaxed. la64: b
+.balign 16
+  call36 bar        # PLT call36 can be relaxed. la64: bl
+  tail36 $t0, bar   # PLT tail36 can be relaxed. la64: bl
+
+a:
+  ret
+.size _start, . - _start
+_start_end:
+
+.section .mid,"ax", at progbits
+  call36 _start at plt         # relaxed. la64: bl
+  tail36 $t0, _start at plt    # relaxed. la64: b
+
+.section .mid2,"ax", at progbits
+  call36 _start at plt         # relaxed. la64: bl
+  tail36 $t0, _start at plt    # relaxed. la64: b
+
+.section .high,"ax", at progbits
+  call36 _start at plt         # exceed range, not relaxed
+  tail36 $t0,_start at plt     # exceed range, not relaxed
+
+#--- b.s
+.globl bar
+bar:
+  ret
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .plt 0x10400 : { *(.plt) }
+  .mid 0x10800 : { *(.mid); mid_end = .; }
+  .mid2 0x1010000 : { *(.mid2) }
+  .high 0x10010000 : { *(.high); high_end = .; }
+}
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
new file mode 100644
index 0000000000000..31cae939eca71
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
@@ -0,0 +1,61 @@
+# REQUIRES: loongarch
+## Test that we can handle --emit-relocs while relaxing.
+## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version.
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
+# 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=CHECKR
+
+## --no-relax should keep original relocations.
+# 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
+
+# RELAX:      00010000 <_start>:
+# RELAX-NEXT:   bl  0
+# RELAX-NEXT:     R_LARCH_B26 _start
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   b   -4
+# RELAX-NEXT:     R_LARCH_B26 _start
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   nop
+# RELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# RELAX-NEXT:   nop
+# RELAX-NEXT:   ret
+
+# CHECKR:      <_start>:
+# CHECKR-NEXT:   pcaddu18i $ra, 0
+# CHECKR-NEXT:     R_LARCH_CALL36 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   jirl   $ra, $ra, 0
+# CHECKR-NEXT:   pcaddu18i $t0, 0
+# CHECKR-NEXT:     R_LARCH_CALL36 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   jr     $t0
+# CHECKR-NEXT:   nop
+# CHECKR-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# CHECKR-NEXT:   nop
+# CHECKR-NEXT:   nop
+# CHECKR-NEXT:   ret
+
+# NORELAX:      <_start>:
+# NORELAX-NEXT:   pcaddu18i $ra, 0
+# NORELAX-NEXT:     R_LARCH_CALL36 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   jirl   $ra, $ra, 0
+# NORELAX-NEXT:   pcaddu18i $t0, 0
+# NORELAX-NEXT:     R_LARCH_CALL36 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   jirl $zero, $t0, -8
+# NORELAX-NEXT:   ret
+# NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+
+.global _start
+_start:
+  call36 _start
+  tail36 $t0, _start
+  .p2align 4
+  ret

>From f2aae15f701863d03edd32657824a97f66696e8d Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Thu, 16 Jan 2025 21:50:14 +0800
Subject: [PATCH 09/20] Modify test. Add the option --relax.

---
 lld/test/ELF/loongarch-relax-call36-2.s      | 6 +++---
 lld/test/ELF/loongarch-relax-call36.s        | 6 +++---
 lld/test/ELF/loongarch-relax-emit-relocs-2.s | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s
index 1c216a9bdc35e..71650aefe9432 100644
--- a/lld/test/ELF/loongarch-relax-call36-2.s
+++ b/lld/test/ELF/loongarch-relax-call36-2.s
@@ -2,14 +2,14 @@
 # RUN: rm -rf %t && split-file %s %t && cd %t
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o
 
-# RUN: ld.lld -T lds a.o -o a
+# RUN: ld.lld --relax -T lds a.o -o a
 # RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s --check-prefixes=RELAX,RELAX-MID
 
 ## Unsure whether this needs a diagnostic. GNU ld allows this.
-# RUN: ld.lld -T lds -pie a.o -o a.pie
+# RUN: ld.lld --relax -T lds -pie a.o -o a.pie
 # RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s --check-prefixes=RELAX,RELAX-MID
 
-# RUN: ld.lld -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
+# RUN: ld.lld --relax -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
 # RUN: llvm-objdump -d --no-show-raw-insn a.ifunc-noplt | FileCheck %s --check-prefixes=RELAX,NORELAX-MID
 
 # RELAX-LABEL:  <_start>:
diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s
index 57ed214c9eb2e..bda0c4f05da91 100644
--- a/lld/test/ELF/loongarch-relax-call36.s
+++ b/lld/test/ELF/loongarch-relax-call36.s
@@ -4,12 +4,12 @@
 
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o
-# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so
-# RUN: ld.lld -T lds a.64.o b.64.so -o 64
+# RUN: ld.lld --relax -shared -soname=b.so b.64.o -o b.64.so
+# RUN: ld.lld --relax -T lds a.64.o b.64.so -o 64
 # RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX
 
 ## --no-relax disables relaxation.
-# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax
+# RUN: ld.lld --no-relax -T lds a.64.o b.64.so -o 64.norelax
 # RUN: llvm-objdump -td --no-show-raw-insn 64.norelax | FileCheck %s --check-prefix=NORELAX
 
 # RELAX:       {{0*}}00010000 g       .text  {{0*}}0000001c _start
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
index 31cae939eca71..eddfc46b1ad08 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs-2.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
@@ -3,15 +3,15 @@
 ## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version.
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
+# RUN: ld.lld --relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
 # 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: ld.lld --relax -r %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
 
 ## --no-relax should keep original relocations.
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
+# RUN: ld.lld --no-relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64.norelax
 # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
 
 # RELAX:      00010000 <_start>:

>From 7993434e2973437b010034051003f8c03d8eff71 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 27 Dec 2024 19:29:32 +0800
Subject: [PATCH 10/20] Relax TLS LE/GD/LD.

In local-exec form, the code sequence is converted as follows:
```
From:
lu12i.w $rd, %le_hi20_r(sym)
  R_LARCH_TLS_LE_HI20_R, R_LARCH_RELAX
add.w/d $rd, $rd, $tp, %le_add_r(sym)
  R_LARCH_TLS_LE_ADD_R, R_LARCH_RELAX
addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym)
  R_LARCH_TLS_LE_LO12_R, R_LARCH_RELAX
To:
addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym)
  R_LARCH_TLS_LE_LO12_R
```

In global-dynamic or local-dynamic, the code sequence is converted as
follows:
```
From:
pcalau12i     $a0, %ld_pc_hi20(sym)  | %gd_pc_hi20(sym)
  R_LARCH_TLS_GD_PC_HI20 | R_LARCH_TLS_LD_PC_HI20, R_LARCH_RELAX
addi.w/d $a0, $a0, %got_pc_lo12(sym) | %got_pc_lo12(sym)
  R_LARCH_GOT_PC_LO12, R_LARCH_RELAX
To:
pcaddi        $a0, %got_pc_lo12(sym) | %got_pc_lo12(sym)
  R_LARCH_TLS_GD_PCREL20_S2 | R_LARCH_TLS_LD_PCREL20_S2
```

Note: For initial-exec form, since it involves the conversion from IE to
LE, we will implement it in a future patch.
---
 lld/ELF/Arch/LoongArch.cpp | 68 +++++++++++++++++++++++++++++++++++---
 1 file changed, 64 insertions(+), 4 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 0aa0cf5b657a0..2d6d86d2ca63b 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -761,10 +761,10 @@ static bool isPairRelaxable(ArrayRef<Relocation> relocs, size_t i) {
 
 // Relax code sequence.
 // From:
-//   pcalau12i $a0, %pc_hi20(sym)
-//   addi.w/d $a0, $a0, %pc_lo12(sym)
+//   pcalau12i     $a0, %pc_hi20(sym) | %ld_pc_hi20(sym)  | %gd_pc_hi20(sym)
+//   addi.w/d $a0, $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
 // To:
-//   pcaddi $a0, %pc_lo12(sym)
+//   pcaddi $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
 //
 // From:
 //   pcalau12i $a0, %got_pc_hi20(sym_got)
@@ -778,6 +778,10 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
   if (!((rHi20.type == R_LARCH_PCALA_HI20 &&
          rLo12.type == R_LARCH_PCALA_LO12) ||
         (rHi20.type == R_LARCH_GOT_PC_HI20 &&
+         rLo12.type == R_LARCH_GOT_PC_LO12) ||
+        (rHi20.type == R_LARCH_TLS_GD_PC_HI20 &&
+         rLo12.type == R_LARCH_GOT_PC_LO12) ||
+        (rHi20.type == R_LARCH_TLS_LD_PC_HI20 &&
          rLo12.type == R_LARCH_GOT_PC_LO12)))
     return;
 
@@ -798,6 +802,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
   else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
            rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
     symBase = rHi20.sym->getVA(ctx);
+  else if (rHi20.expr == RE_LOONGARCH_TLSGD_PAGE_PC)
+    symBase = ctx.in.got->getGlobalDynAddr(*rHi20.sym);
   else {
     Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr ("
              << rHi20.expr << ") against symbol " << rHi20.sym
@@ -827,7 +833,12 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
     return;
 
   sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
-  sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
+  if (rHi20.type == R_LARCH_TLS_GD_PC_HI20)
+    sec.relaxAux->relocTypes[i + 2] = R_LARCH_TLS_GD_PCREL20_S2;
+  else if (rHi20.type == R_LARCH_TLS_LD_PC_HI20)
+    sec.relaxAux->relocTypes[i + 2] = R_LARCH_TLS_LD_PCREL20_S2;
+  else
+    sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
   sec.relaxAux->writes.push_back(insn(PCADDI, getD5(nextInsn), 0, 0));
   remove = 4;
 }
@@ -863,6 +874,35 @@ static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
   }
 }
 
+// Relax code sequence.
+// From:
+//   lu12i.w $rd, %le_hi20_r(sym)
+//   add.w/d $rd, $rd, $tp, %le_add_r(sym)
+//   addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym)
+// To:
+//   addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym)
+static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i,
+                       uint64_t loc, Relocation &r, uint32_t &remove) {
+  uint64_t val = r.sym->getVA(ctx, r.addend);
+  // Check if the val exceeds the range of addi/ld/st.
+  if (!isInt<12>(val))
+    return;
+  uint32_t currInsn = read32le(sec.content().data() + r.offset);
+  switch (r.type) {
+  case R_LARCH_TLS_LE_HI20_R:
+  case R_LARCH_TLS_LE_ADD_R:
+    sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
+    remove = 4;
+    break;
+  case R_LARCH_TLS_LE_LO12_R:
+    currInsn =
+        insn(extractBits(currInsn, 31, 22) << 22, getD5(currInsn), R_TP, 0);
+    sec.relaxAux->writes.push_back(currInsn);
+    sec.relaxAux->relocTypes[i] = R_LARCH_TLS_LE_LO12_R;
+    break;
+  }
+}
+
 static bool relax(Ctx &ctx, InputSection &sec) {
   const uint64_t secAddr = sec.getVA();
   const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -903,6 +943,8 @@ static bool relax(Ctx &ctx, InputSection &sec) {
     }
     case R_LARCH_PCALA_HI20:
     case R_LARCH_GOT_PC_HI20:
+    case R_LARCH_TLS_GD_PC_HI20:
+    case R_LARCH_TLS_LD_PC_HI20:
       // The overflow check for i+2 will be carried out in isPairRelaxable.
       if (isPairRelaxable(relocs, i))
         relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
@@ -911,6 +953,12 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       if (relaxable(relocs, i))
         relaxCall36(ctx, sec, i, loc, r, remove);
       break;
+    case R_LARCH_TLS_LE_HI20_R:
+    case R_LARCH_TLS_LE_ADD_R:
+    case R_LARCH_TLS_LE_LO12_R:
+      if (relaxable(relocs, i))
+        relaxTlsLe(ctx, sec, i, loc, r, remove);
+      break;
     }
 
     // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -1015,8 +1063,20 @@ void LoongArch::finalizeRelax(int passes) const {
             r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
             break;
           case R_LARCH_B26:
+          case R_LARCH_TLS_LE_LO12_R:
+            skip = 4;
+            write32le(p, aux.writes[writesIdx++]);
+            break;
+          case R_LARCH_TLS_GD_PCREL20_S2:
+            // Note: R_LARCH_TLS_LD_PCREL20_S2 must also use R_TLSGD_PC instead
+            // of R_TLSLD_PC because the processing of relocation
+            // R_LARCH_TLS_LD_PC_HI20 is the same as R_LARCH_TLS_GD_PC_HI20. If
+            // not, the value obtained from getRelocTargetVA will be unexpected
+            // and lead to error.
+          case R_LARCH_TLS_LD_PCREL20_S2:
             skip = 4;
             write32le(p, aux.writes[writesIdx++]);
+            r.expr = R_TLSGD_PC;
             break;
           default:
             llvm_unreachable("unsupported type");

>From 1e9aa529f34dbe6d61295980593c894d3074a7b2 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Sun, 29 Dec 2024 17:02:09 +0800
Subject: [PATCH 11/20] Add test for TLSLD/TLSGD when relax enabled.

---
 lld/test/ELF/loongarch-tls-gd.s | 43 +++++++++++++++++++++++++++++++--
 lld/test/ELF/loongarch-tls-ld.s | 40 ++++++++++++++++++++++++++++--
 2 files changed, 79 insertions(+), 4 deletions(-)

diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s
index 2aecb44c17a34..27d9fdb7ee701 100644
--- a/lld/test/ELF/loongarch-tls-gd.s
+++ b/lld/test/ELF/loongarch-tls-gd.s
@@ -1,14 +1,17 @@
 # REQUIRES: loongarch
 # RUN: rm -rf %t && split-file %s %t
 
-## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not
-## relaxed, dynamic relocations can be omitted for GD->LE relaxation.
+## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc:
+## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`.
+## (b) dynamic relocations can be omitted for LD->LE relaxation.
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/a.s -o %t/a.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %t/a.s -o %t/a.32.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/bc.s -o %t/bc.32.o
 # RUN: ld.lld -shared -soname=bc.so %t/bc.32.o -o %t/bc.32.so
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -o %t/a.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -mattr=+relax -o %t/a.64.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/bc.s -o %t/bc.64.o
 # RUN: ld.lld -shared -soname=bc.so %t/bc.64.o -o %t/bc.64.so
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o
@@ -17,6 +20,9 @@
 # RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so
 # RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s
+# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so
+# RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s
 
 ## LA32 GD -> LE
 # RUN: ld.lld %t/a.32.o %t/bc.32.o %t/tga.32.o -o %t/le.32
@@ -35,6 +41,9 @@
 # RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so
 # RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s
+# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so
+# RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s
 
 ## LA64 GD -> LE
 # RUN: ld.lld %t/a.64.o %t/bc.64.o %t/tga.64.o -o %t/le.64
@@ -66,6 +75,21 @@
 # GD32-NEXT:        addi.w $a0, $a0, 792
 # GD32-NEXT:        bl 44
 
+# GD32-REL-RELAX:      .rela.dyn {
+# GD32-REL-RELAX-NEXT:   0x20300 R_LARCH_TLS_DTPMOD32 a 0x0
+# GD32-REL-RELAX-NEXT:   0x20304 R_LARCH_TLS_DTPREL32 a 0x0
+# GD32-REL-RELAX-NEXT:   0x20308 R_LARCH_TLS_DTPMOD32 b 0x0
+# GD32-REL-RELAX-NEXT:   0x2030C R_LARCH_TLS_DTPREL32 b 0x0
+# GD32-REL-RELAX-NEXT: }
+
+## &DTPMOD(a) - . = 0x20300 - 0x10250 = 16428<<2
+# GD32-RELAX:      10250: pcaddi $a0, 16428
+# GD32-RELAX-NEXT:        bl 44
+
+## &DTPMOD(b) - . = 0x20308 - 0x10258 = 16428<<2
+# GD32-RELAX:      10258: pcaddi $a0, 16428
+# GD32-RELAX-NEXT:        bl 36
+
 # GD64-REL:      .rela.dyn {
 # GD64-REL-NEXT:   0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0
 # GD64-REL-NEXT:   0x204C8 R_LARCH_TLS_DTPREL64 a 0x0
@@ -83,6 +107,21 @@
 # GD64-NEXT:        addi.d $a0, $a0, 1232
 # GD64-NEXT:        bl 36
 
+# GD64-REL-RELAX:      .rela.dyn {
+# GD64-REL-RELAX-NEXT:   0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0
+# GD64-REL-RELAX-NEXT:   0x204C8 R_LARCH_TLS_DTPREL64 a 0x0
+# GD64-REL-RELAX-NEXT:   0x204D0 R_LARCH_TLS_DTPMOD64 b 0x0
+# GD64-REL-RELAX-NEXT:   0x204D8 R_LARCH_TLS_DTPREL64 b 0x0
+# GD64-REL-RELAX-NEXT: }
+
+## &DTPMOD(a) - . = 0x204c0 - 0x10398 = 16458<<2
+# GD64-RELAX:      10398: pcaddi $a0, 16458
+# GD64-RELAX-NEXT:        bl 52
+
+## &DTPMOD(b) - . = 0x204d0 - 0x103a0 = 16460<<2
+# GD64-RELAX:      103a0: pcaddi $a0, 16460
+# GD64-RELAX-NEXT:        bl 44
+
 # NOREL: no relocations
 
 ## .got contains pre-populated values: [a at dtpmod, a at dtprel, b at dtpmod, b at dtprel]
diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s
index a5be3ad905b76..27adb1e17702a 100644
--- a/lld/test/ELF/loongarch-tls-ld.s
+++ b/lld/test/ELF/loongarch-tls-ld.s
@@ -1,12 +1,15 @@
 # REQUIRES: loongarch
 # RUN: rm -rf %t && split-file %s %t
 
-## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not
-## relaxed, dynamic relocations can be omitted for LD->LE relaxation.
+## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc:
+## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`.
+## (b) dynamic relocations can be omitted for LD->LE relaxation.
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent %t/a.s -o %t/a.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent -mattr=+relax %t/a.s -o %t/a.32.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent %t/a.s -o %t/a.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent -mattr=+relax %t/a.s -o %t/a.64.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o
 
 ## LA32 LD
@@ -14,24 +17,34 @@
 # RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s
 # RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s
+# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so
+# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s
 
 ## LA32 LD -> LE
 # RUN: ld.lld %t/a.32.o %t/tga.32.o -o %t/le.32
 # RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s
 # RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s
+# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax
+# RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s
 
 ## LA64 LD
 # RUN: ld.lld -shared %t/a.64.o -o %t/ld.64.so
 # RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s
 # RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s
+# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so
+# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s
 
 ## LA64 LD -> LE
 # RUN: ld.lld %t/a.64.o %t/tga.64.o -o %t/le.64
 # RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s
 # RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s
+# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax
+# RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s
 
 ## a at dtprel = st_value(a) = 0 is a link-time constant.
 # LD32-REL:      .rela.dyn {
@@ -56,6 +69,14 @@
 # LD64-NEXT:        addi.d $a0, $a0, 1024
 # LD64-NEXT:        bl 40
 
+## LA32: &DTPMOD(a) - . = 0x20280 - 0x101cc = 16429<<2
+# LD32-RELAX:      101cc: pcaddi  $a0, 16429
+# LD32-RELAX-NEXT:        bl 48
+
+## LA64: &DTPMOD(a) - . = 0x20400 - 0x102e0 = 16456<<2
+# LD64-RELAX:      102e0: pcaddi  $a0, 16456
+# LD64-RELAX-NEXT:        bl 44
+
 # NOREL: no relocations
 
 ## a is local - its DTPMOD/DTPREL slots are link-time constants.
@@ -66,6 +87,12 @@
 # LE64-GOT: section '.got':
 # LE64-GOT-NEXT: 0x000301d8 01000000 00000000 00000000 00000000
 
+# LE32-GOT-RELAX: section '.got':
+# LE32-GOT-RELAX-NEXT: 0x0003011c 01000000 00000000
+
+# LE64-GOT-RELAX: section '.got':
+# LE64-GOT-RELAX-NEXT: 0x000301d0 01000000 00000000 00000000 00000000
+
 ## LA32: DTPMOD(.LANCHOR0) - . = 0x30120 - 0x20114: 0x10 pages, page offset 0x120
 # LE32:      20114: pcalau12i $a0, 16
 # LE32-NEXT:        addi.w $a0, $a0, 288
@@ -76,6 +103,15 @@
 # LE64-NEXT:        addi.d $a0, $a0, 472
 # LE64-NEXT:        bl 4
 
+## LA32: DTPMOD(.LANCHOR0) - . = 0x3011c - 0x20114 = 16386<<2
+# LE32-RELAX:      20114: pcaddi $a0, 16386
+# LE32-RELAX-NEXT:        bl 4
+
+## LA64: DTPMOD(.LANCHOR0) - . = 0x301d0 - 0x201c8 = 16386<<2
+# LE64-RELAX:      201c8: pcaddi $a0, 16386
+# LE64-RELAX-NEXT:        bl 4
+
+
 #--- a.s
 la.tls.ld $a0, .LANCHOR0
 bl %plt(__tls_get_addr)

>From 91da25ea973556fc3a9f4dd2af06af0371cc4d36 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Tue, 31 Dec 2024 20:00:17 +0800
Subject: [PATCH 12/20] Modify test for TLSLE when relax enabled.

---
 lld/test/ELF/loongarch-tls-le.s | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s
index 394c60f67bce8..981baa6fd726f 100644
--- a/lld/test/ELF/loongarch-tls-le.s
+++ b/lld/test/ELF/loongarch-tls-le.s
@@ -1,14 +1,20 @@
 # REQUIRES: loongarch
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --defsym ELF32=1 %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --defsym ELF32=1 -mattr=+relax %s -o %t.32.relax.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.relax.o
 
 # RUN: ld.lld %t.32.o -o %t.32
 # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s
+# RUN: ld.lld %t.32.relax.o -o %t.32.relax
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s
 
 # RUN: ld.lld %t.64.o -o %t.64
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s
+# RUN: ld.lld %t.64.relax.o -o %t.64.relax
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s
 
 # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
 
@@ -37,12 +43,22 @@
 # LE32-NEXT: add.w   $a0, $a0, $tp
 # LE32-NEXT: addi.w  $a0, $a0, -2048
 
+# LE32-RELAX:      addi.w  $a0, $tp, 8
+# LE32-RELAX-NEXT: lu12i.w $a0, 1
+# LE32-RELAX-NEXT: add.w   $a0, $a0, $tp
+# LE32-RELAX-NEXT: addi.w  $a0, $a0, -2048
+
 # LE64:      add.d   $a0, $a0, $tp
 # LE64-NEXT: addi.d  $a0, $a0, 8
 # LE64-NEXT: lu12i.w $a0, 1
 # LE64-NEXT: add.d   $a0, $a0, $tp
 # LE64-NEXT: addi.d  $a0, $a0, -2048
 
+# LE64-RELAX:      addi.d  $a0, $tp, 8
+# LE64-RELAX-NEXT: lu12i.w $a0, 1
+# LE64-RELAX-NEXT: add.d   $a0, $a0, $tp
+# LE64-RELAX-NEXT: addi.d  $a0, $a0, -2048
+
 # LE-EMPTY:
 
 .macro add dst, src1, src2, src3

>From 2066c5f7cc3eecfdd76216378efbfb8376fa4262 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Tue, 31 Dec 2024 14:49:40 +0800
Subject: [PATCH 13/20] Add test for loongarch-relax-tls-le.s and modify
 loongarch-relax-emit-relocs.s

---
 lld/test/ELF/loongarch-relax-emit-relocs.s | 112 +++++++++++++++++++-
 lld/test/ELF/loongarch-relax-tls-le.s      | 115 +++++++++++++++++++++
 2 files changed, 222 insertions(+), 5 deletions(-)
 create mode 100644 lld/test/ELF/loongarch-relax-tls-le.s

diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index a02cd272aba5b..5bb445dcaff50 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -1,7 +1,7 @@
 # REQUIRES: loongarch
 ## Test that we can handle --emit-relocs while relaxing.
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax --defsym ELF32=1 %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64
@@ -17,19 +17,39 @@
 # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
 
 # RELAX:      00010000 <_start>:
-# RELAX-NEXT:   pcaddi $a0, 0
+# RELAX-NEXT:   pcaddi    $a0, 0
 # RELAX-NEXT:     R_LARCH_RELAX _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   pcaddi $a0, -1
+# RELAX-NEXT:   pcaddi    $a0, -1
 # RELAX-NEXT:     R_LARCH_RELAX _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   lu12i.w   $a0, 0
+# RELAX-NEXT:     R_LARCH_TLS_LE_HI20 a
+# RELAX-NEXT:   ori       $a0, $a0, 0
+# RELAX-NEXT:     R_LARCH_TLS_LE_LO12 a
+# RELAX-NEXT:   pcaddi    $a0, {{[0-9]+}}
+# RELAX-NEXT:     R_LARCH_RELAX a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:     R_LARCH_TLS_GD_PCREL20_S2 a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   pcaddi    $a0, {{[0-9]+}}
+# RELAX-NEXT:     R_LARCH_RELAX a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:     R_LARCH_TLS_LD_PCREL20_S2 a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:   addi.{{[dw]}} $a0, $tp, 0
+# RELAX-NEXT:     R_LARCH_RELAX a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:     R_LARCH_RELAX a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
+# RELAX-NEXT:     R_LARCH_TLS_LE_LO12_R a
+# RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:   nop
 # RELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# RELAX-NEXT:   nop
 # RELAX-NEXT:   ret
 
 # NORELAX:      <_start>:
@@ -45,8 +65,36 @@
 # NORELAX-NEXT:   ld.d      $a0, $a0, 0
 # NORELAX-NEXT:     R_LARCH_GOT_PC_LO12 _start
 # NORELAX-NEXT:     R_LARCH_RELAX *ABS*
-# NORELAX-NEXT:   ret
+# NORELAX-NEXT:   lu12i.w   $a0, 0
+# NORELAX-NEXT:     R_LARCH_TLS_LE_HI20 a
+# NORELAX-NEXT:   ori       $a0, $a0, 0
+# NORELAX-NEXT:     R_LARCH_TLS_LE_LO12 a
+# NORELAX-NEXT:   pcalau12i $a0, 16
+# NORELAX-NEXT:     R_LARCH_TLS_GD_PC_HI20 a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   addi.d    $a0, $a0, 8
+# NORELAX-NEXT:     R_LARCH_GOT_PC_LO12 a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   pcalau12i $a0, 16
+# NORELAX-NEXT:     R_LARCH_TLS_LD_PC_HI20 a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   addi.d    $a0, $a0, 8
+# NORELAX-NEXT:     R_LARCH_GOT_PC_LO12 a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   lu12i.w   $a0, 0
+# NORELAX-NEXT:     R_LARCH_TLS_LE_HI20_R a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   add.d     $a0, $a0, $tp
+# NORELAX-NEXT:     R_LARCH_TLS_LE_ADD_R a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   addi.d    $a0, $a0, 0
+# NORELAX-NEXT:     R_LARCH_TLS_LE_LO12_R a
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   nop
 # NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   nop
+# NORELAX-NEXT:   ret
 
 # CHECKR:      <_start>:
 # CHECKR-NEXT:   pcalau12i $a0, 0
@@ -61,15 +109,69 @@
 # CHECKR-NEXT:   ld.d      $a0, $a0, 0
 # CHECKR-NEXT:     R_LARCH_GOT_PC_LO12 _start
 # CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   lu12i.w   $a0, 0
+# CHECKR-NEXT:     R_LARCH_TLS_LE_HI20 a
+# CHECKR-NEXT:   ori       $a0, $a0, 0
+# CHECKR-NEXT:     R_LARCH_TLS_LE_LO12 a
+# CHECKR-NEXT:   pcalau12i $a0, 0
+# CHECKR-NEXT:     R_LARCH_TLS_GD_PC_HI20 a
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   addi.d    $a0, $a0, 0
+# CHECKR-NEXT:     R_LARCH_GOT_PC_LO12 a
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   pcalau12i $a0, 0
+# CHECKR-NEXT:     R_LARCH_TLS_LD_PC_HI20 a
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   addi.d    $a0, $a0, 0
+# CHECKR-NEXT:     R_LARCH_GOT_PC_LO12 a
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   lu12i.w   $a0, 0
+# CHECKR-NEXT:     R_LARCH_TLS_LE_HI20_R a
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   add.d     $a0, $a0, $tp
+# CHECKR-NEXT:     R_LARCH_TLS_LE_ADD_R a
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   addi.d    $a0, $a0, 0
+# CHECKR-NEXT:     R_LARCH_TLS_LE_LO12_R a
+# 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
 
+.macro add dst, src1, src2, src3
+.ifdef ELF32
+add.w \dst, \src1, \src2, \src3
+.else
+add.d \dst, \src1, \src2, \src3
+.endif
+.endm
+.macro addi dst, src1, src2
+.ifdef ELF32
+addi.w \dst, \src1, \src2
+.else
+addi.d \dst, \src1, \src2
+.endif
+.endm
+
 .global _start
 _start:
   la.pcrel $a0, _start
   la.got   $a0, _start
+
+  la.tls.le $a0, a  # without R_LARCH_RELAX reloaction
+  la.tls.gd $a0, a
+  la.tls.ld $a0, a
+
+  lu12i.w $a0, %le_hi20_r(a)
+  add $a0, $a0, $tp, %le_add_r(a)
+  addi $a0, $a0, %le_lo12_r(a)
+
   .p2align 4
   ret
+
+.section .tbss,"awT", at nobits
+.globl a
+a:
+.zero 4
diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s
new file mode 100644
index 0000000000000..8f9b6e1092a62
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-tls-le.s
@@ -0,0 +1,115 @@
+# REQUIRES: loongarch
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax --defsym ELF32=1 %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
+
+# RUN: ld.lld %t.32.o -o %t.32
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s
+
+# RUN: ld.lld %t.64.o -o %t.64
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s
+
+# RELAX32-LABEL: <_start>:
+## .LANCHOR0 at tprel = 8
+# RELAX32-NEXT:    addi.w  $a0, $tp, 8 
+# RELAX32-NEXT:    ld.w    $a1, $a0, 0
+# RELAX32-NEXT:    ld.w    $a2, $tp, 8
+## .a at tprel - 4 = 0x7fc
+# RELAX32-NEXT:    addi.w  $a1, $zero, 1
+# RELAX32-NEXT:    addi.w $a1, $a1, 2
+# RELAX32-NEXT:    st.w   $a1, $tp, 2044
+## .a at tprel = 0x800
+# RELAX32-NEXT:    lu12i.w $a0, 1
+# RELAX32-NEXT:    add.w   $a0, $a0, $tp
+# RELAX32-NEXT:    addi.w  $a0, $a0, -2048
+
+# RELAX64-LABEL: <_start>:
+## .LANCHOR0 at tprel = 8
+# RELAX64-NEXT:    addi.d  $a0, $tp, 8 
+# RELAX64-NEXT:    ld.d    $a1, $a0, 0
+# RELAX64-NEXT:    ld.d    $a2, $tp, 8
+## .a at tprel - 4 = 0x7fc
+# RELAX64-NEXT:    addi.d  $a1, $zero, 1
+# RELAX64-NEXT:    addi.d $a1, $a1, 2
+# RELAX64-NEXT:    st.d   $a1, $tp, 2044
+## .a at tprel = 0x800
+# RELAX64-NEXT:    lu12i.w $a0, 1
+# RELAX64-NEXT:    add.d   $a0, $a0, $tp
+# RELAX64-NEXT:    addi.d  $a0, $a0, -2048
+
+.macro add dst, src1, src2, src3
+.ifdef ELF32
+add.w \dst, \src1, \src2, \src3
+.else
+add.d \dst, \src1, \src2, \src3
+.endif
+.endm
+.macro inst op dst, src1, src2
+.ifdef ELF32
+  .ifc      \op, addi
+    addi.w  \dst, \src1, \src2
+  .else;    .ifc   \op, ld
+    ld.w    \dst, \src1, \src2
+  .else;    .ifc   \op, st
+    st.w    \dst, \src1, \src2
+  .else;    .ifc   \op, ldptr
+    ldptr.w \dst, \src1, \src2
+  .else
+    .error "Unknown op in ELF32 mode"
+  .endif; .endif; .endif; .endif
+.else
+  .ifc      \op, addi
+    addi.d  \dst, \src1, \src2
+  .else;    .ifc   \op, ld
+    ld.d    \dst, \src1, \src2
+  .else;    .ifc   \op, st
+    st.d    \dst, \src1, \src2
+  .else;    .ifc   \op, ldptr
+    ldptr.d \dst, \src1, \src2
+  .else
+    .error "Unknown op in ELF64 mode"
+  .endif; .endif; .endif; .endif
+.endif
+.endm
+
+.macro addi dst, src1, src2
+inst addi \dst, \src1, \src2
+.endm
+.macro ld dst, src1, src2
+inst ld \dst, \src1, \src2
+.endm
+.macro st dst, src1, src2
+inst st \dst, \src1, \src2
+.endm
+.macro ldptr dst, src1, src2
+inst ldptr \dst, \src1, \src2
+.endm
+
+_start:
+## Test instructions not in pairs.
+lu12i.w $a0, %le_hi20_r(.LANCHOR0)
+add $a0, $a0, $tp, %le_add_r(.LANCHOR0)
+addi $a0, $a0, %le_lo12_r(.LANCHOR0)
+ld $a1, $a0, 0
+ld $a2, $a0, %le_lo12_r(.LANCHOR0)
+
+## hi20(a-4) = hi20(0x7fc) = 0. relaxable
+## Test non-adjacent instructions.
+lu12i.w $a0, %le_hi20_r(a-4)
+addi $a1, $zero, 0x1
+add $a0, $a0, $tp, %le_add_r(a-4)
+addi $a1, $a1, 0x2
+st $a1, $a0, %le_lo12_r(a-4)
+
+## hi20(a) = hi20(0x800) = 1. not relaxable
+lu12i.w $a0, %le_hi20_r(a)
+add $a0, $a0, $tp, %le_add_r(a)
+addi $a0, $a0, %le_lo12_r(a)
+
+.section .tbss,"awT", at nobits
+.space 8
+.LANCHOR0:
+.space 0x800-8
+.globl a
+a:
+.zero 4

>From b57c40e275dc0977e002e68834c2b40fa030d9fc Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Thu, 16 Jan 2025 22:08:02 +0800
Subject: [PATCH 14/20] Modify test. Add --relax option.

---
 lld/test/ELF/loongarch-relax-tls-le.s | 4 ++--
 lld/test/ELF/loongarch-tls-gd.s       | 4 ++--
 lld/test/ELF/loongarch-tls-ld.s       | 8 ++++----
 lld/test/ELF/loongarch-tls-le.s       | 4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s
index 8f9b6e1092a62..b55f284f32cb8 100644
--- a/lld/test/ELF/loongarch-relax-tls-le.s
+++ b/lld/test/ELF/loongarch-relax-tls-le.s
@@ -3,10 +3,10 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax --defsym ELF32=1 %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
 
-# RUN: ld.lld %t.32.o -o %t.32
+# RUN: ld.lld --relax %t.32.o -o %t.32
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s
 
-# RUN: ld.lld %t.64.o -o %t.64
+# RUN: ld.lld --relax %t.64.o -o %t.64
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s
 
 # RELAX32-LABEL: <_start>:
diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s
index 27d9fdb7ee701..4cfed41d70f38 100644
--- a/lld/test/ELF/loongarch-tls-gd.s
+++ b/lld/test/ELF/loongarch-tls-gd.s
@@ -20,7 +20,7 @@
 # RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so
 # RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s
-# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so
+# RUN: ld.lld --relax -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so
 # RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s
 
@@ -41,7 +41,7 @@
 # RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so
 # RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s
-# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so
+# RUN: ld.lld --relax -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so
 # RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s
 
diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s
index 27adb1e17702a..6cf6fa92939d5 100644
--- a/lld/test/ELF/loongarch-tls-ld.s
+++ b/lld/test/ELF/loongarch-tls-ld.s
@@ -17,7 +17,7 @@
 # RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s
 # RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s
-# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so
+# RUN: ld.lld --relax -shared %t/a.32.relax.o -o %t/ld.32.relax.so
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s
 
 ## LA32 LD -> LE
@@ -25,7 +25,7 @@
 # RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s
 # RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s
-# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax
+# RUN: ld.lld --relax %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax
 # RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s
 
@@ -34,7 +34,7 @@
 # RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s
 # RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s
-# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so
+# RUN: ld.lld --relax -shared %t/a.64.relax.o -o %t/ld.64.relax.so
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s
 
 ## LA64 LD -> LE
@@ -42,7 +42,7 @@
 # RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s
 # RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s
-# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax
+# RUN: ld.lld --relax %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax
 # RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s
 
diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s
index 981baa6fd726f..bc55e08591d28 100644
--- a/lld/test/ELF/loongarch-tls-le.s
+++ b/lld/test/ELF/loongarch-tls-le.s
@@ -8,12 +8,12 @@
 # RUN: ld.lld %t.32.o -o %t.32
 # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s
-# RUN: ld.lld %t.32.relax.o -o %t.32.relax
+# RUN: ld.lld --relax %t.32.relax.o -o %t.32.relax
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s
 
 # RUN: ld.lld %t.64.o -o %t.64
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s
-# RUN: ld.lld %t.64.relax.o -o %t.64.relax
+# RUN: ld.lld --relax %t.64.relax.o -o %t.64.relax
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s
 
 # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:

>From 924d511235d2a06edd816360b54eebc7599423c3 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 14 Feb 2025 09:31:10 +0800
Subject: [PATCH 15/20] Fixes for reviews.

---
 lld/ELF/Arch/LoongArch.cpp                    | 14 +++++-----
 lld/test/ELF/loongarch-relax-align.s          |  8 +++---
 lld/test/ELF/loongarch-relax-emit-relocs.s    |  6 ++--
 ...loongarch-relax-pc-hi20-lo12-got-symbols.s | 28 +++++++++----------
 lld/test/ELF/loongarch-relax-pc-hi20-lo12.s   | 12 ++++----
 5 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index b999e7fd27ae9..dbf024eadf100 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -790,23 +790,23 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
        (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section)))
     return;
 
-  uint64_t symBase = 0;
+  uint64_t dest = 0;
   if (rHi20.expr == RE_LOONGARCH_PLT_PAGE_PC)
-    symBase = rHi20.sym->getPltVA(ctx);
+    dest = rHi20.sym->getPltVA(ctx);
   else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
            rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
-    symBase = rHi20.sym->getVA(ctx);
+    dest = rHi20.sym->getVA(ctx);
   else {
     Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr ("
              << rHi20.expr << ") against symbol " << rHi20.sym
              << "in relaxPCHi20Lo12";
     return;
   }
-  const uint64_t symLocal = symBase + rHi20.addend;
+  dest += rHi20.addend;
 
-  const int64_t distance = symLocal - loc;
-  // Check if the distance aligns 4 bytes or exceeds the range of pcaddi.
-  if ((distance & 0x3) != 0 || !isInt<22>(distance))
+  const int64_t displace = dest - loc;
+  // Check if the displace aligns 4 bytes or exceeds the range of pcaddi.
+  if ((displace & 0x3) != 0 || !isInt<22>(displace))
     return;
 
   // Note: If we can ensure that the .o files generated by LLVM only contain
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index 66a8ed3abf71e..79353f2a3be47 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -2,8 +2,8 @@
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.32.o -o %t.32
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.64.o -o %t.64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32
+# 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 --no-relax %t.32.o -o %t.32n
 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.64.o -o %t.64n
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s
@@ -13,13 +13,13 @@
 
 ## 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 --relax %t.o64.o -o %t.o64
+# 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 --no-relax %t.o64.o -o %t.o64n
 # RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s
 
 ## -r keeps section contents unchanged.
-# RUN: ld.lld -r --relax %t.64.o -o %t.64.r
+# 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
 
 # NOOLD: {{0*}}10000 l .text  {{0*}}00 .Lalign_symbol
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index a02cd272aba5b..7031ffd9f6686 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -3,13 +3,13 @@
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32
-# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
 # 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 --relax -r %t.64.o -o %t.64.r
+# RUN: ld.lld -r %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
 
 ## --no-relax should keep original relocations.
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
index 0a75d2289209c..f37de8e3b7c83 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
@@ -9,45 +9,45 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o
 
-# RUN: ld.lld --shared --relax -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
-# RUN: ld.lld --shared --relax -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
+# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
+# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s
 
-# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
-# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
+# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
+# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s
 # RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s
 
 
 ## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied.
-LIB:      pcaddi      $a0, {{[0-9]+}}
+LIB:      pcaddi      $a0, [[#]]
 ## Symbol 'global_sym' is preemptible, no relaxations should be applied.
 LIB-NEXT: pcalau12i   $a1, 4
-LIB-NEXT: ld.{{[wd]}} $a1, $a1, {{[0-9]+}}
+LIB-NEXT: ld.{{[wd]}} $a1, $a1, [[#]]
 ## Symbol 'undefined_sym' is undefined, no relaxations should be applied.
 LIB-NEXT: pcalau12i   $a2, 4
-LIB-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}}
+LIB-NEXT: ld.{{[wd]}} $a2, $a2, [[#]]
 ## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied.
 LIB-NEXT: pcalau12i   $a3, 4
-LIB-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}}
+LIB-NEXT: ld.{{[wd]}} $a3, $a3, [[#]]
 ## Symbol 'abs_sym' is absolute, no relaxations should be applied.
 LIB-NEXT: pcalau12i   $a4, 4
-LIB-NEXT: ld.{{[wd]}} $a4, $a4, {{[0-9]+}}
+LIB-NEXT: ld.{{[wd]}} $a4, $a4, [[#]]
 
 
 ## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied.
-EXE:      pcaddi      $a0, {{[0-9]+}}
+EXE:      pcaddi      $a0, [[#]]
 ## Symbol 'global_sym' is nonpreemptible, the relaxation should be applied.
-EXE-NEXT: pcaddi      $a1, {{[0-9]+}}
+EXE-NEXT: pcaddi      $a1, [[#]]
 ## Symbol 'undefined_sym' is undefined, no relaxations should be applied.
 EXE-NEXT: pcalau12i   $a2, 4
-EXE-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}}
+EXE-NEXT: ld.{{[wd]}} $a2, $a2, [[#]]
 ## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied.
 EXE-NEXT: pcalau12i   $a3, 4
-EXE-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}}
+EXE-NEXT: ld.{{[wd]}} $a3, $a3, [[#]]
 ## Symbol 'abs_sym' is absolute, relaxations may be applied in -no-pie mode.
-EXE-NEXT: pcaddi      $a4, -{{[0-9]+}}
+EXE-NEXT: pcaddi      $a4, -[[#]]
 
 
 ## The linker script ensures that .rodata and .text are near (>4M) so that
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index 760fe77d774e3..a417d89e9fa2e 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -3,18 +3,18 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
 
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -o %t.32
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -o %t.64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
 
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -shared -o %t.32s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -shared -o %t.64s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s
 
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.32.o -o %t.32o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.64.o -o %t.64o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o
 # RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s
 # RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s
 

>From b9c2ea1ad26ad6c81213ee9d563bd1448ed4a097 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 14 Feb 2025 09:43:07 +0800
Subject: [PATCH 16/20] Revert "Modify test. Add the option --relax."

This reverts commit f2aae15f701863d03edd32657824a97f66696e8d.
---
 lld/test/ELF/loongarch-relax-call36-2.s      | 6 +++---
 lld/test/ELF/loongarch-relax-call36.s        | 6 +++---
 lld/test/ELF/loongarch-relax-emit-relocs-2.s | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s
index 71650aefe9432..1c216a9bdc35e 100644
--- a/lld/test/ELF/loongarch-relax-call36-2.s
+++ b/lld/test/ELF/loongarch-relax-call36-2.s
@@ -2,14 +2,14 @@
 # RUN: rm -rf %t && split-file %s %t && cd %t
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o
 
-# RUN: ld.lld --relax -T lds a.o -o a
+# RUN: ld.lld -T lds a.o -o a
 # RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s --check-prefixes=RELAX,RELAX-MID
 
 ## Unsure whether this needs a diagnostic. GNU ld allows this.
-# RUN: ld.lld --relax -T lds -pie a.o -o a.pie
+# RUN: ld.lld -T lds -pie a.o -o a.pie
 # RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s --check-prefixes=RELAX,RELAX-MID
 
-# RUN: ld.lld --relax -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
+# RUN: ld.lld -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
 # RUN: llvm-objdump -d --no-show-raw-insn a.ifunc-noplt | FileCheck %s --check-prefixes=RELAX,NORELAX-MID
 
 # RELAX-LABEL:  <_start>:
diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s
index bda0c4f05da91..57ed214c9eb2e 100644
--- a/lld/test/ELF/loongarch-relax-call36.s
+++ b/lld/test/ELF/loongarch-relax-call36.s
@@ -4,12 +4,12 @@
 
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o
-# RUN: ld.lld --relax -shared -soname=b.so b.64.o -o b.64.so
-# RUN: ld.lld --relax -T lds a.64.o b.64.so -o 64
+# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so
+# RUN: ld.lld -T lds a.64.o b.64.so -o 64
 # RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX
 
 ## --no-relax disables relaxation.
-# RUN: ld.lld --no-relax -T lds a.64.o b.64.so -o 64.norelax
+# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax
 # RUN: llvm-objdump -td --no-show-raw-insn 64.norelax | FileCheck %s --check-prefix=NORELAX
 
 # RELAX:       {{0*}}00010000 g       .text  {{0*}}0000001c _start
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
index eddfc46b1ad08..31cae939eca71 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs-2.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
@@ -3,15 +3,15 @@
 ## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version.
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld --relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
 # RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
 
 ## -r should keep original relocations.
-# RUN: ld.lld --relax -r %t.64.o -o %t.64.r
+# RUN: ld.lld -r %t.64.o -o %t.64.r
 # RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
 
 ## --no-relax should keep original relocations.
-# RUN: ld.lld --no-relax -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64.norelax
+# 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
 
 # RELAX:      00010000 <_start>:

>From 11018299e150c7c6f20fc47ff2673d8f963eb199 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 14 Feb 2025 11:23:30 +0800
Subject: [PATCH 17/20] Fixes for reviews.

---
 lld/ELF/Arch/LoongArch.cpp                   |  8 +--
 lld/test/ELF/loongarch-relax-call36-2.s      |  2 +
 lld/test/ELF/loongarch-relax-call36.s        |  1 +
 lld/test/ELF/loongarch-relax-emit-relocs-2.s | 61 --------------------
 lld/test/ELF/loongarch-relax-emit-relocs.s   | 43 +++++++++++---
 5 files changed, 43 insertions(+), 72 deletions(-)
 delete mode 100644 lld/test/ELF/loongarch-relax-emit-relocs-2.s

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 0aa0cf5b657a0..c1e2229c3f9a7 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -840,13 +840,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
 //   b/bl foo
 static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
                         uint64_t loc, Relocation &r, uint32_t &remove) {
-  const uint64_t symLocal =
+  const uint64_t dest =
       (r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) +
       r.addend;
 
-  const int64_t distance = symLocal - loc;
-  // Check if the distance aligns 4 bytes or exceeds the range of b[l].
-  if ((distance & 0x3) != 0 || !isInt<28>(distance))
+  const int64_t displace = dest - loc;
+  // Check if the displace aligns 4 bytes or exceeds the range of b[l].
+  if ((displace & 0x3) != 0 || !isInt<28>(displace))
     return;
 
   const uint32_t nextInsn = read32le(sec.content().data() + r.offset + 4);
diff --git a/lld/test/ELF/loongarch-relax-call36-2.s b/lld/test/ELF/loongarch-relax-call36-2.s
index 1c216a9bdc35e..482eed2ebd111 100644
--- a/lld/test/ELF/loongarch-relax-call36-2.s
+++ b/lld/test/ELF/loongarch-relax-call36-2.s
@@ -1,4 +1,6 @@
 # REQUIRES: loongarch
+## Relax R_LARCH_CALL36. This test tests boundary cases and some special symbols.
+
 # RUN: rm -rf %t && split-file %s %t && cd %t
 # RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o
 
diff --git a/lld/test/ELF/loongarch-relax-call36.s b/lld/test/ELF/loongarch-relax-call36.s
index 57ed214c9eb2e..0f0ba26b15f30 100644
--- a/lld/test/ELF/loongarch-relax-call36.s
+++ b/lld/test/ELF/loongarch-relax-call36.s
@@ -1,4 +1,5 @@
 # REQUIRES: loongarch
+## Relax R_LARCH_CALL36, which involves the macro instructions call36/tail36.
 
 # RUN: rm -rf %t && split-file %s %t && cd %t
 
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs-2.s b/lld/test/ELF/loongarch-relax-emit-relocs-2.s
deleted file mode 100644
index 31cae939eca71..0000000000000
--- a/lld/test/ELF/loongarch-relax-emit-relocs-2.s
+++ /dev/null
@@ -1,61 +0,0 @@
-# REQUIRES: loongarch
-## Test that we can handle --emit-relocs while relaxing.
-## Call36 and tail36 need LA64 basic integer, so they donot have 32-bit version.
-
-# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
-# 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=CHECKR
-
-## --no-relax should keep original relocations.
-# 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
-
-# RELAX:      00010000 <_start>:
-# RELAX-NEXT:   bl  0
-# RELAX-NEXT:     R_LARCH_B26 _start
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   b   -4
-# RELAX-NEXT:     R_LARCH_B26 _start
-# RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   nop
-# RELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# RELAX-NEXT:   nop
-# RELAX-NEXT:   ret
-
-# CHECKR:      <_start>:
-# CHECKR-NEXT:   pcaddu18i $ra, 0
-# CHECKR-NEXT:     R_LARCH_CALL36 _start
-# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
-# CHECKR-NEXT:   jirl   $ra, $ra, 0
-# CHECKR-NEXT:   pcaddu18i $t0, 0
-# CHECKR-NEXT:     R_LARCH_CALL36 _start
-# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
-# CHECKR-NEXT:   jr     $t0
-# CHECKR-NEXT:   nop
-# CHECKR-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# CHECKR-NEXT:   nop
-# CHECKR-NEXT:   nop
-# CHECKR-NEXT:   ret
-
-# NORELAX:      <_start>:
-# NORELAX-NEXT:   pcaddu18i $ra, 0
-# NORELAX-NEXT:     R_LARCH_CALL36 _start
-# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
-# NORELAX-NEXT:   jirl   $ra, $ra, 0
-# NORELAX-NEXT:   pcaddu18i $t0, 0
-# NORELAX-NEXT:     R_LARCH_CALL36 _start
-# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
-# NORELAX-NEXT:   jirl $zero, $t0, -8
-# NORELAX-NEXT:   ret
-# NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-
-.global _start
-_start:
-  call36 _start
-  tail36 $t0, _start
-  .p2align 4
-  ret
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index a02cd272aba5b..d7f444470f0f9 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -2,11 +2,11 @@
 ## Test that we can handle --emit-relocs while relaxing.
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
-# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax --defsym ELF64=1 %s -o %t.64.o
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64
-# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
-# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
+# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefixes=RELAX,RELAX32
+# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefixes=RELAX,RELAX64
 
 ## -r should keep original relocations.
 # RUN: ld.lld --relax -r %t.64.o -o %t.64.r
@@ -27,10 +27,19 @@
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   nop
-# RELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
-# RELAX-NEXT:   nop
-# RELAX-NEXT:   ret
+# RELAX32-NEXT:  nop
+# RELAX32-NEXT:    R_LARCH_ALIGN *ABS*+0xc
+# RELAX32-NEXT:  nop
+# RELAX32-NEXT:  ret
+
+# RELAX64-NEXT:  bl  -8
+# RELAX64-NEXT:    R_LARCH_B26 _start
+# RELAX64-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:  b   -12
+# RELAX64-NEXT:    R_LARCH_B26 _start
+# RELAX64-NEXT:    R_LARCH_RELAX *ABS*
+# RELAX64-NEXT:  ret
+# RELAX64-NEXT:    R_LARCH_ALIGN *ABS*+0xc
 
 # NORELAX:      <_start>:
 # NORELAX-NEXT:   pcalau12i $a0, 0
@@ -45,6 +54,14 @@
 # NORELAX-NEXT:   ld.d      $a0, $a0, 0
 # NORELAX-NEXT:     R_LARCH_GOT_PC_LO12 _start
 # NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   pcaddu18i $ra, 0
+# NORELAX-NEXT:     R_LARCH_CALL36 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   jirl   $ra, $ra, -16
+# NORELAX-NEXT:   pcaddu18i $a0, 0
+# NORELAX-NEXT:     R_LARCH_CALL36 _start
+# NORELAX-NEXT:     R_LARCH_RELAX *ABS*
+# NORELAX-NEXT:   jirl $zero, $a0, -24
 # NORELAX-NEXT:   ret
 # NORELAX-NEXT:     R_LARCH_ALIGN *ABS*+0xc
 
@@ -61,6 +78,14 @@
 # CHECKR-NEXT:   ld.d      $a0, $a0, 0
 # CHECKR-NEXT:     R_LARCH_GOT_PC_LO12 _start
 # CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   pcaddu18i $ra, 0
+# CHECKR-NEXT:     R_LARCH_CALL36 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   jirl   $ra, $ra, 0
+# CHECKR-NEXT:   pcaddu18i $a0, 0
+# CHECKR-NEXT:     R_LARCH_CALL36 _start
+# CHECKR-NEXT:     R_LARCH_RELAX *ABS*
+# CHECKR-NEXT:   jr     $a0
 # CHECKR-NEXT:   nop
 # CHECKR-NEXT:     R_LARCH_ALIGN *ABS*+0xc
 # CHECKR-NEXT:   nop
@@ -71,5 +96,9 @@
 _start:
   la.pcrel $a0, _start
   la.got   $a0, _start
+.ifdef ELF64
+  call36 _start
+  tail36 $a0, _start
+.endif
   .p2align 4
   ret

>From 1192441fd76a2c3bd407fa720b1d0d56e6b3f498 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 14 Feb 2025 14:11:17 +0800
Subject: [PATCH 18/20] Revert "Modify test. Add --relax option."

This reverts commit b57c40e275dc0977e002e68834c2b40fa030d9fc.
---
 lld/test/ELF/loongarch-relax-tls-le.s | 4 ++--
 lld/test/ELF/loongarch-tls-gd.s       | 4 ++--
 lld/test/ELF/loongarch-tls-ld.s       | 8 ++++----
 lld/test/ELF/loongarch-tls-le.s       | 4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s
index b55f284f32cb8..8f9b6e1092a62 100644
--- a/lld/test/ELF/loongarch-relax-tls-le.s
+++ b/lld/test/ELF/loongarch-relax-tls-le.s
@@ -3,10 +3,10 @@
 # RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax --defsym ELF32=1 %s -o %t.32.o
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
 
-# RUN: ld.lld --relax %t.32.o -o %t.32
+# RUN: ld.lld %t.32.o -o %t.32
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s
 
-# RUN: ld.lld --relax %t.64.o -o %t.64
+# RUN: ld.lld %t.64.o -o %t.64
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s
 
 # RELAX32-LABEL: <_start>:
diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s
index 4cfed41d70f38..27d9fdb7ee701 100644
--- a/lld/test/ELF/loongarch-tls-gd.s
+++ b/lld/test/ELF/loongarch-tls-gd.s
@@ -20,7 +20,7 @@
 # RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so
 # RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s
-# RUN: ld.lld --relax -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so
+# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so
 # RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s
 
@@ -41,7 +41,7 @@
 # RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so
 # RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s
-# RUN: ld.lld --relax -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so
+# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so
 # RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s
 
diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s
index 6cf6fa92939d5..27adb1e17702a 100644
--- a/lld/test/ELF/loongarch-tls-ld.s
+++ b/lld/test/ELF/loongarch-tls-ld.s
@@ -17,7 +17,7 @@
 # RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s
 # RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s
-# RUN: ld.lld --relax -shared %t/a.32.relax.o -o %t/ld.32.relax.so
+# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s
 
 ## LA32 LD -> LE
@@ -25,7 +25,7 @@
 # RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s
 # RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s
-# RUN: ld.lld --relax %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax
+# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax
 # RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s
 
@@ -34,7 +34,7 @@
 # RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s
 # RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s
-# RUN: ld.lld --relax -shared %t/a.64.relax.o -o %t/ld.64.relax.so
+# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so
 # RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s
 
 ## LA64 LD -> LE
@@ -42,7 +42,7 @@
 # RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s
 # RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s
-# RUN: ld.lld --relax %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax
+# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax
 # RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s
 
diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s
index bc55e08591d28..981baa6fd726f 100644
--- a/lld/test/ELF/loongarch-tls-le.s
+++ b/lld/test/ELF/loongarch-tls-le.s
@@ -8,12 +8,12 @@
 # RUN: ld.lld %t.32.o -o %t.32
 # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s
-# RUN: ld.lld --relax %t.32.relax.o -o %t.32.relax
+# RUN: ld.lld %t.32.relax.o -o %t.32.relax
 # RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s
 
 # RUN: ld.lld %t.64.o -o %t.64
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s
-# RUN: ld.lld --relax %t.64.relax.o -o %t.64.relax
+# RUN: ld.lld %t.64.relax.o -o %t.64.relax
 # RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s
 
 # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:

>From e627784a042eb02a4b26eca40af0b9f2d1bb4f56 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 14 Feb 2025 14:18:29 +0800
Subject: [PATCH 19/20] Remove unnecessary spaces.

---
 lld/test/ELF/loongarch-relax-emit-relocs.s | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index df2c713855a26..0f4ca2ce03657 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -17,12 +17,12 @@
 # RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
 
 # RELAX:      00010000 <_start>:
-# RELAX-NEXT:   pcaddi    $a0, 0
+# RELAX-NEXT:   pcaddi $a0, 0
 # RELAX-NEXT:     R_LARCH_RELAX _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
-# RELAX-NEXT:   pcaddi    $a0, -1
+# RELAX-NEXT:   pcaddi $a0, -1
 # RELAX-NEXT:     R_LARCH_RELAX _start
 # RELAX-NEXT:     R_LARCH_RELAX *ABS*
 # RELAX-NEXT:     R_LARCH_PCREL20_S2 _start
@@ -191,7 +191,6 @@ addi.w \dst, \src1, \src2
 _start:
   la.pcrel $a0, _start
   la.got   $a0, _start
-
 .ifdef ELF64
   call36 _start
   tail36 $a0, _start

>From 26c1e0c29bd09e58d80a6d8ef8552cf1c817c0af Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Mon, 17 Feb 2025 11:28:26 +0800
Subject: [PATCH 20/20] Fixes for reviews.

---
 lld/ELF/Arch/LoongArch.cpp            | 17 ++++++----
 lld/test/ELF/loongarch-relax-tls-le.s | 46 +++++++++++++--------------
 2 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 526d8061fec26..709b31ed4e01a 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -154,6 +154,10 @@ static uint32_t setJ20(uint32_t insn, uint32_t imm) {
   return (insn & 0xfe00001f) | (extractBits(imm, 19, 0) << 5);
 }
 
+static uint32_t setJ5(uint32_t insn, uint32_t imm) {
+  return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5);
+}
+
 static uint32_t setK12(uint32_t insn, uint32_t imm) {
   return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
 }
@@ -895,9 +899,7 @@ static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i,
     remove = 4;
     break;
   case R_LARCH_TLS_LE_LO12_R:
-    currInsn =
-        insn(extractBits(currInsn, 31, 22) << 22, getD5(currInsn), R_TP, 0);
-    sec.relaxAux->writes.push_back(currInsn);
+    sec.relaxAux->writes.push_back(setJ5(currInsn, R_TP));
     sec.relaxAux->relocTypes[i] = R_LARCH_TLS_LE_LO12_R;
     break;
   }
@@ -1069,10 +1071,11 @@ void LoongArch::finalizeRelax(int passes) const {
             break;
           case R_LARCH_TLS_GD_PCREL20_S2:
             // Note: R_LARCH_TLS_LD_PCREL20_S2 must also use R_TLSGD_PC instead
-            // of R_TLSLD_PC because the processing of relocation
-            // R_LARCH_TLS_LD_PC_HI20 is the same as R_LARCH_TLS_GD_PC_HI20. If
-            // not, the value obtained from getRelocTargetVA will be unexpected
-            // and lead to error.
+            // of R_TLSLD_PC due to historical reasons. In fact, right now TLSLD
+            // behaves exactly like TLSGD on LoongArch.
+            //
+            // This reason has also been mentioned in mold commit:
+            // https://github.com/rui314/mold/commit/5dfa1cf07c03bd57cb3d493b652ef22441bcd71c
           case R_LARCH_TLS_LD_PCREL20_S2:
             skip = 4;
             write32le(p, aux.writes[writesIdx++]);
diff --git a/lld/test/ELF/loongarch-relax-tls-le.s b/lld/test/ELF/loongarch-relax-tls-le.s
index 8f9b6e1092a62..a91374b6e81a3 100644
--- a/lld/test/ELF/loongarch-relax-tls-le.s
+++ b/lld/test/ELF/loongarch-relax-tls-le.s
@@ -39,9 +39,9 @@
 
 .macro add dst, src1, src2, src3
 .ifdef ELF32
-add.w \dst, \src1, \src2, \src3
+  add.w \dst, \src1, \src2, \src3
 .else
-add.d \dst, \src1, \src2, \src3
+  add.d \dst, \src1, \src2, \src3
 .endif
 .endm
 .macro inst op dst, src1, src2
@@ -73,38 +73,38 @@ add.d \dst, \src1, \src2, \src3
 .endm
 
 .macro addi dst, src1, src2
-inst addi \dst, \src1, \src2
+  inst addi \dst, \src1, \src2
 .endm
 .macro ld dst, src1, src2
-inst ld \dst, \src1, \src2
+  inst ld \dst, \src1, \src2
 .endm
 .macro st dst, src1, src2
-inst st \dst, \src1, \src2
+  inst st \dst, \src1, \src2
 .endm
 .macro ldptr dst, src1, src2
-inst ldptr \dst, \src1, \src2
+  inst ldptr \dst, \src1, \src2
 .endm
 
 _start:
-## Test instructions not in pairs.
-lu12i.w $a0, %le_hi20_r(.LANCHOR0)
-add $a0, $a0, $tp, %le_add_r(.LANCHOR0)
-addi $a0, $a0, %le_lo12_r(.LANCHOR0)
-ld $a1, $a0, 0
-ld $a2, $a0, %le_lo12_r(.LANCHOR0)
+  ## Test instructions not in pairs.
+  lu12i.w $a0, %le_hi20_r(.LANCHOR0)
+  add $a0, $a0, $tp, %le_add_r(.LANCHOR0)
+  addi $a0, $a0, %le_lo12_r(.LANCHOR0)
+  ld $a1, $a0, 0
+  ld $a2, $a0, %le_lo12_r(.LANCHOR0)
 
-## hi20(a-4) = hi20(0x7fc) = 0. relaxable
-## Test non-adjacent instructions.
-lu12i.w $a0, %le_hi20_r(a-4)
-addi $a1, $zero, 0x1
-add $a0, $a0, $tp, %le_add_r(a-4)
-addi $a1, $a1, 0x2
-st $a1, $a0, %le_lo12_r(a-4)
+  ## hi20(a-4) = hi20(0x7fc) = 0. relaxable
+  ## Test non-adjacent instructions.
+  lu12i.w $a0, %le_hi20_r(a-4)
+  addi $a1, $zero, 0x1
+  add $a0, $a0, $tp, %le_add_r(a-4)
+  addi $a1, $a1, 0x2
+  st $a1, $a0, %le_lo12_r(a-4)
 
-## hi20(a) = hi20(0x800) = 1. not relaxable
-lu12i.w $a0, %le_hi20_r(a)
-add $a0, $a0, $tp, %le_add_r(a)
-addi $a0, $a0, %le_lo12_r(a)
+  ## hi20(a) = hi20(0x800) = 1. not relaxable
+  lu12i.w $a0, %le_hi20_r(a)
+  add $a0, $a0, $tp, %le_add_r(a)
+  addi $a0, $a0, %le_lo12_r(a)
 
 .section .tbss,"awT", at nobits
 .space 8



More information about the llvm-commits mailing list