[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 14:17:53 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/3] [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/3] 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
>From 5b3e093df4f3673cef2f92c6cfbc8011cfec8dc1 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan at google.com>
Date: Tue, 14 Oct 2025 14:16:44 -0700
Subject: [PATCH 3/3] Just check for getAbsoluteSymbolRange since there's no
benefit to using the sign extending instruction with absolute symbols.
---
llvm/lib/Target/X86/X86InstrCompiler.td | 5 +---
.../X86/absolute-symbol-kernel-code-model.ll | 25 ++++---------------
2 files changed, 6 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 8a1443932f853..49474649e7102 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -1261,10 +1261,7 @@ def : Pat<(i64 (X86Wrapper tjumptable :$dst)),
// 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->getMinSignedBits() <= 32;
+ return !GA->getGlobal()->getAbsoluteSymbolRange();
}]>;
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 10048ba4fec2f..ce7024dcc438b 100644
--- a/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
+++ b/llvm/test/CodeGen/X86/absolute-symbol-kernel-code-model.ll
@@ -18,32 +18,17 @@ define i64 @func_abs_sym() nounwind {
; CHECK-LABEL: func_abs_sym_in_range
define i64 @func_abs_sym_in_range() nounwind {
- ; CHECK: movq $abs_sym_in_range, %rax
+ ;; The absolute_symbol range fits in 32 bits but we still use movabs
+ ;; since there's no benefit to using the sign extending instruction
+ ;; with absolute symbols.
+ ; CHECK: movabsq $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
-}
-
@no_abs_sym = external hidden global [0 x i8]
@abs_sym = external hidden global [0 x i8], !absolute_symbol !0
@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} ;; 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
+!1 = !{i64 -2147483648, i64 2147483648} ;; In range
More information about the llvm-commits
mailing list