[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