[lld] [llvm] [LoongArch] Add reloc types for LA32R/LA32S (PR #146499)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 1 03:02:20 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: hev (heiher)

<details>
<summary>Changes</summary>

Link: https://github.com/loongson/la-abi-specs/pull/16
Link: https://sourceware.org/pipermail/binutils/2025-April/140730.html

---

Patch is 196.86 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/146499.diff


55 Files Affected:

- (modified) lld/ELF/Arch/LoongArch.cpp (+38) 
- (modified) lld/ELF/InputSection.cpp (+60) 
- (modified) lld/ELF/Relocations.cpp (+1-1) 
- (modified) lld/ELF/Relocations.h (+1) 
- (added) lld/test/ELF/loongarch-call30.s (+64) 
- (modified) lld/test/ELF/loongarch-relax-align.s (+2-2) 
- (modified) lld/test/ELF/loongarch-relax-emit-relocs.s (+1-1) 
- (modified) lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s (+2-2) 
- (modified) lld/test/ELF/loongarch-relax-pc-hi20-lo12.s (+1-1) 
- (modified) lld/test/ELF/loongarch-tls-gd-edge-case.s (+2-2) 
- (modified) lld/test/ELF/loongarch-tls-ie.s (+10-9) 
- (modified) llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def (+11) 
- (modified) llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h (+80-236) 
- (modified) llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp (+313-2) 
- (modified) llvm/lib/ExecutionEngine/JITLink/loongarch.cpp (+6-2) 
- (modified) llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (+156-29) 
- (modified) llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp (+146-59) 
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+14-5) 
- (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp (+34-16) 
- (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (+20-9) 
- (modified) llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp (+21) 
- (modified) llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp (+26-16) 
- (modified) llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (+1-1) 
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h (+6) 
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp (+3) 
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp (+18) 
- (modified) llvm/test/CodeGen/LoongArch/block-address.ll (+7-5) 
- (modified) llvm/test/CodeGen/LoongArch/branch-relaxation-spill-32.ll (+5-4) 
- (modified) llvm/test/CodeGen/LoongArch/branch-relaxation.ll (+3-2) 
- (modified) llvm/test/CodeGen/LoongArch/calling-conv-half.ll (+108-72) 
- (modified) llvm/test/CodeGen/LoongArch/calling-conv-ilp32d.ll (+42-28) 
- (modified) llvm/test/CodeGen/LoongArch/code-models.ll (+149-90) 
- (modified) llvm/test/CodeGen/LoongArch/ctlz-cttz-ctpop.ll (+12-8) 
- (modified) llvm/test/CodeGen/LoongArch/double-imm.ll (+3-2) 
- (modified) llvm/test/CodeGen/LoongArch/float-imm.ll (+3-2) 
- (modified) llvm/test/CodeGen/LoongArch/fsqrt-reciprocal-estimate.ll (+141-124) 
- (modified) llvm/test/CodeGen/LoongArch/global-address.ll (+12-8) 
- (modified) llvm/test/CodeGen/LoongArch/inline-asm-constraint-f.ll (+3-2) 
- (modified) llvm/test/CodeGen/LoongArch/inline-asm-constraint-m.ll (+6-4) 
- (modified) llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll (+6-4) 
- (modified) llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll (+9-6) 
- (modified) llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll (+14-10) 
- (modified) llvm/test/CodeGen/LoongArch/machinelicm-address-pseudos.ll (+9-6) 
- (modified) llvm/test/CodeGen/LoongArch/merge-base-offset.ll (+132-89) 
- (modified) llvm/test/CodeGen/LoongArch/numeric-reg-names.ll (+3-2) 
- (modified) llvm/test/CodeGen/LoongArch/tls-models.ll (+21-14) 
- (modified) llvm/test/CodeGen/LoongArch/unaligned-memcpy-inline.ll (+3-2) 
- (modified) llvm/test/CodeGen/LoongArch/vector-fp-imm.ll (+63-42) 
- (modified) llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_reloc_addsub.s (+5-2) 
- (modified) llvm/test/MC/LoongArch/Basic/Integer/invalid.s (+2-2) 
- (modified) llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.generated.expected (+3-2) 
- (modified) llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/loongarch_generated_funcs.ll.nogenerated.expected (+3-2) 
- (modified) llvm/test/tools/llvm-readobj/ELF/reloc-types-loongarch64.test (+2) 
- (modified) llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp (+8-8) 
- (modified) llvm/unittests/Object/ELFTest.cpp (+2) 


``````````diff
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 3c4ad53af1b51..fa79c8df39f1b 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -161,6 +161,10 @@ static uint32_t setJ5(uint32_t insn, uint32_t imm) {
   return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5);
 }
 
+static uint32_t setK10(uint32_t insn, uint32_t imm) {
+  return (insn & 0xffc003ff) | (extractBits(imm, 9, 0) << 10);
+}
+
 static uint32_t setK12(uint32_t insn, uint32_t imm) {
   return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
 }
@@ -416,6 +420,8 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
     // [1]: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=9f482b73f41a9a1bbfb173aad0733d1c824c788a
     // [2]: https://github.com/loongson/la-abi-specs/pull/3
     return isJirl(read32le(loc)) ? R_PLT : R_ABS;
+  case R_LARCH_PCADD_LO12_I:
+    return RE_LOONGARCH_PC_INDIRECT;
   case R_LARCH_TLS_DTPREL32:
   case R_LARCH_TLS_DTPREL64:
     return R_DTPREL;
@@ -446,10 +452,12 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
   case R_LARCH_32_PCREL:
   case R_LARCH_64_PCREL:
   case R_LARCH_PCREL20_S2:
+  case R_LARCH_PCADD_HI20:
     return R_PC;
   case R_LARCH_B16:
   case R_LARCH_B21:
   case R_LARCH_B26:
+  case R_LARCH_CALL30:
   case R_LARCH_CALL36:
     return R_PLT_PC;
   case R_LARCH_GOT_PC_HI20:
@@ -459,6 +467,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
   case R_LARCH_TLS_IE64_PC_LO20:
   case R_LARCH_TLS_IE64_PC_HI12:
     return RE_LOONGARCH_GOT_PAGE_PC;
+  case R_LARCH_PCADD_GOT_HI20:
+  case R_LARCH_PCADD_TLS_IE_HI20:
+    return R_GOT_PC;
   case R_LARCH_GOT_PC_LO12:
   case R_LARCH_TLS_IE_PC_LO12:
     return RE_LOONGARCH_GOT;
@@ -522,6 +533,7 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
   case R_LARCH_TLS_DESC_LO12:
   case R_LARCH_TLS_DESC64_LO20:
   case R_LARCH_TLS_DESC64_HI12:
+  case R_LARCH_PCADD_TLS_DESC_HI20:
     return R_TLSDESC;
   case R_LARCH_TLS_DESC_CALL:
     return R_TLSDESC_CALL;
@@ -605,6 +617,22 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
     write32le(loc, setD10k16(read32le(loc), val >> 2));
     return;
 
+  case R_LARCH_CALL30: {
+    // This relocation is designed for adjacent pcaddu12i+jirl pairs that
+    // are patched in one time.
+    // The relocation range is [-4G, +4G) (of course must be 4-byte aligned).
+    if ((int64_t)val != llvm::SignExtend64(val, 32))
+      reportRangeError(ctx, loc, rel, Twine(val), llvm::minIntN(32),
+                       llvm::maxIntN(32));
+    checkAlignment(ctx, loc, val, 4, rel);
+    uint32_t hi20 = extractBits(val, 31, 12);
+    // Despite the name, the lower part is actually 12 bits with 4-byte aligned.
+    uint32_t lo10 = extractBits(val, 11, 2);
+    write32le(loc, setJ20(read32le(loc), hi20));
+    write32le(loc + 4, setK10(read32le(loc + 4), lo10));
+    return;
+  }
+
   case R_LARCH_CALL36: {
     // This relocation is designed for adjacent pcaddu18i+jirl pairs that
     // are patched in one time. Because of sign extension of these insns'
@@ -648,6 +676,7 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_TLS_LE_LO12_R:
   case R_LARCH_TLS_DESC_PC_LO12:
   case R_LARCH_TLS_DESC_LO12:
+  case R_LARCH_PCADD_LO12_I:
     write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
     return;
 
@@ -667,6 +696,15 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_TLS_DESC_HI20:
     write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
     return;
+  case R_LARCH_PCADD_HI20:
+  case R_LARCH_PCADD_GOT_HI20:
+  case R_LARCH_PCADD_TLS_IE_HI20:
+  case R_LARCH_PCADD_TLS_DESC_HI20: {
+    uint64_t hi = val + 0x800;
+    checkInt(ctx, loc, SignExtend64(hi, 32) >> 12, 20, rel);
+    write32le(loc, setJ20(read32le(loc), extractBits(hi, 31, 12)));
+    return;
+  }
   case R_LARCH_TLS_LE_HI20_R:
     write32le(loc, setJ20(read32le(loc), extractBits(val + 0x800, 31, 12)));
     return;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index f8786265029e8..777209d5b20cf 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -713,6 +713,61 @@ static Relocation *getRISCVPCRelHi20(Ctx &ctx, const InputSectionBase *loSec,
   return nullptr;
 }
 
+// For RE_LARCH_PC_INDIRECT (R_LARCH_PCADD_LO12_I), the symbol actually
+// points the corresponding R_LARCH_PCADD_*_HI20 relocation, and the target VA
+// is calculated using PCADD_HI20's symbol.
+//
+// This function returns the R_LARCH_PCADD_*_HI20 relocation from the
+// R_LARCH_PCADD_LO12 relocation.
+static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
+                                         const InputSectionBase *loSec,
+                                         const Relocation &loReloc) {
+  int64_t addend = loReloc.addend;
+  Symbol *sym = loReloc.sym;
+
+  const Defined *d = cast<Defined>(sym);
+  if (!d->section) {
+    Err(ctx) << loSec->getLocation(loReloc.offset)
+             << ": R_LARCH_PCADD_LO12 relocation points to an absolute symbol: "
+             << sym->getName();
+    return nullptr;
+  }
+  InputSection *hiSec = cast<InputSection>(d->section);
+
+  if (hiSec != loSec)
+    Err(ctx) << loSec->getLocation(loReloc.offset)
+             << ": R_LARCH_PCADD_LO12 relocation points to a symbol '"
+             << sym->getName() << "' in a different section '" << hiSec->name
+             << "'";
+
+  if (addend != 0)
+    Warn(ctx) << loSec->getLocation(loReloc.offset)
+              << ": non-zero addend in R_LARCH_PCADD_LO12 relocation to "
+              << hiSec->getObjMsg(d->value) << " is ignored";
+
+  // Relocations are sorted by offset, so we can use std::equal_range to do
+  // binary search.
+  Relocation hiReloc;
+  hiReloc.offset = d->value + addend;
+  auto range =
+      std::equal_range(hiSec->relocs().begin(), hiSec->relocs().end(), hiReloc,
+                       [](const Relocation &lhs, const Relocation &rhs) {
+                         return lhs.offset < rhs.offset;
+                       });
+
+  for (auto it = range.first; it != range.second; ++it)
+    if (it->type == R_LARCH_PCADD_HI20 || it->type == R_LARCH_PCADD_GOT_HI20 ||
+        it->type == R_LARCH_PCADD_TLS_IE_HI20 ||
+        it->type == R_LARCH_PCADD_TLS_DESC_HI20)
+      return &*it;
+
+  Err(ctx) << loSec->getLocation(loReloc.offset)
+           << ": R_LARCH_PCADD_LO12 relocation points to "
+           << hiSec->getObjMsg(d->value)
+           << " without an associated R_LARCH_PCADD_HI20 relocation";
+  return nullptr;
+}
+
 // A TLS symbol's virtual address is relative to the TLS segment. Add a
 // target-specific adjustment to produce a thread-pointer-relative offset.
 static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) {
@@ -884,6 +939,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
       return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx));
     return 0;
   }
+  case RE_LOONGARCH_PC_INDIRECT: {
+    if (const Relocation *hiRel = getLoongArchPCAddHi20(ctx, this, r))
+      return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx, a));
+    return 0;
+  }
   case RE_LOONGARCH_PAGE_PC:
     return getLoongArchPageDelta(r.sym->getVA(ctx, a), p, r.type);
   case R_PC:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 43f19186f0981..5b12f40c8d5fc 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -210,7 +210,7 @@ static bool isRelExpr(RelExpr expr) {
   return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
                RE_PPC64_CALL, RE_PPC64_RELAX_TOC, RE_AARCH64_PAGE_PC,
                R_RELAX_GOT_PC, RE_RISCV_PC_INDIRECT, RE_PPC64_RELAX_GOT_PC,
-               RE_LOONGARCH_PAGE_PC>(expr);
+               RE_LOONGARCH_PAGE_PC, RE_LOONGARCH_PC_INDIRECT>(expr);
 }
 
 static RelExpr toPlt(RelExpr expr) {
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index d2a77bc953109..3213c9387606e 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -129,6 +129,7 @@ enum RelExpr {
   // also reused for TLS, making the semantics differ from other architectures.
   RE_LOONGARCH_GOT,
   RE_LOONGARCH_GOT_PAGE_PC,
+  RE_LOONGARCH_PC_INDIRECT,
   RE_LOONGARCH_TLSGD_PAGE_PC,
   RE_LOONGARCH_TLSDESC_PAGE_PC,
 };
diff --git a/lld/test/ELF/loongarch-call30.s b/lld/test/ELF/loongarch-call30.s
new file mode 100644
index 0000000000000..907e8704e908b
--- /dev/null
+++ b/lld/test/ELF/loongarch-call30.s
@@ -0,0 +1,64 @@
+# REQUIRES: loongarch
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %t/a.s -o %t/a.o
+
+# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x21020 -o %t/exe1
+# RUN: llvm-objdump --no-show-raw-insn -d %t/exe1 | FileCheck --match-full-lines %s --check-prefix=EXE1
+## hi20 = target - pc >> 12 = 0x21020 - 0x20010 >> 12 = 1
+## lo12 = target - pc & (1 << 12) - 1 = 0x21020 - 0x20010 & 0xfff = 16
+# EXE1:      20010: pcaddu12i $t0, 1
+# EXE1-NEXT: 20014: jirl $zero, $t0, 16
+
+# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x21820 -o %t/exe2
+# RUN: llvm-objdump --no-show-raw-insn -d %t/exe2 | FileCheck --match-full-lines %s --check-prefix=EXE2
+## hi20 = target - pc >> 12 = 0x21820 - 0x20010 >> 12 = 1
+## lo12 = target - pc & (1 << 12) - 1 = 0x21820 - 0x20010 & 0xfff = 2064
+# EXE2:      20010: pcaddu12i $t0, 1
+# EXE2-NEXT: 20014: jirl $zero, $t0, 2064
+
+# RUN: ld.lld %t/a.o -shared -T %t/a.t -o %t/a.so
+# RUN: llvm-readelf -x .got.plt %t/a.so | FileCheck --check-prefix=GOTPLT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/a.so | FileCheck --check-prefix=SO %s
+## PLT should be present in this case.
+# SO:    Disassembly of section .plt:
+# SO:    <.plt>:
+##       foo at plt:
+# SO:    1234520:  pcaddu12i $t3, 64{{$}}
+# SO-NEXT:         ld.w $t3, $t3, 444{{$}}
+# SO-NEXT:         jirl $t1, $t3, 0
+# SO-NEXT:         nop
+
+# SO:   Disassembly of section .text:
+# SO:   <_start>:
+## hi20 = foo at plt - pc >> 12 = 0x1234520 - 0x1274670 >> 12 = -65
+## lo18 = foo at plt - pc & (1 << 12) - 1 = 0x1234520 - 0x1274670 & 0xfff = 3760
+# SO-NEXT: pcaddu12i $t0, -65{{$}}
+# SO-NEXT: jirl $zero, $t0, 3760{{$}}
+
+# GOTPLT:      section '.got.plt':
+# GOTPLT-NEXT: 0x012746d4 00000000 00000000 00452301
+
+## Impossible case in reality becasue all LoongArch instructions are fixed 4-bytes long.
+# RUN: not ld.lld %t/a.o --section-start=.text=0x20000 --section-start=.sec.foo=0x40001 -o /dev/null 2>&1 | \
+# RUN:   FileCheck -DFILE=%t/a.o --check-prefix=ERROR-ALIGN %s
+# ERROR-ALIGN: error: [[FILE]]:(.text+0x0): improper alignment for relocation R_LARCH_CALL30: 0x20001 is not aligned to 4 bytes
+
+#--- a.t
+SECTIONS {
+ .plt   0x1234500: { *(.plt) }
+ .text  0x1274670: { *(.text) }
+}
+
+#--- a.s
+.text
+.global _start
+_start:
+  .reloc ., R_LARCH_CALL30, foo
+  pcaddu12i $t0, 0
+  jirl      $zero, $t0, 0
+
+.section .sec.foo,"awx"
+.global foo
+foo:
+  ret
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index 79353f2a3be47..b9da1322a8c00 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -1,7 +1,7 @@
 # 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: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s,+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+32s,+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 --no-relax %t.32.o -o %t.32n
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 909b65075a695..6e1e85c004439 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=+32s,+relax %s -o %t.32.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 %t.32.o -o %t.32
 # RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
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 f37de8e3b7c83..fe243397af346 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
@@ -4,9 +4,9 @@
 # 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=loongarch32 -mattr=+32s,+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=loongarch32 -mattr=+32s,+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
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index a417d89e9fa2e..a1d6c0f7eec73 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -1,6 +1,6 @@
 # REQUIRES: loongarch
 
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+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
diff --git a/lld/test/ELF/loongarch-tls-gd-edge-case.s b/lld/test/ELF/loongarch-tls-gd-edge-case.s
index 9f25f10c73b44..cfa65f91aebb8 100644
--- a/lld/test/ELF/loongarch-tls-gd-edge-case.s
+++ b/lld/test/ELF/loongarch-tls-gd-edge-case.s
@@ -24,8 +24,8 @@
 # LA64-REL-NEXT: 00000000000203a8  0000000200000009 R_LARCH_TLS_DTPREL64   0000000000000000 y + 0
 # LA64-REL-NEXT: 00000000000203b0  000000020000000b R_LARCH_TLS_TPREL64    0000000000000000 y + 0
 
-# LA32:      101d4: pcalau12i $a0, 16
-# LA32-NEXT:        ld.w $a0, $a0, 580
+# LA32:      101d4: pcaddu12i $a0, 16
+# LA32-NEXT:        ld.w $a0, $a0, 112
 # LA32-NEXT:        pcalau12i $a1, 16
 # LA32-NEXT:        addi.w $a1, $a1, 572
 
diff --git a/lld/test/ELF/loongarch-tls-ie.s b/lld/test/ELF/loongarch-tls-ie.s
index ddfd9c976cb9b..84e6672e31e05 100644
--- a/lld/test/ELF/loongarch-tls-ie.s
+++ b/lld/test/ELF/loongarch-tls-ie.s
@@ -41,11 +41,11 @@
 ## LA32:
 ## &.got[0] - . = 0x20214 - 0x101a4: 0x10 pages, page offset 0x214
 ## &.got[1] - . = 0x20218 - 0x101b0: 0x10 pages, page offset 0x218
-# IE32:      101a4: pcalau12i $a4, 16
-# IE32-NEXT:        ld.w $a4, $a4, 532
+# IE32:      101a4: pcaddu12i $a4, 16
+# IE32-NEXT:        ld.w $a4, $a4, 112
 # IE32-NEXT:        add.w $a4, $a4, $tp
-# IE32-NEXT: 101b0: pcalau12i $a5, 16
-# IE32-NEXT:        ld.w $a5, $a5, 536
+# IE32:      101b0: pcaddu12i $a5, 16
+# IE32-NEXT:        ld.w $a5, $a5, 104
 # IE32-NEXT:        add.w $a5, $a5, $tp
 
 ## LA64:
@@ -62,15 +62,16 @@
 
 # a at tprel = st_value(a) = 0x8
 # b at tprel = st_value(a) = 0xc
-# LE32-GOT: could not find section '.got'
+# LE32-GOT: section '.got':
+# LE32-GOT-NEXT: 0x0003012c 08000000 0c000000
 # LE64-GOT: could not find section '.got'
 
 ## LA32:
-# LE32:      200d4: nop
-# LE32-NEXT:        ori $a4, $zero, 8
+# LE32:      20114: pcaddu12i $a4, 16
+# LE32-NEXT:        ld.w $a4, $a4, 24
 # LE32-NEXT:        add.w $a4, $a4, $tp
-# LE32-NEXT: 200e0: nop
-# LE32-NEXT:        ori $a5, $zero, 12
+# LE32:      20120: pcaddu12i $a5, 16
+# LE32-NEXT:        ld.w $a5, $a5, 16
 # LE32-NEXT:        add.w $a5, $a5, $tp
 
 ## LA64:
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def
index 4859057abcbb9..ee5f6ed8c89b4 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def
@@ -149,3 +149,14 @@ ELF_RELOC(R_LARCH_TLS_LE_LO12_R,       123)
 ELF_RELOC(R_LARCH_TLS_LD_PCREL20_S2,   124)
 ELF_RELOC(R_LARCH_TLS_GD_PCREL20_S2,   125)
 ELF_RELOC(R_LARCH_TLS_DESC_PCREL20_S2, 126)
+
+// Relocs added in ELF for the LoongArchâ„¢ Architecture v2025????, part of the
+// v2.40 LoongArch ABI specs.
+//
+// Spec addition: https://github.com/loongson/la-abi-specs/pull/16
+ELF_RELOC(R_LARCH_CALL30, 127)
+ELF_RELOC(R_LARCH_PCADD_HI20, 128)
+ELF_RELOC(R_LARCH_PCADD_GOT_HI20, 129)
+ELF_RELOC(R_LARCH_PCADD_TLS_IE_HI20, 130)
+ELF_RELOC(R_LARCH_PCADD_TLS_DESC_HI20, 131)
+ELF_RELOC(R_LARCH_PCADD_LO12_I, 132)
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h b/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h
index 04c5a67ac4fe3..1d9038a6fe2d8 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h
@@ -170,6 +170,30 @@ enum EdgeKind_loongarch : Edge::Kind {
   ///
   PageOffset12,
 
+  /// The upper 20 bits of the offset from the fixup to the target.
+  ///
+  /// Fixup expression:
+  ///   Fixup <- (Target + Addend - Fixup + 0x800) >> 12 : int20
+  ///
+  /// Notes:
+  ///   For PCADDU12I fixups.
+  ///
+  /// Errors:
+  ///   - The result of the fixup expression must fit into an int20 otherwise an
+  ///     out-of-range error will be returned.
+  ///
+  PCAdd20,
+
+  /// The lower 12 bits of the offset from the paired PCADDU12I (the initial
+  /// target) to the final target it points to.
+  ///
+  /// Typically used to fix up ADDI/LD_W/LD_D immediates.
+  ///
+  /// Fixup expression:
+  ///   Fixup <- (FinalTarget - InitialTarget) & 0xfff : int12
+  ///
+  PCAdd12,
+
   /// A GOT entry getter/constructor, transformed to Page20 pointing at the GOT
   /// entry for the original target.
   ///
@@ -206,6 +230,49 @@ enum EdgeKind_loongarch : Edge::Kind {
   ///
   RequestGOTAndTransformToPageOffset12,
 
+  /// A GOT entry getter/constructor, transformed to PCAdd20 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a PCAdd20 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT/PLT builder pass inserted
+  /// by default.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
+  ///
+  RequestGOTAndTransformToPCAdd20,
+
+  /// A 30-bit PC-relative call.
+  ///
+  /// Represents a PC-relative call to a target within [-4G, +4G)
+  /// The target must be 4-byte aligned. For adjacent pcaddu12i+jirl
+  /// instruction pairs.
+  ///
+  /// Fixup expression:
+  ///   Fixup <- (Target - Fixup + Addend) >> 2 : int30
+  ///
+  /// Notes:
+  ///   The '30' in the name refers to the number operand bits and follows the
+  /// naming convention used by the corresponding ELF relocations. Since the low
+  /// two bits must be zero (because of the 4-byte alignment of the target) the
+  /// operand is effectively a signed 32-bit number.
+  ///
+  /// Errors:
+  ///   - The result of the unshifted part of the fixup expression must be
+  ///     4-byte aligned otherwise an alignment error will be returned.
+  ///   - The result of the fixup expression must fit into an int30 otherwise an
+  ///     out-of-range error will be returned.
+  ///
+  Call30PCRel,
+
   /// A 36-bit PC-relative call.
   ///
   /// Represents a PC-relative call to a target within [-128G - 0x20000, +128G
...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/146499


More information about the llvm-commits mailing list