[lld] [lld][Hexagon] Fix R_HEX_TPREL_11_X relocation on duplex instructions (PR #179860)

Brian Cain via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 5 06:58:16 PST 2026


https://github.com/androm3da updated https://github.com/llvm/llvm-project/pull/179860

>From 1a77688c2673503f2edb6c168e240e88d6ba9a56 Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Wed, 4 Feb 2026 20:51:39 -0800
Subject: [PATCH] [lld][Hexagon] Fix R_HEX_TPREL_11_X relocation on duplex
 instructions

The findMaskR11() function was missing handling for duplex instructions,
unlike findMaskR6() and findMaskR16() which already had isDuplex() checks.
This caused incorrect encoding when R_HEX_TPREL_11_X relocations were
applied to duplex instructions with large TLS offsets.

For duplex instructions, the immediate bits are located at positions 20-25
(mask 0x03f00000), not in the standard positions used for non-duplex
instructions.

This fix adds the isDuplex() check to findMaskR11() to return the correct
mask for duplex instruction encodings.
---
 lld/ELF/Arch/Hexagon.cpp      |  6 ++++--
 lld/test/ELF/hexagon-tls-ie.s | 36 ++++++++++++++++++++++++++++++++++-
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp
index 9b33e78731c97..63621060775e7 100644
--- a/lld/ELF/Arch/Hexagon.cpp
+++ b/lld/ELF/Arch/Hexagon.cpp
@@ -225,6 +225,8 @@ static uint32_t findMaskR8(uint32_t insn) {
 }
 
 static uint32_t findMaskR11(uint32_t insn) {
+  if (isDuplex(insn))
+    return 0x03f00000;
   if ((0xff000000 & insn) == 0xa1000000)
     return 0x060020ff;
   return 0x06003fe0;
@@ -390,14 +392,14 @@ void Hexagon::relocate(uint8_t *loc, const Relocation &rel,
     break;
   case R_HEX_B32_PCREL_X:
   case R_HEX_GD_PLT_B32_PCREL_X:
-    or32le(loc, applyMask(0x0fff3fff, val >> 6));
+    or32le(loc, applyMask(0x0fff3fff, static_cast<uint32_t>(val) >> 6));
     break;
   case R_HEX_GOTREL_HI16:
   case R_HEX_HI16:
   case R_HEX_IE_GOT_HI16:
   case R_HEX_IE_HI16:
   case R_HEX_TPREL_HI16:
-    or32le(loc, applyMask(0x00c03fff, val >> 16));
+    or32le(loc, applyMask(0x00c03fff, static_cast<uint32_t>(val) >> 16));
     break;
   case R_HEX_GOTREL_LO16:
   case R_HEX_LO16:
diff --git a/lld/test/ELF/hexagon-tls-ie.s b/lld/test/ELF/hexagon-tls-ie.s
index ea05279473116..e64f550842536 100644
--- a/lld/test/ELF/hexagon-tls-ie.s
+++ b/lld/test/ELF/hexagon-tls-ie.s
@@ -1,5 +1,6 @@
 # REQUIRES: hexagon
-# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t.o
+# RUN: rm -rf %t.dir && split-file %s %t.dir
+# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %t.dir/main.s -o %t.o
 # RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
 # RUN: ld.lld %t.o -o %t
 ## shared needs -z notext because of the R_HEX_IE_16/32_X(R_GOT) static
@@ -11,6 +12,16 @@
 # RUN: FileCheck -check-prefix=SHARED %s
 # RUN: llvm-readobj -r  %t.so | FileCheck -check-prefix=RELA %s
 
+## Test R_HEX_TPREL_11_X on duplex instructions with large TLS offset.
+## TPREL relocations cannot be used with -shared, so test separately.
+# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf \
+# RUN:   %t.dir/tprel-duplex.s -o %t-duplex.o
+# RUN: llvm-readobj -r %t-duplex.o | FileCheck -check-prefix=RELOC-DUPLEX %s
+# RUN: ld.lld %t-duplex.o -o %t-duplex
+# RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex %t-duplex | \
+# RUN:   FileCheck -check-prefix=CHECK-DUPLEX %s
+
+#--- main.s
 	.globl	_start
 	.type	_start, @function
 _start:
@@ -76,3 +87,26 @@ c:
 .globl  d
 d:
 .word 4
+
+#--- tprel-duplex.s
+## Test R_HEX_TPREL_11_X on duplex instructions with large TLS offset.
+## This exercises the isDuplex() path in findMaskR11().
+	.globl	_start
+	.type	_start, @function
+_start:
+# RELOC-DUPLEX:      0x0 R_HEX_TPREL_32_6_X e 0x0
+# RELOC-DUPLEX-NEXT: 0x4 R_HEX_TPREL_11_X e 0x0
+# CHECK-DUPLEX:      { immext(#0xfffbffc0)
+# CHECK-DUPLEX-NEXT:   r2 = add(r2,##-0x40003); memw(r3+#0x0) = #0 }
+    {
+        r2 = add(r2,##e at TPREL)
+        memw(r3+#0) = #0
+    }
+    jumpr r31
+
+.section        .tbss,"awT", at nobits
+        .p2align        2
+        .space  0xd
+        .globl  e
+e:
+        .space  0x40000



More information about the llvm-commits mailing list