[llvm] [X86] Don't form pmaddwd for shift by 15 (PR #206473)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 29 05:44:55 PDT 2026
https://github.com/nikic created https://github.com/llvm/llvm-project/pull/206473
I believe the transform is not correct for shifts by 15, because the multiplier gets sign extended, turning a multiply by 2^15 into one by -2^15.
>From 980caf15264da6106296f0380204efd98964d4d6 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 29 Jun 2026 14:34:04 +0200
Subject: [PATCH 1/2] Add test for miscompile
---
llvm/test/CodeGen/X86/madd.ll | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/llvm/test/CodeGen/X86/madd.ll b/llvm/test/CodeGen/X86/madd.ll
index 4ca0b05dbe92b..032f086213cb6 100644
--- a/llvm/test/CodeGen/X86/madd.ll
+++ b/llvm/test/CodeGen/X86/madd.ll
@@ -3882,3 +3882,21 @@ define <3 x i32> @oddvector_shl(<12 x i16> %A) {
%ret = add <3 x i32> %odd, %even
ret <3 x i32> %ret
}
+
+define <4 x i32> @shl15(<8 x i16> %x) {
+; SSE-LABEL: shl15:
+; SSE: # %bb.0:
+; SSE-NEXT: pmaddwd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 # [32768,32768,32768,32768,32768,32768,32768,32768]
+; SSE-NEXT: retq
+;
+; AVX-LABEL: shl15:
+; AVX: # %bb.0:
+; AVX-NEXT: vpmaddwd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [32768,32768,32768,32768,32768,32768,32768,32768]
+; AVX-NEXT: retq
+ %s = sext <8 x i16> %x to <8 x i32>
+ %m = shl <8 x i32> %s, splat (i32 15)
+ %even = shufflevector <8 x i32> %m, <8 x i32> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+ %odd = shufflevector <8 x i32> %m, <8 x i32> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+ %r = add <4 x i32> %even, %odd
+ ret <4 x i32> %r
+}
>From 8a00d3ffb6ba4f74c9b8076b5e37146d2dc35b26 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 29 Jun 2026 14:36:45 +0200
Subject: [PATCH 2/2] Fix
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 4 +-
llvm/test/CodeGen/X86/madd.ll | 52 +++++++++++++++++++++----
2 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index b95ac78f50049..5575b68ed7c72 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -59681,9 +59681,9 @@ static SDValue matchPMADDWD(SelectionDAG &DAG, SDNode *N,
if (N0.getValueType().getScalarType() != MVT::i16)
return SDValue();
- // A shift by more than 15 would overflow an i16.
+ // A shift by more 15 or more would overflow a signed i16.
if (!ISD::matchUnaryPredicate(Mul.getOperand(1), [](ConstantSDNode *C) {
- return C->getAPIntValue().ule(15);
+ return C->getAPIntValue().ult(15);
}))
return SDValue();
diff --git a/llvm/test/CodeGen/X86/madd.ll b/llvm/test/CodeGen/X86/madd.ll
index 032f086213cb6..4ee77c0bdf70c 100644
--- a/llvm/test/CodeGen/X86/madd.ll
+++ b/llvm/test/CodeGen/X86/madd.ll
@@ -3883,16 +3883,52 @@ define <3 x i32> @oddvector_shl(<12 x i16> %A) {
ret <3 x i32> %ret
}
+; Don't form pmaddwd for shift by 15, because this would get interpreted as
+; a multiply by -2^15 rather than +2^15.
define <4 x i32> @shl15(<8 x i16> %x) {
-; SSE-LABEL: shl15:
-; SSE: # %bb.0:
-; SSE-NEXT: pmaddwd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0 # [32768,32768,32768,32768,32768,32768,32768,32768]
-; SSE-NEXT: retq
+; SSE2-LABEL: shl15:
+; SSE2: # %bb.0:
+; SSE2-NEXT: punpcklwd {{.*#+}} xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1],xmm1[2],xmm0[2],xmm1[3],xmm0[3]
+; SSE2-NEXT: psrad $16, %xmm1
+; SSE2-NEXT: punpckhwd {{.*#+}} xmm0 = xmm0[4,4,5,5,6,6,7,7]
+; SSE2-NEXT: psrad $16, %xmm0
+; SSE2-NEXT: pslld $15, %xmm0
+; SSE2-NEXT: pslld $15, %xmm1
+; SSE2-NEXT: movdqa %xmm1, %xmm2
+; SSE2-NEXT: shufps {{.*#+}} xmm2 = xmm2[0,2],xmm0[0,2]
+; SSE2-NEXT: shufps {{.*#+}} xmm1 = xmm1[1,3],xmm0[1,3]
+; SSE2-NEXT: paddd %xmm2, %xmm1
+; SSE2-NEXT: movdqa %xmm1, %xmm0
+; SSE2-NEXT: retq
;
-; AVX-LABEL: shl15:
-; AVX: # %bb.0:
-; AVX-NEXT: vpmaddwd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [32768,32768,32768,32768,32768,32768,32768,32768]
-; AVX-NEXT: retq
+; SSE42-LABEL: shl15:
+; SSE42: # %bb.0:
+; SSE42-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; SSE42-NEXT: pmovsxwd %xmm1, %xmm1
+; SSE42-NEXT: pmovsxwd %xmm0, %xmm0
+; SSE42-NEXT: pslld $15, %xmm0
+; SSE42-NEXT: pslld $15, %xmm1
+; SSE42-NEXT: phaddd %xmm1, %xmm0
+; SSE42-NEXT: retq
+;
+; AVX1-LABEL: shl15:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-NEXT: vpmovsxwd %xmm1, %xmm1
+; AVX1-NEXT: vpmovsxwd %xmm0, %xmm0
+; AVX1-NEXT: vpslld $15, %xmm0, %xmm0
+; AVX1-NEXT: vpslld $15, %xmm1, %xmm1
+; AVX1-NEXT: vphaddd %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: retq
+;
+; AVX256-LABEL: shl15:
+; AVX256: # %bb.0:
+; AVX256-NEXT: vpmovsxwd %xmm0, %ymm0
+; AVX256-NEXT: vpslld $15, %ymm0, %ymm0
+; AVX256-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX256-NEXT: vphaddd %xmm1, %xmm0, %xmm0
+; AVX256-NEXT: vzeroupper
+; AVX256-NEXT: retq
%s = sext <8 x i16> %x to <8 x i32>
%m = shl <8 x i32> %s, splat (i32 15)
%even = shufflevector <8 x i32> %m, <8 x i32> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
More information about the llvm-commits
mailing list