[llvm] [InstCombine] Prevent folding shuffle-select with binary operation when FMF is more restrictive than input (PR #201315)
Fuad Ismail via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 03:58:58 PDT 2026
https://github.com/fuad1502 created https://github.com/llvm/llvm-project/pull/201315
Solves https://github.com/llvm/llvm-project/issues/74326
When binary operation has `ninf` FMF, but the input does not have `nofpclass(inf)`, we should not perform the transformation. Because the transformation may produce poison value when the input has an `Inf` element, whereas the original code will simply pass through the `Inf` element.
Alive proof: https://alive2.llvm.org/ce/
>From 2c03e472682e52ae467900c21bed2a3a130c3877 Mon Sep 17 00:00:00 2001
From: Fuad Ismail <fuad1502 at gmail.com>
Date: Wed, 3 Jun 2026 17:34:05 +0700
Subject: [PATCH 1/2] Add checks for differring FMF flags and FP class
---
.../shuffle_select-inseltpoison.ll | 36 +++++++++++++++++++
.../Transforms/InstCombine/shuffle_select.ll | 36 +++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll b/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll
index 3ed7fc2589d7a..bf83df8da7b80 100644
--- a/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll
@@ -372,6 +372,18 @@ define <4 x double> @fsub(<4 x double> %v) {
define <4 x float> @fmul(<4 x float> nofpclass(nan) %v) {
; CHECK-LABEL: @fmul(
+; CHECK-NEXT: [[S:%.*]] = fmul nnan <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[S]]
+;
+ %b = fmul nnan <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
+ %s = shufflevector <4 x float> %b, <4 x float> %v, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+ ret <4 x float> %s
+}
+
+; Negative test: FMF more restrictive than input FP class
+
+define <4 x float> @fmul_fmf_more_restrictive(<4 x float> nofpclass(nan) %v) {
+; CHECK-LABEL: @fmul_fmf_more_restrictive(
; CHECK-NEXT: [[S:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
; CHECK-NEXT: ret <4 x float> [[S]]
;
@@ -380,6 +392,30 @@ define <4 x float> @fmul(<4 x float> nofpclass(nan) %v) {
ret <4 x float> %s
}
+; Try FMF (nnan ninf) as restrictive input FP class
+
+define <4 x float> @fmul_fmf_as_restrictive(<4 x float> nofpclass(nan inf) %v) {
+; CHECK-LABEL: @fmul_fmf_as_restrictive(
+; CHECK-NEXT: [[S:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[S]]
+;
+ %b = fmul nnan ninf <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
+ %s = shufflevector <4 x float> %b, <4 x float> %v, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+ ret <4 x float> %s
+}
+
+; Try FMF less restrictive than input FP class
+
+define <4 x float> @fmul_fmf_less_restrictive(<4 x float> nofpclass(nan) %v) {
+; CHECK-LABEL: @fmul_fmf_less_restrictive(
+; CHECK-NEXT: [[S:%.*]] = fmul nnan <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[S]]
+;
+ %b = fmul <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
+ %s = shufflevector <4 x float> %b, <4 x float> %v, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+ ret <4 x float> %s
+}
+
define <4 x double> @fdiv_constant_op0(<4 x double> %v) {
; CHECK-LABEL: @fdiv_constant_op0(
; CHECK-NEXT: [[B:%.*]] = fdiv fast <4 x double> <double poison, double poison, double 4.300000e+01, double 4.400000e+01>, [[V:%.*]]
diff --git a/llvm/test/Transforms/InstCombine/shuffle_select.ll b/llvm/test/Transforms/InstCombine/shuffle_select.ll
index 21765f74dad78..b436f9a3db74c 100644
--- a/llvm/test/Transforms/InstCombine/shuffle_select.ll
+++ b/llvm/test/Transforms/InstCombine/shuffle_select.ll
@@ -372,6 +372,18 @@ define <4 x double> @fsub(<4 x double> %v) {
define <4 x float> @fmul(<4 x float> nofpclass(nan) %v) {
; CHECK-LABEL: @fmul(
+; CHECK-NEXT: [[S:%.*]] = fmul nnan <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[S]]
+;
+ %b = fmul nnan <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
+ %s = shufflevector <4 x float> %b, <4 x float> %v, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+ ret <4 x float> %s
+}
+
+; Negative test: FMF more restrictive than input FP class
+
+define <4 x float> @fmul_fmf_more_restrictive(<4 x float> nofpclass(nan) %v) {
+; CHECK-LABEL: @fmul_fmf_more_restrictive(
; CHECK-NEXT: [[S:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
; CHECK-NEXT: ret <4 x float> [[S]]
;
@@ -380,6 +392,30 @@ define <4 x float> @fmul(<4 x float> nofpclass(nan) %v) {
ret <4 x float> %s
}
+; Try FMF (nnan ninf) as restrictive input FP class
+
+define <4 x float> @fmul_fmf_as_restrictive(<4 x float> nofpclass(nan inf) %v) {
+; CHECK-LABEL: @fmul_fmf_as_restrictive(
+; CHECK-NEXT: [[S:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[S]]
+;
+ %b = fmul nnan ninf <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
+ %s = shufflevector <4 x float> %b, <4 x float> %v, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+ ret <4 x float> %s
+}
+
+; Try FMF less restrictive than input FP class
+
+define <4 x float> @fmul_fmf_less_restrictive(<4 x float> nofpclass(nan) %v) {
+; CHECK-LABEL: @fmul_fmf_less_restrictive(
+; CHECK-NEXT: [[S:%.*]] = fmul nnan <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: ret <4 x float> [[S]]
+;
+ %b = fmul <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
+ %s = shufflevector <4 x float> %b, <4 x float> %v, <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+ ret <4 x float> %s
+}
+
define <4 x double> @fdiv_constant_op0(<4 x double> %v) {
; CHECK-LABEL: @fdiv_constant_op0(
; CHECK-NEXT: [[B:%.*]] = fdiv fast <4 x double> <double poison, double poison, double 4.300000e+01, double 4.400000e+01>, [[V:%.*]]
>From 56c9e19830de943668b36546d17bc2dd29e81d49 Mon Sep 17 00:00:00 2001
From: Fuad Ismail <fuad1502 at gmail.com>
Date: Wed, 3 Jun 2026 17:51:26 +0700
Subject: [PATCH 2/2] Prevent folding shuffle-binop if FMF is more restrictive
---
.../InstCombine/InstCombineVectorOps.cpp | 30 ++++++++++++-------
.../shuffle_select-inseltpoison.ll | 3 +-
.../Transforms/InstCombine/shuffle_select.ll | 3 +-
3 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
index 3a7fbbcb468da..e85a50919efee 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
@@ -2283,16 +2283,26 @@ static Instruction *foldSelectShuffleWith1Binop(ShuffleVectorInst &Shuf,
Value *X = Op0IsBinop ? Op1 : Op0;
- // Prevent folding in the case the non-binop operand might have NaN values.
- // If X can have NaN elements then we have that the floating point math
- // operation in the transformed code may not preserve the exact NaN
- // bit-pattern -- e.g. `fadd sNaN, 0.0 -> qNaN`.
- // This makes the transformation incorrect since the original program would
- // have preserved the exact NaN bit-pattern.
- // Avoid the folding if X can have NaN elements.
- if (Shuf.getType()->getElementType()->isFloatingPointTy() &&
- !isKnownNeverNaN(X, SQ))
- return nullptr;
+ if (Shuf.getType()->getElementType()->isFloatingPointTy()) {
+ // Prevent folding in the case the non-binop operand might have NaN values.
+ // If X can have NaN elements then we have that the floating point math
+ // operation in the transformed code may not preserve the exact NaN
+ // bit-pattern -- e.g. `fadd sNaN, 0.0 -> qNaN`.
+ // This makes the transformation incorrect since the original program would
+ // have preserved the exact NaN bit-pattern.
+ // Avoid the folding if X can have NaN elements.
+ if (!isKnownNeverNaN(X, SQ))
+ return nullptr;
+
+ // Prevent folding when input can be infinity but noinf fast math flags is
+ // set. If X can have Inf elements and fast math flag noinf is set, the
+ // transformation may generate poison where the original program would
+ // preserve the Inf value.
+ auto Fmf = BO->getFastMathFlags();
+ if (Fmf.noInfs() && !isKnownNeverInfinity(X, SQ)) {
+ return nullptr;
+ }
+ }
// Shuffle identity constants into the lanes that return the original value.
// Example: shuf (mul X, {-1,-2,-3,-4}), X, {0,5,6,3} --> mul X, {-1,1,1,-4}
diff --git a/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll b/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll
index bf83df8da7b80..62aacec027b14 100644
--- a/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/shuffle_select-inseltpoison.ll
@@ -384,7 +384,8 @@ define <4 x float> @fmul(<4 x float> nofpclass(nan) %v) {
define <4 x float> @fmul_fmf_more_restrictive(<4 x float> nofpclass(nan) %v) {
; CHECK-LABEL: @fmul_fmf_more_restrictive(
-; CHECK-NEXT: [[S:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: [[B:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float poison, float poison, float poison>
+; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x float> [[B]], <4 x float> [[V]], <4 x i32> <i32 0, i32 5, i32 6, i32 7>
; CHECK-NEXT: ret <4 x float> [[S]]
;
%b = fmul nnan ninf <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
diff --git a/llvm/test/Transforms/InstCombine/shuffle_select.ll b/llvm/test/Transforms/InstCombine/shuffle_select.ll
index b436f9a3db74c..a4d314066a536 100644
--- a/llvm/test/Transforms/InstCombine/shuffle_select.ll
+++ b/llvm/test/Transforms/InstCombine/shuffle_select.ll
@@ -384,7 +384,8 @@ define <4 x float> @fmul(<4 x float> nofpclass(nan) %v) {
define <4 x float> @fmul_fmf_more_restrictive(<4 x float> nofpclass(nan) %v) {
; CHECK-LABEL: @fmul_fmf_more_restrictive(
-; CHECK-NEXT: [[S:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: [[B:%.*]] = fmul nnan ninf <4 x float> [[V:%.*]], <float 4.100000e+01, float poison, float poison, float poison>
+; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x float> [[B]], <4 x float> [[V]], <4 x i32> <i32 0, i32 5, i32 6, i32 7>
; CHECK-NEXT: ret <4 x float> [[S]]
;
%b = fmul nnan ninf <4 x float> %v, <float 41.0, float 42.0, float 43.0, float 44.0>
More information about the llvm-commits
mailing list