[llvm] [X86] Do not use movq in -mcmodel=kernel on an out of range abs global (PR #163323)

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 14 12:06:43 PDT 2025


https://github.com/PiJoules updated https://github.com/llvm/llvm-project/pull/163323

>From fbe5f0e2affc2f30ba037d6d8bed251da9b9e3cf Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan at google.com>
Date: Mon, 13 Oct 2025 22:25:32 -0700
Subject: [PATCH 1/2] [X86] Do not use movq in -mcmodel=kernel on an out of
 range abs global

CFI can lead to some `relocation R_X86_64_32S out of range` errors when
using thinlto. We have an instance of an `inline_bits` alias with a
value of 0x8000008000000001 which cannot fit into a signed 32-bit reloc
hence the error. This reloc is used because the instruction for reading
the alias is `movq` which uses a signed 32-bit immediate. The proper
instruction to use in this instance is `movabs` for the full 64-bit
reloc.

Under the kernel model, a signed 32-bit immediate was always used but if
the target is a global with `absolue_symbol` attached and the range
cannot fit within 32 bits, we should reject the MOV64ri32. The pattern
matching logic will eventually lead to a match for MOV64ri which emits
the `movabs`.
---
 llvm/lib/Target/X86/X86InstrCompiler.td       | 16 ++++++++++++--
 .../X86/absolute-symbol-kernel-code-model.ll  | 22 +++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll

diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 0fd44b74fd449..08aa9b13cd167 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -1256,8 +1256,20 @@ def : Pat<(i64 (X86Wrapper tconstpool  :$dst)),
           (MOV64ri32 tconstpool  :$dst)>, Requires<[KernelCode]>;
 def : Pat<(i64 (X86Wrapper tjumptable  :$dst)),
           (MOV64ri32 tjumptable  :$dst)>, Requires<[KernelCode]>;
-def : Pat<(i64 (X86Wrapper tglobaladdr :$dst)),
-          (MOV64ri32 tglobaladdr :$dst)>, Requires<[KernelCode]>;
+
+// If the globaladdr has an absolute_symbol range, we should assert it would
+// fit into a 32-bit offset.
+def inRange32GlobalAddr : PatLeaf<(tglobaladdr:$dst), [{
+  auto *GA = cast<GlobalAddressSDNode>(N);
+  std::optional<ConstantRange> CR = GA->getGlobal()->getAbsoluteSymbolRange();
+  if (!CR)
+    return true;
+  return CR->getSignedMin().sge(-1ull << 32) &&
+         CR->getSignedMax().slt(1ull << 32);
+}]>;
+def : Pat<(i64 (X86Wrapper inRange32GlobalAddr:$dst)),
+          (MOV64ri32 tglobaladdr:$dst)>, Requires<[KernelCode]>;
+
 def : Pat<(i64 (X86Wrapper texternalsym:$dst)),
           (MOV64ri32 texternalsym:$dst)>, Requires<[KernelCode]>;
 def : Pat<(i64 (X86Wrapper mcsym:$dst)),
diff --git a/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll b/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
new file mode 100644
index 0000000000000..4355e44c701fc
--- /dev/null
+++ b/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
@@ -0,0 +1,22 @@
+; RUN: llc --code-model=kernel < %s -asm-verbose=0 | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK-LABEL: func_abs_sym
+define i64 @func_abs_sym() nounwind {
+  ; CHECK: movabsq $abs_sym, %rax
+  %1 = ptrtoint ptr @abs_sym to i64
+  ret i64 %1
+}
+
+; CHECK-LABEL: func_no_abs_sym
+define i64 @func_no_abs_sym() nounwind {
+  ; CHECK: movq $no_abs_sym, %rax
+  %1 = ptrtoint ptr @no_abs_sym to i64
+  ret i64 %1
+}
+
+ at abs_sym = external hidden global [0 x i8], !absolute_symbol !0
+ at no_abs_sym = external hidden global [0 x i8]
+
+!0 = !{i64 -1, i64 -1}

>From 954420cf8d153491b23e878f6802c226a588c523 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan at google.com>
Date: Tue, 14 Oct 2025 12:06:13 -0700
Subject: [PATCH 2/2] Use getMinSignedBits and add a few more tests

---
 llvm/lib/Target/X86/X86InstrCompiler.td       |  3 +-
 .../X86/absolute-symbol-kernel-code-model.ll  | 39 ++++++++++++++++---
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 08aa9b13cd167..8a1443932f853 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -1264,8 +1264,7 @@ def inRange32GlobalAddr : PatLeaf<(tglobaladdr:$dst), [{
   std::optional<ConstantRange> CR = GA->getGlobal()->getAbsoluteSymbolRange();
   if (!CR)
     return true;
-  return CR->getSignedMin().sge(-1ull << 32) &&
-         CR->getSignedMax().slt(1ull << 32);
+  return CR->getMinSignedBits() <= 32;
 }]>;
 def : Pat<(i64 (X86Wrapper inRange32GlobalAddr:$dst)),
           (MOV64ri32 tglobaladdr:$dst)>, Requires<[KernelCode]>;
diff --git a/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll b/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
index 4355e44c701fc..10048ba4fec2f 100644
--- a/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
+++ b/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
@@ -2,6 +2,13 @@
 
 target triple = "x86_64-unknown-linux-gnu"
 
+; CHECK-LABEL: func_no_abs_sym
+define i64 @func_no_abs_sym() nounwind {
+  ; CHECK: movq $no_abs_sym, %rax
+  %1 = ptrtoint ptr @no_abs_sym to i64
+  ret i64 %1
+}
+
 ; CHECK-LABEL: func_abs_sym
 define i64 @func_abs_sym() nounwind {
   ; CHECK: movabsq $abs_sym, %rax
@@ -9,14 +16,34 @@ define i64 @func_abs_sym() nounwind {
   ret i64 %1
 }
 
-; CHECK-LABEL: func_no_abs_sym
-define i64 @func_no_abs_sym() nounwind {
-  ; CHECK: movq $no_abs_sym, %rax
-  %1 = ptrtoint ptr @no_abs_sym to i64
+; CHECK-LABEL: func_abs_sym_in_range
+define i64 @func_abs_sym_in_range() nounwind {
+  ; CHECK: movq $abs_sym_in_range, %rax
+  %1 = ptrtoint ptr @abs_sym_in_range to i64
+  ret i64 %1
+}
+
+; CHECK-LABEL: func_abs_sym_min_out_of_range
+define i64 @func_abs_sym_min_out_of_range() nounwind {
+  ; CHECK: movabsq $abs_sym_min_out_of_range, %rax
+  %1 = ptrtoint ptr @abs_sym_min_out_of_range to i64
+  ret i64 %1
+}
+
+; CHECK-LABEL: func_abs_sym_max_out_of_range
+define i64 @func_abs_sym_max_out_of_range() nounwind {
+  ; CHECK: movabsq $abs_sym_max_out_of_range, %rax
+  %1 = ptrtoint ptr @abs_sym_max_out_of_range to i64
   ret i64 %1
 }
 
- at abs_sym = external hidden global [0 x i8], !absolute_symbol !0
 @no_abs_sym = external hidden global [0 x i8]
+ at abs_sym = external hidden global [0 x i8], !absolute_symbol !0
+ at abs_sym_in_range = external hidden global [0 x i8], !absolute_symbol !1
+ at abs_sym_min_out_of_range = external hidden global [0 x i8], !absolute_symbol !2
+ at abs_sym_max_out_of_range = external hidden global [0 x i8], !absolute_symbol !3
 
-!0 = !{i64 -1, i64 -1}
+!0 = !{i64 -1, i64 -1}  ;; Full range
+!1 = !{i64 -2147483648, i64 2147483648}  ;; Note the upper bound is exclusive.
+!2 = !{i64 -2147483649, i64 2147483648}  ;; Min is one below -2^31
+!3 = !{i64 -2147483648, i64 2147483649}  ;; Max is one above 2^31-1



More information about the llvm-commits mailing list