From 8a351f1f2ed593b5e3ddf453d744b9d53908c616 Mon Sep 17 00:00:00 2001
From: Zhaoxin Yang <yangzhaoxin@loongson.cn>
Date: Fri, 11 Apr 2025 16:55:59 +0800
Subject: [PATCH] [lld][LoongArch] Support relaxation during IE to LE
 conversion (#123702)

Complement https://github.com/llvm/llvm-project/pull/123680. When
relaxation enable, remove redundant NOPs.
---
 lld/ELF/Arch/LoongArch.cpp            | 10 +++++++++-
 lld/test/ELF/loongarch-relax-tls-ie.s | 28 ++++++++++++++++++++++++---
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 86f1778112a3..3c4ad53af1b5 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -974,6 +974,11 @@ static bool relax(Ctx &ctx, InputSection &sec) {
       if (relaxable(relocs, i))
         relaxTlsLe(ctx, sec, i, loc, r, remove);
       break;
+    case R_LARCH_TLS_IE_PC_HI20:
+      if (relaxable(relocs, i) && r.expr == R_RELAX_TLS_IE_TO_LE &&
+          isUInt<12>(r.sym->getVA(ctx, r.addend)))
+        remove = 4;
+      break;
     }
 
     // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -1048,7 +1053,7 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
     secAddr += s->outSecOff;
   else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
     secAddr += ehIn->getParent()->outSecOff;
-  bool isExtreme = false;
+  bool isExtreme = false, isRelax = false;
   const MutableArrayRef<Relocation> relocs = sec.relocs();
   for (size_t i = 0, size = relocs.size(); i != size; ++i) {
     Relocation &rel = relocs[i];
@@ -1077,6 +1082,9 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
                            bits);
         relocateNoSym(loc, rel.type, val);
       } else {
+        isRelax = relaxable(relocs, i);
+        if (isRelax && rel.type == R_LARCH_TLS_IE_PC_HI20 && isUInt<12>(val))
+          continue;
         tlsIeToLe(loc, rel, val);
       }
       continue;
diff --git a/lld/test/ELF/loongarch-relax-tls-ie.s b/lld/test/ELF/loongarch-relax-tls-ie.s
index 82e609d005af..34359862ae6e 100644
--- a/lld/test/ELF/loongarch-relax-tls-ie.s
+++ b/lld/test/ELF/loongarch-relax-tls-ie.s
@@ -3,11 +3,10 @@
 
 # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.o
 
-## FIXME: IE relaxation has not yet been implemented.
-## --relax/--no-relax has the same result. Also check --emit-relocs.
+## Also check --emit-relocs.
 # RUN: ld.lld --emit-relocs %t.o -o %t
 # RUN: llvm-readelf -x .got %t 2>&1 | FileCheck --check-prefix=LE-GOT %s
-# RUN: llvm-objdump -dr --no-show-raw-insn %t | FileCheck --check-prefixes=LE %s
+# RUN: llvm-objdump -dr --no-show-raw-insn %t | FileCheck --check-prefixes=LER %s
 
 # RUN: ld.lld --emit-relocs --no-relax %t.o -o %t.norelax
 # RUN: llvm-readelf -x .got %t.norelax 2>&1 | FileCheck --check-prefix=LE-GOT %s
@@ -42,6 +41,29 @@
 # LE-NEXT:        add.d   $a2, $a2, $tp
 # LE-NEXT:        add.d   $a3, $a3, $tp
 
+# LER:      20158: ori     $a0, $zero, 4095
+# LER-NEXT:          R_LARCH_TLS_IE_PC_HI20 a
+# LER-NEXT:          R_LARCH_RELAX   *ABS*
+# LER-NEXT:          R_LARCH_TLS_IE_PC_LO12 a
+# LER-NEXT:          R_LARCH_RELAX   *ABS*
+# LER-NEXT:        add.d   $a0, $a0, $tp
+# LER-NEXT: 20160: lu12i.w $a1, 1
+# LER-NEXT:          R_LARCH_TLS_IE_PC_HI20 b
+# LER-NEXT:        ori     $a1, $a1, 0
+# LER-NEXT:          R_LARCH_TLS_IE_PC_LO12 b
+# LER-NEXT:        add.d   $a1, $a1, $tp
+# LER-NEXT: 2016c: lu12i.w $a3, 1
+# LER-NEXT:          R_LARCH_TLS_IE_PC_HI20 a
+# LER-NEXT:          R_LARCH_RELAX   *ABS*
+# LER-NEXT:          R_LARCH_TLS_IE_PC_HI20 b
+# LER-NEXT:          R_LARCH_RELAX   *ABS*
+# LER-NEXT:        ori     $a2, $zero, 4095
+# LER-NEXT:          R_LARCH_TLS_IE_PC_LO12 a
+# LER-NEXT:        ori     $a3, $a3, 0
+# LER-NEXT:          R_LARCH_TLS_IE_PC_LO12 b
+# LER-NEXT:        add.d   $a2, $a2, $tp
+# LER-NEXT:        add.d   $a3, $a3, $tp
+
 la.tls.ie $a0, a    # relax
 add.d $a0, $a0, $tp