[llvm] [ISEL] Fix x86-64 instruction selection bug leaking upper 32 bits (PR #205600)
Ammar Askar via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 09:17:03 PDT 2026
https://github.com/ammaraskar updated https://github.com/llvm/llvm-project/pull/205600
>From 38148d1dbe1980aabaeed0705d3957cb204167f2 Mon Sep 17 00:00:00 2001
From: Ammar Askar <aaskar at google.com>
Date: Wed, 24 Jun 2026 17:19:11 +0000
Subject: [PATCH 1/2] [ISEL] Fix x86-64 instruction selection bug leaking upper
32 bits
The x86 backend had optimization patterns that matched:
(or (and GR32:$dst, -256), (i32 (zextloadi8 addr:$src)))
and lowered it to:
(INSERT_SUBREG (i32 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)
INSERT_SUBREG for sub_8bit emits a movb instruction which preserves
the upper 56 bits. Now, if the GR32 dst came from a node that does
not zero the upper 32 bits (like IMPLICIT_DEF or EXTRACT_SUBREG),
those upper 32 bits would be leaked into the resulting register
without being zeroed.
This fixes #205291 by ensuring the input operand satisfies def32
which requires the upper 32 bits of the register to be set.
---
llvm/lib/Target/X86/X86InstrCompiler.td | 4 ++--
llvm/test/CodeGen/X86/insert.ll | 28 +++++++++++++++++++++----
2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 35dfdf2d0067c..6a6604d2a046f 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -1680,7 +1680,7 @@ def : Pat<(or (and GR64:$dst, -256),
(i64 (zextloadi8 addr:$src))),
(INSERT_SUBREG (i64 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)>;
-def : Pat<(or (and GR32:$dst, -256),
+def : Pat<(or (and def32:$dst, -256),
(i32 (zextloadi8 addr:$src))),
(INSERT_SUBREG (i32 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)>;
@@ -1688,7 +1688,7 @@ def : Pat<(or (and GR64:$dst, -65536),
(i64 (zextloadi16 addr:$src))),
(INSERT_SUBREG (i64 (COPY $dst)), (MOV16rm i16mem:$src), sub_16bit)>;
-def : Pat<(or (and GR32:$dst, -65536),
+def : Pat<(or (and def32:$dst, -65536),
(i32 (zextloadi16 addr:$src))),
(INSERT_SUBREG (i32 (COPY $dst)), (MOV16rm i16mem:$src), sub_16bit)>;
diff --git a/llvm/test/CodeGen/X86/insert.ll b/llvm/test/CodeGen/X86/insert.ll
index 381de2ecaa164..dd6b533624cec 100644
--- a/llvm/test/CodeGen/X86/insert.ll
+++ b/llvm/test/CodeGen/X86/insert.ll
@@ -58,8 +58,9 @@ define i32 @sub8_32(i32 noundef %res, ptr %byte) {
;
; X64-LABEL: sub8_32:
; X64: # %bb.0: # %entry
-; X64-NEXT: movl %edi, %eax
-; X64-NEXT: movb (%rsi), %al
+; X64-NEXT: andl $-256, %edi
+; X64-NEXT: movzbl (%rsi), %eax
+; X64-NEXT: orl %edi, %eax
; X64-NEXT: retq
entry:
%and = and i32 %res, -256
@@ -81,8 +82,9 @@ define i32 @sub16_32(i32 noundef %res, ptr %byte) {
;
; X64-LABEL: sub16_32:
; X64: # %bb.0: # %entry
-; X64-NEXT: movl %edi, %eax
-; X64-NEXT: movw (%rsi), %ax
+; X64-NEXT: andl $-65536, %edi # imm = 0xFFFF0000
+; X64-NEXT: movzwl (%rsi), %eax
+; X64-NEXT: orl %edi, %eax
; X64-NEXT: retq
entry:
%and = and i32 %res, -65536
@@ -91,3 +93,21 @@ entry:
%or = or i32 %and, %conv2
ret i32 %or
}
+
+define void @sub8_32_store_i64ptr(i32 noundef %res, ptr %byte, ptr %out) {
+; X64-LABEL: sub8_32_store_i64ptr:
+; X64: # %bb.0: # %entry
+; X64-NEXT: andl $-256, %edi
+; X64-NEXT: movzbl (%rsi), %eax
+; X64-NEXT: orl %edi, %eax
+; X64-NEXT: movq %rax, (%rdx)
+; X64-NEXT: retq
+entry:
+ %and = and i32 %res, -256
+ %d = load i8, ptr %byte, align 1
+ %conv2 = zext i8 %d to i32
+ %or = or i32 %and, %conv2
+ %z = zext i32 %or to i64
+ store i64 %z, ptr %out
+ ret void
+}
>From a9f3c30fb8e02e36e237bda9172d32f644eaf0f6 Mon Sep 17 00:00:00 2001
From: Ammar Askar <aaskar at google.com>
Date: Thu, 25 Jun 2026 16:16:50 +0000
Subject: [PATCH 2/2] Predicate patterns on In64BitMode and Not64BitMode
---
llvm/lib/Target/X86/X86InstrCompiler.td | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 6a6604d2a046f..5d6d56457dd68 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -1680,17 +1680,29 @@ def : Pat<(or (and GR64:$dst, -256),
(i64 (zextloadi8 addr:$src))),
(INSERT_SUBREG (i64 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)>;
+def : Pat<(or (and GR32:$dst, -256),
+ (i32 (zextloadi8 addr:$src))),
+ (INSERT_SUBREG (i32 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)>,
+ Requires<[Not64BitMode]>;
+
def : Pat<(or (and def32:$dst, -256),
(i32 (zextloadi8 addr:$src))),
- (INSERT_SUBREG (i32 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)>;
+ (INSERT_SUBREG (i32 (COPY $dst)), (MOV8rm i8mem:$src), sub_8bit)>,
+ Requires<[In64BitMode]>;
def : Pat<(or (and GR64:$dst, -65536),
(i64 (zextloadi16 addr:$src))),
(INSERT_SUBREG (i64 (COPY $dst)), (MOV16rm i16mem:$src), sub_16bit)>;
+def : Pat<(or (and GR32:$dst, -65536),
+ (i32 (zextloadi16 addr:$src))),
+ (INSERT_SUBREG (i32 (COPY $dst)), (MOV16rm i16mem:$src), sub_16bit)>,
+ Requires<[Not64BitMode]>;
+
def : Pat<(or (and def32:$dst, -65536),
(i32 (zextloadi16 addr:$src))),
- (INSERT_SUBREG (i32 (COPY $dst)), (MOV16rm i16mem:$src), sub_16bit)>;
+ (INSERT_SUBREG (i32 (COPY $dst)), (MOV16rm i16mem:$src), sub_16bit)>,
+ Requires<[In64BitMode]>;
// To avoid needing to materialize an immediate in a register, use a 32-bit and
// with implicit zero-extension instead of a 64-bit and if the immediate has at
More information about the llvm-commits
mailing list