Skip to content

Conversation

@heiher
Copy link
Member

@heiher heiher commented Dec 17, 2025

This patch introduces the relocation types added in la-abi-sepcs v2.50, enabling support for LoongArch32 Reduced and Standard variants.

Link: loongson/la-abi-specs#16
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html
Link: https://gcc.gnu.org/pipermail/gcc-patches/2025-December/703312.html

This patch introduces the relocation types added in la-abi-sepcs v2.50, enabling support for LoongArch32 Reduced and Standard variants. Link: loongson/la-abi-specs#16 Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html Link: https://gcc.gnu.org/pipermail/gcc-patches/2025-December/703312.html
@llvmbot
Copy link
Member

llvmbot commented Dec 17, 2025

@llvm/pr-subscribers-lld-elf
@llvm/pr-subscribers-backend-loongarch

@llvm/pr-subscribers-lld

Author: hev (heiher)

Changes

This patch introduces the relocation types added in la-abi-sepcs v2.50, enabling support for LoongArch32 Reduced and Standard variants.

Link: loongson/la-abi-specs#16
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html
Link: https://gcc.gnu.org/pipermail/gcc-patches/2025-December/703312.html


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

54 Files Affected:

  • (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 (+2-2)
  • (modified) lld/test/ELF/loongarch-relocatable-align.s (+2-2)
  • (modified) lld/test/ELF/loongarch-tls-gd-edge-case.s (+1-1)
  • (modified) lld/test/ELF/loongarch-tls-gd.s (+4-4)
  • (modified) lld/test/ELF/loongarch-tls-ie.s (+1-1)
  • (modified) lld/test/ELF/loongarch-tls-ld.s (+3-3)
  • (modified) lld/test/ELF/loongarch-tlsdesc.s (+2-2)
  • (modified) llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def (+18)
  • (modified) llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h (+80-236)
  • (modified) llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp (+314-2)
  • (modified) llvm/lib/ExecutionEngine/JITLink/loongarch.cpp (+6-2)
  • (modified) llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (+170-39)
  • (modified) llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp (+174-64)
  • (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+15-6)
  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp (+41-16)
  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (+36-16)
  • (modified) llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp (+42)
  • (modified) llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp (+39-16)
  • (modified) llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp (+1-1)
  • (modified) llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (+1-1)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h (+13)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp (+39)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp (+1)
  • (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-ilp32d.ll (+24-16)
  • (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 (+42-28)
  • (modified) llvm/test/CodeGen/LoongArch/expand-call.ll (+1-1)
  • (modified) llvm/test/CodeGen/LoongArch/float-imm.ll (+9-6)
  • (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 (+11-7)
  • (modified) llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll (+14-10)
  • (modified) llvm/test/CodeGen/LoongArch/machinelicm-address-pseudos.ll (+15-10)
  • (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/stack-protector-target.ll (+11-8)
  • (modified) llvm/test/CodeGen/LoongArch/tls-models.ll (+27-18)
  • (modified) llvm/test/CodeGen/LoongArch/unaligned-memcpy-inline.ll (+3-2)
  • (modified) llvm/test/CodeGen/LoongArch/vector-fp-imm.ll (+6-4)
  • (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/MC/LoongArch/Macros/macros-call.s (+28-1)
  • (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 --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 08d5d3e950d84..28ce704d2ea42 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s @@ -1,7 +1,7 @@ # REQUIRES: loongarch # RUN: rm -rf %t && split-file %s %t && cd %t -# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax a.s -o a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax a.s -o a.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax a.s -o a.64.o # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.32.o -o a.32 @@ -54,7 +54,7 @@ ## GOT references with non-zero addends. No relaxation. -# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax nonzero.s -o nonzero.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax nonzero.s -o nonzero.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax nonzero.s -o nonzero.64.o # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.32.o -o nonzero.32 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.64.o -o nonzero.64 diff --git a/lld/test/ELF/loongarch-relocatable-align.s b/lld/test/ELF/loongarch-relocatable-align.s index 747a58ed61eaa..c02007f9f719b 100644 --- a/lld/test/ELF/loongarch-relocatable-align.s +++ b/lld/test/ELF/loongarch-relocatable-align.s @@ -57,8 +57,8 @@ # CHECK-REL: Relocation section '.rela.text1' at offset {{.*}} contains 5 entries: ## Test LA32. -# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax a.s -o a.32.o -# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax b.s -o b.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+32s,+relax a.s -o a.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+32s,+relax b.s -o b.32.o # RUN: ld.lld -r a.32.o b.32.o -o out.32.ro # RUN: ld.lld -Ttext=0x10000 out.32.ro -o out32 # RUN: llvm-objdump -dr --no-show-raw-insn out32 | FileCheck %s --check-prefix=CHECK32 diff --git a/lld/test/ELF/loongarch-tls-gd-edge-case.s b/lld/test/ELF/loongarch-tls-gd-edge-case.s index 9f25f10c73b44..dd87d3002b180 100644 --- a/lld/test/ELF/loongarch-tls-gd-edge-case.s +++ b/lld/test/ELF/loongarch-tls-gd-edge-case.s @@ -3,7 +3,7 @@ ## Edge case: when a TLS symbol is being accessed in both GD and IE manners, ## correct reloc behavior should be preserved for both kinds of accesses. -# RUN: llvm-mc --filetype=obj --triple=loongarch32 %s -o %t.la32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s %s -o %t.la32.o # RUN: ld.lld %t.la32.o -shared -o %t.la32 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.la64.o # RUN: ld.lld %t.la64.o -shared -o %t.la64 diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s index 140aa4cea6bad..9a4ccfa2201a4 100644 --- a/lld/test/ELF/loongarch-tls-gd.s +++ b/lld/test/ELF/loongarch-tls-gd.s @@ -5,11 +5,11 @@ ## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`. ## (b) dynamic relocations can be omitted for GD->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: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %t/a.s -o %t/a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax %t/a.s -o %t/a.32.relax.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %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=loongarch32 -mattr=+32s %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 diff --git a/lld/test/ELF/loongarch-tls-ie.s b/lld/test/ELF/loongarch-tls-ie.s index ddfd9c976cb9b..e7e9617dd3efc 100644 --- a/lld/test/ELF/loongarch-tls-ie.s +++ b/lld/test/ELF/loongarch-tls-ie.s @@ -1,7 +1,7 @@ # REQUIRES: loongarch # RUN: rm -rf %t && split-file %s %t -# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/32.s -o %t/32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s %t/32.s -o %t/32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/64.s -o %t/64.o ## LA32 IE diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s index 27adb1e17702a..65be2f8fd36e4 100644 --- a/lld/test/ELF/loongarch-tls-ld.s +++ b/lld/test/ELF/loongarch-tls-ld.s @@ -5,9 +5,9 @@ ## (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=loongarch32 --position-independent -mattr=+32s %t/a.s -o %t/a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent -mattr=+32s,+relax %t/a.s -o %t/a.32.relax.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %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 diff --git a/lld/test/ELF/loongarch-tlsdesc.s b/lld/test/ELF/loongarch-tlsdesc.s index 3dc31210d7ddb..7d07c66606a87 100644 --- a/lld/test/ELF/loongarch-tlsdesc.s +++ b/lld/test/ELF/loongarch-tlsdesc.s @@ -3,8 +3,8 @@ # RUN: llvm-mc -filetype=obj -triple=loongarch64 a.s -o a.64.o # RUN: llvm-mc -filetype=obj -triple=loongarch64 c.s -o c.64.o # RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so -# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 a.s -o a.32.o -# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 c.s -o c.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 --mattr=+32s --defsym ELF32=1 a.s -o a.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 --mattr=+32s --defsym ELF32=1 c.s -o c.32.o # RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so # RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def index 4859057abcbb9..96e2c1645b57a 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def @@ -149,3 +149,21 @@ 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 v20251210, part of the +// v2.50 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_LO12, 129) +ELF_RELOC(R_LARCH_GOT_PCADD_HI20, 130) +ELF_RELOC(R_LARCH_GOT_PCADD_LO12, 131) +ELF_RELOC(R_LARCH_TLS_IE_PCADD_HI20, 132) +ELF_RELOC(R_LARCH_TLS_IE_PCADD_LO12, 133) +ELF_RELOC(R_LARCH_TLS_LD_PCADD_HI20, 134) +ELF_RELOC(R_LARCH_TLS_LD_PCADD_LO12, 135) +ELF_RELOC(R_LARCH_TLS_GD_PCADD_HI20, 136) +ELF_RELOC(R_LARCH_TLS_GD_PCADD_LO12, 137) +ELF_RELOC(R_LARCH_TLS_DESC_PCADD_HI20, 138) +ELF_RELOC(R_LARCH_TLS_DESC_PCADD_LO12, 139) 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 @@ -330,238 +397,6 @@ inline uint32_t extractBits(uint64_t Val, unsigned Hi, unsigned Lo) { return Hi == 63 ? Val >> Lo : (Val & ((((uint64_t)1 << (Hi + 1)) - 1))) >> Lo; } -/// Apply fixup expression for edge to block content. -inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) { - using namespace support; - - char *BlockWorkingMem = B.getAlreadyMutableContent().data(); - char *FixupPtr = BlockWorkingMem + E.getOffset(); - uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); - uint64_t TargetAddress = E.getTarget().getAddress().getValue(); - int64_t Addend = E.getAddend(); - - switch (E.getKind()) { - case Pointer64: - *(ulittle64_t *)FixupPtr = TargetAddress + Addend; - break; - case Pointer32: { - uint64_t Value = TargetAddress + Addend; - if (Value > std::numeric_limits<uint32_t>::max()) - return makeTargetOutOfRangeError(G, B, E); - *(ulittle32_t *)FixupPtr = Value; - break; - } - case Branch16PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<18>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<16, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm = static_cast<uint32_t>(Value >> 2); - uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10; - *(little32_t *)FixupPtr = RawInstr | Imm15_0; - break; - } - case Branch21PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<23>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<21, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm = static_cast<uint32_t>(Value >> 2); - uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10; - uint32_t Imm20_16 = extractBits(Imm, /*Hi=*/20, /*Lo=*/16); - *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16; - break; - } - case Branch26PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<28>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<26, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm = static_cast<uint32_t>(Value >> 2); - uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10; - uint32_t Imm25_16 = extractBits(Imm, /*Hi=*/25, /*Lo=*/16); - *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm25_16; - break; - } - case Delta32: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<32>(Value)) - return makeTargetOutOfRangeError(G, B, E); - *(little32_t *)FixupPtr = Value; - break; - } - case NegDelta32: { - int64_t Value = FixupAddress - TargetAddress + Addend; - if (!isInt<32>(Value)) - return makeTargetOutOfRangeError(G, B, E); - *(little32_t *)FixupPtr = Value; - break; - } - case Delta64: - *(little64_t *)FixupPtr = TargetAddress - FixupAddress + Addend; - break; - case Page20: { - uint64_t Target = TargetAddress + Addend; - uint64_t TargetPage = - (Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff); - uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(0xfff); - - int64_t PageDelta = TargetPage - PCPage; - if (!isInt<32>(PageDelta)) - return makeTargetOutOfRangeError(G, B, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5; - *(little32_t *)FixupPtr = RawInstr | Imm31_12; - break; - } - case PageOffset12: { - uint64_t TargetOffset = (TargetAddress + Addend) & 0xfff; - - uint32_t RawInstr = *(ulittle32_t *)FixupPtr; - uint32_t Imm11_0 = TargetOffset << 10; - *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0; - break; - } - case Call36PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if ((Value + 0x20000) != llvm::SignExtend64(Value + 0x20000, 38)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<36, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t Pcaddu18i = *(little32_t *)FixupPtr; - uint32_t Hi20 = extractBits(Value + (1 << 17), /*Hi=*/37, /*Lo=*/18) << 5; - *(little32_t *)FixupPtr = Pcaddu18i | Hi20; - uint32_t Jirl = *(little32_t *)(FixupPtr + 4); - uint32_t Lo16 = extractBits(Value, /*Hi=*/17, /*Lo=*/2) << 10; - *(little32_t *)(FixupPtr + 4) = Jirl | Lo16; - break; - } - case Add6: { - int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr)); - Value += ((TargetAddress + Addend) & 0x3f); - *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f); - break; - } - case Add8: { - int64_t Value = - TargetAddress + *(reinterpret_cast<const int8_t *>(FixupPtr)) + Addend; - *FixupPtr = static_cast<int8_t>(Value); - break; - } - case Add16: { - int64_t Value = - TargetAddress + support::endian::read16le(FixupPtr) + Addend; - *(little16_t *)FixupPtr = static_cast<int16_t>(Value); - break; - } - case Add32: { - int64_t Value = - TargetAddress + support::endian::read32le(FixupPtr) + Addend; - *(little32_t *)FixupPtr = static_cast<int32_t>(Value); - break; - } - case Add64: { - int64_t Value = - TargetAddress + support::endian::read64le(FixupPtr) + Addend; - *(little64_t *)FixupPtr = static_cast<int64_t>(Value); - break; - } - case AddUleb128: { - const uint32_t Maxcount = 1 + 64 / 7; - uint32_t Count; - const char *Error = nullptr; - uint64_t Orig = decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)), - &Count, nullptr, &Error); - - if (Count > Maxcount || (Count == Maxcount && Error)) - return make_error<JITLinkError>( - "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) + - ": extra space for uleb128"); - - uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL; - encodeULEB128((Orig + TargetAddress + Addend) & Mask, - (reinterpret_cast<uint8_t *>(FixupPtr)), Count); - break; - } - case Sub6: { - int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr)); - Value -= ((TargetAddress + Addend) & 0x3f); - *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f); - break; - } - case Sub8: { - int64_t Value = - *(reinterpret_cast<const int8_... [truncated] 
@llvmbot
Copy link
Member

llvmbot commented Dec 17, 2025

@llvm/pr-subscribers-llvm-binary-utilities

Author: hev (heiher)

Changes

This patch introduces the relocation types added in la-abi-sepcs v2.50, enabling support for LoongArch32 Reduced and Standard variants.

Link: loongson/la-abi-specs#16
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html
Link: https://gcc.gnu.org/pipermail/gcc-patches/2025-December/703312.html


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

54 Files Affected:

  • (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 (+2-2)
  • (modified) lld/test/ELF/loongarch-relocatable-align.s (+2-2)
  • (modified) lld/test/ELF/loongarch-tls-gd-edge-case.s (+1-1)
  • (modified) lld/test/ELF/loongarch-tls-gd.s (+4-4)
  • (modified) lld/test/ELF/loongarch-tls-ie.s (+1-1)
  • (modified) lld/test/ELF/loongarch-tls-ld.s (+3-3)
  • (modified) lld/test/ELF/loongarch-tlsdesc.s (+2-2)
  • (modified) llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def (+18)
  • (modified) llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h (+80-236)
  • (modified) llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp (+314-2)
  • (modified) llvm/lib/ExecutionEngine/JITLink/loongarch.cpp (+6-2)
  • (modified) llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (+170-39)
  • (modified) llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp (+174-64)
  • (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+15-6)
  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp (+41-16)
  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (+36-16)
  • (modified) llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp (+42)
  • (modified) llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp (+39-16)
  • (modified) llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp (+1-1)
  • (modified) llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp (+1-1)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h (+13)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCAsmInfo.cpp (+39)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp (+1)
  • (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-ilp32d.ll (+24-16)
  • (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 (+42-28)
  • (modified) llvm/test/CodeGen/LoongArch/expand-call.ll (+1-1)
  • (modified) llvm/test/CodeGen/LoongArch/float-imm.ll (+9-6)
  • (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 (+11-7)
  • (modified) llvm/test/CodeGen/LoongArch/ir-instruction/load-store.ll (+14-10)
  • (modified) llvm/test/CodeGen/LoongArch/machinelicm-address-pseudos.ll (+15-10)
  • (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/stack-protector-target.ll (+11-8)
  • (modified) llvm/test/CodeGen/LoongArch/tls-models.ll (+27-18)
  • (modified) llvm/test/CodeGen/LoongArch/unaligned-memcpy-inline.ll (+3-2)
  • (modified) llvm/test/CodeGen/LoongArch/vector-fp-imm.ll (+6-4)
  • (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/MC/LoongArch/Macros/macros-call.s (+28-1)
  • (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 --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 08d5d3e950d84..28ce704d2ea42 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s @@ -1,7 +1,7 @@ # REQUIRES: loongarch # RUN: rm -rf %t && split-file %s %t && cd %t -# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax a.s -o a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax a.s -o a.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax a.s -o a.64.o # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.32.o -o a.32 @@ -54,7 +54,7 @@ ## GOT references with non-zero addends. No relaxation. -# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax nonzero.s -o nonzero.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax nonzero.s -o nonzero.32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax nonzero.s -o nonzero.64.o # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.32.o -o nonzero.32 # RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.64.o -o nonzero.64 diff --git a/lld/test/ELF/loongarch-relocatable-align.s b/lld/test/ELF/loongarch-relocatable-align.s index 747a58ed61eaa..c02007f9f719b 100644 --- a/lld/test/ELF/loongarch-relocatable-align.s +++ b/lld/test/ELF/loongarch-relocatable-align.s @@ -57,8 +57,8 @@ # CHECK-REL: Relocation section '.rela.text1' at offset {{.*}} contains 5 entries: ## Test LA32. -# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax a.s -o a.32.o -# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax b.s -o b.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+32s,+relax a.s -o a.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+32s,+relax b.s -o b.32.o # RUN: ld.lld -r a.32.o b.32.o -o out.32.ro # RUN: ld.lld -Ttext=0x10000 out.32.ro -o out32 # RUN: llvm-objdump -dr --no-show-raw-insn out32 | FileCheck %s --check-prefix=CHECK32 diff --git a/lld/test/ELF/loongarch-tls-gd-edge-case.s b/lld/test/ELF/loongarch-tls-gd-edge-case.s index 9f25f10c73b44..dd87d3002b180 100644 --- a/lld/test/ELF/loongarch-tls-gd-edge-case.s +++ b/lld/test/ELF/loongarch-tls-gd-edge-case.s @@ -3,7 +3,7 @@ ## Edge case: when a TLS symbol is being accessed in both GD and IE manners, ## correct reloc behavior should be preserved for both kinds of accesses. -# RUN: llvm-mc --filetype=obj --triple=loongarch32 %s -o %t.la32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s %s -o %t.la32.o # RUN: ld.lld %t.la32.o -shared -o %t.la32 # RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.la64.o # RUN: ld.lld %t.la64.o -shared -o %t.la64 diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s index 140aa4cea6bad..9a4ccfa2201a4 100644 --- a/lld/test/ELF/loongarch-tls-gd.s +++ b/lld/test/ELF/loongarch-tls-gd.s @@ -5,11 +5,11 @@ ## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`. ## (b) dynamic relocations can be omitted for GD->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: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %t/a.s -o %t/a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s,+relax %t/a.s -o %t/a.32.relax.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %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=loongarch32 -mattr=+32s %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 diff --git a/lld/test/ELF/loongarch-tls-ie.s b/lld/test/ELF/loongarch-tls-ie.s index ddfd9c976cb9b..e7e9617dd3efc 100644 --- a/lld/test/ELF/loongarch-tls-ie.s +++ b/lld/test/ELF/loongarch-tls-ie.s @@ -1,7 +1,7 @@ # REQUIRES: loongarch # RUN: rm -rf %t && split-file %s %t -# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/32.s -o %t/32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+32s %t/32.s -o %t/32.o # RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/64.s -o %t/64.o ## LA32 IE diff --git a/lld/test/ELF/loongarch-tls-ld.s b/lld/test/ELF/loongarch-tls-ld.s index 27adb1e17702a..65be2f8fd36e4 100644 --- a/lld/test/ELF/loongarch-tls-ld.s +++ b/lld/test/ELF/loongarch-tls-ld.s @@ -5,9 +5,9 @@ ## (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=loongarch32 --position-independent -mattr=+32s %t/a.s -o %t/a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent -mattr=+32s,+relax %t/a.s -o %t/a.32.relax.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+32s %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 diff --git a/lld/test/ELF/loongarch-tlsdesc.s b/lld/test/ELF/loongarch-tlsdesc.s index 3dc31210d7ddb..7d07c66606a87 100644 --- a/lld/test/ELF/loongarch-tlsdesc.s +++ b/lld/test/ELF/loongarch-tlsdesc.s @@ -3,8 +3,8 @@ # RUN: llvm-mc -filetype=obj -triple=loongarch64 a.s -o a.64.o # RUN: llvm-mc -filetype=obj -triple=loongarch64 c.s -o c.64.o # RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so -# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 a.s -o a.32.o -# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 c.s -o c.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 --mattr=+32s --defsym ELF32=1 a.s -o a.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 --mattr=+32s --defsym ELF32=1 c.s -o c.32.o # RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so # RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def index 4859057abcbb9..96e2c1645b57a 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/LoongArch.def @@ -149,3 +149,21 @@ 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 v20251210, part of the +// v2.50 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_LO12, 129) +ELF_RELOC(R_LARCH_GOT_PCADD_HI20, 130) +ELF_RELOC(R_LARCH_GOT_PCADD_LO12, 131) +ELF_RELOC(R_LARCH_TLS_IE_PCADD_HI20, 132) +ELF_RELOC(R_LARCH_TLS_IE_PCADD_LO12, 133) +ELF_RELOC(R_LARCH_TLS_LD_PCADD_HI20, 134) +ELF_RELOC(R_LARCH_TLS_LD_PCADD_LO12, 135) +ELF_RELOC(R_LARCH_TLS_GD_PCADD_HI20, 136) +ELF_RELOC(R_LARCH_TLS_GD_PCADD_LO12, 137) +ELF_RELOC(R_LARCH_TLS_DESC_PCADD_HI20, 138) +ELF_RELOC(R_LARCH_TLS_DESC_PCADD_LO12, 139) 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 @@ -330,238 +397,6 @@ inline uint32_t extractBits(uint64_t Val, unsigned Hi, unsigned Lo) { return Hi == 63 ? Val >> Lo : (Val & ((((uint64_t)1 << (Hi + 1)) - 1))) >> Lo; } -/// Apply fixup expression for edge to block content. -inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) { - using namespace support; - - char *BlockWorkingMem = B.getAlreadyMutableContent().data(); - char *FixupPtr = BlockWorkingMem + E.getOffset(); - uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); - uint64_t TargetAddress = E.getTarget().getAddress().getValue(); - int64_t Addend = E.getAddend(); - - switch (E.getKind()) { - case Pointer64: - *(ulittle64_t *)FixupPtr = TargetAddress + Addend; - break; - case Pointer32: { - uint64_t Value = TargetAddress + Addend; - if (Value > std::numeric_limits<uint32_t>::max()) - return makeTargetOutOfRangeError(G, B, E); - *(ulittle32_t *)FixupPtr = Value; - break; - } - case Branch16PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<18>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<16, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm = static_cast<uint32_t>(Value >> 2); - uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10; - *(little32_t *)FixupPtr = RawInstr | Imm15_0; - break; - } - case Branch21PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<23>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<21, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm = static_cast<uint32_t>(Value >> 2); - uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10; - uint32_t Imm20_16 = extractBits(Imm, /*Hi=*/20, /*Lo=*/16); - *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16; - break; - } - case Branch26PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<28>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<26, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm = static_cast<uint32_t>(Value >> 2); - uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10; - uint32_t Imm25_16 = extractBits(Imm, /*Hi=*/25, /*Lo=*/16); - *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm25_16; - break; - } - case Delta32: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if (!isInt<32>(Value)) - return makeTargetOutOfRangeError(G, B, E); - *(little32_t *)FixupPtr = Value; - break; - } - case NegDelta32: { - int64_t Value = FixupAddress - TargetAddress + Addend; - if (!isInt<32>(Value)) - return makeTargetOutOfRangeError(G, B, E); - *(little32_t *)FixupPtr = Value; - break; - } - case Delta64: - *(little64_t *)FixupPtr = TargetAddress - FixupAddress + Addend; - break; - case Page20: { - uint64_t Target = TargetAddress + Addend; - uint64_t TargetPage = - (Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff); - uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(0xfff); - - int64_t PageDelta = TargetPage - PCPage; - if (!isInt<32>(PageDelta)) - return makeTargetOutOfRangeError(G, B, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5; - *(little32_t *)FixupPtr = RawInstr | Imm31_12; - break; - } - case PageOffset12: { - uint64_t TargetOffset = (TargetAddress + Addend) & 0xfff; - - uint32_t RawInstr = *(ulittle32_t *)FixupPtr; - uint32_t Imm11_0 = TargetOffset << 10; - *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0; - break; - } - case Call36PCRel: { - int64_t Value = TargetAddress - FixupAddress + Addend; - - if ((Value + 0x20000) != llvm::SignExtend64(Value + 0x20000, 38)) - return makeTargetOutOfRangeError(G, B, E); - - if (!isShiftedInt<36, 2>(Value)) - return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); - - uint32_t Pcaddu18i = *(little32_t *)FixupPtr; - uint32_t Hi20 = extractBits(Value + (1 << 17), /*Hi=*/37, /*Lo=*/18) << 5; - *(little32_t *)FixupPtr = Pcaddu18i | Hi20; - uint32_t Jirl = *(little32_t *)(FixupPtr + 4); - uint32_t Lo16 = extractBits(Value, /*Hi=*/17, /*Lo=*/2) << 10; - *(little32_t *)(FixupPtr + 4) = Jirl | Lo16; - break; - } - case Add6: { - int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr)); - Value += ((TargetAddress + Addend) & 0x3f); - *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f); - break; - } - case Add8: { - int64_t Value = - TargetAddress + *(reinterpret_cast<const int8_t *>(FixupPtr)) + Addend; - *FixupPtr = static_cast<int8_t>(Value); - break; - } - case Add16: { - int64_t Value = - TargetAddress + support::endian::read16le(FixupPtr) + Addend; - *(little16_t *)FixupPtr = static_cast<int16_t>(Value); - break; - } - case Add32: { - int64_t Value = - TargetAddress + support::endian::read32le(FixupPtr) + Addend; - *(little32_t *)FixupPtr = static_cast<int32_t>(Value); - break; - } - case Add64: { - int64_t Value = - TargetAddress + support::endian::read64le(FixupPtr) + Addend; - *(little64_t *)FixupPtr = static_cast<int64_t>(Value); - break; - } - case AddUleb128: { - const uint32_t Maxcount = 1 + 64 / 7; - uint32_t Count; - const char *Error = nullptr; - uint64_t Orig = decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)), - &Count, nullptr, &Error); - - if (Count > Maxcount || (Count == Maxcount && Error)) - return make_error<JITLinkError>( - "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) + - ": extra space for uleb128"); - - uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL; - encodeULEB128((Orig + TargetAddress + Addend) & Mask, - (reinterpret_cast<uint8_t *>(FixupPtr)), Count); - break; - } - case Sub6: { - int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr)); - Value -= ((TargetAddress + Addend) & 0x3f); - *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f); - break; - } - case Sub8: { - int64_t Value = - *(reinterpret_cast<const int8_... [truncated] 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment