[llvm] [InstCombine] Fold select of ordered fcmps of fabs over `isKnownNeverNaN`-selects to a single select (PR #192182)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 19 23:31:42 PDT 2026
https://github.com/imkiva updated https://github.com/llvm/llvm-project/pull/192182
>From e009c9eac05ae5a6de4da24a5eaf29912ce40323 Mon Sep 17 00:00:00 2001
From: imkiva <zengtao at iscas.ac.cn>
Date: Tue, 14 Apr 2026 17:11:13 +0800
Subject: [PATCH 1/4] [InstCombine] Fold ordered fcmps of fabs over
NaN-scrubbed selects
---
.../InstCombine/InstCombineSelect.cpp | 71 +++++++++++++++++++
.../Transforms/InstCombine/fcmp-select.ll | 65 +++++++++++++++++
2 files changed, 136 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index bffc887d93535..7ecb4ece56015 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3347,6 +3347,74 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
return ChangedFMF ? &SI : nullptr;
}
+// Fold a select of an ordered fcmp using fabs of a NaN-scrubbed value:
+// %ord = fcmp ord T %x, 0.0
+// %s = select i1 %ord, T %x, T %y
+// %a = call T @llvm.fabs.T(T %s)
+// %c = fcmp <ordered-pred> T %a, %k
+// %r = select i1 %c, T %s, T %y
+// =>
+// %a2 = call T @llvm.fabs.T(T %x)
+// %c2 = fcmp <ordered-pred> T %a2, %k
+// %r2 = select i1 %c2, T %x, T %y
+static Instruction *
+foldSelectOfOrderedFAbsCmpOfNaNScrubbedValue(SelectInst &SI,
+ InstCombinerImpl &IC) {
+ auto *OuterCmp = dyn_cast<FCmpInst>(SI.getCondition());
+ if (!OuterCmp || !OuterCmp->hasOneUse() ||
+ !FCmpInst::isOrdered(OuterCmp->getPredicate()))
+ return nullptr;
+
+ // The NaN path now evaluates fabs(X) instead of fabs(Y), so preserving nnan
+ // on the fcmp could introduce poison when X is NaN.
+ if (OuterCmp->hasNoNaNs())
+ return nullptr;
+
+ Value *Y = SI.getFalseValue();
+ Value *X = nullptr;
+
+ auto *InnerSel = dyn_cast<SelectInst>(SI.getTrueValue());
+ if (!InnerSel)
+ return nullptr;
+
+ // Match: select (fcmp ord X, 0.0), X, Y
+ auto *InnerCmp = dyn_cast<FCmpInst>(InnerSel->getCondition());
+ if (!InnerCmp || !InnerCmp->hasOneUse() ||
+ InnerCmp->getPredicate() != FCmpInst::FCMP_ORD ||
+ InnerSel->getFalseValue() != Y)
+ return nullptr;
+
+ X = InnerSel->getTrueValue();
+ if (InnerCmp->getOperand(0) != X ||
+ !match(InnerCmp->getOperand(1), m_AnyZeroFP()))
+ return nullptr;
+
+ bool Swapped = false;
+ Value *OtherOp = nullptr;
+ auto *FAbs = dyn_cast<IntrinsicInst>(OuterCmp->getOperand(0));
+
+ if (FAbs && FAbs->hasOneUse() && FAbs->getIntrinsicID() == Intrinsic::fabs &&
+ FAbs->getArgOperand(0) == InnerSel) {
+ OtherOp = OuterCmp->getOperand(1);
+ } else if ((FAbs = dyn_cast<IntrinsicInst>(OuterCmp->getOperand(1))) &&
+ FAbs->hasOneUse() && FAbs->getIntrinsicID() == Intrinsic::fabs &&
+ FAbs->getArgOperand(0) == InnerSel) {
+ Swapped = true;
+ OtherOp = OuterCmp->getOperand(0);
+ } else {
+ return nullptr;
+ }
+
+ Value *NewAbs = IC.Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X);
+ Value *NewCmp = Swapped
+ ? IC.Builder.CreateFCmpFMF(OuterCmp->getPredicate(),
+ OtherOp, NewAbs, OuterCmp)
+ : IC.Builder.CreateFCmpFMF(OuterCmp->getPredicate(),
+ NewAbs, OtherOp, OuterCmp);
+ Value *NewSel = IC.Builder.CreateSelectFMF(NewCmp, X, Y, &SI);
+ return IC.replaceInstUsesWith(SI, NewSel);
+}
+
// Match the following IR pattern:
// %x.lowbits = and i8 %x, %lowbitmask
// %x.lowbits.are.zero = icmp eq i8 %x.lowbits, 0
@@ -4599,6 +4667,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Instruction *Fabs = foldSelectWithFCmpToFabs(SI, *this))
return Fabs;
+ if (Instruction *I = foldSelectOfOrderedFAbsCmpOfNaNScrubbedValue(SI, *this))
+ return I;
+
// See if we are selecting two values based on a comparison of the two values.
if (CmpInst *CI = dyn_cast<CmpInst>(CondVal))
if (Instruction *NewSel = foldSelectValueEquivalence(SI, *CI))
diff --git a/llvm/test/Transforms/InstCombine/fcmp-select.ll b/llvm/test/Transforms/InstCombine/fcmp-select.ll
index 268cd4675c6cc..0b4e9ebff1c92 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-select.ll
@@ -3,6 +3,7 @@
declare void @use(i1)
declare void @usef64(double)
+declare double @llvm.fabs.f64(double)
; X == 42.0 ? X : 42.0 --> 42.0
@@ -280,6 +281,70 @@ define i1 @test_fcmp_ord_select_fcmp_oeq_var_const(double %x) {
ret i1 %cmp2
}
+define double @test_fcmp_ord_select_fabs_fcmp_one_select_var_const(double %x) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_one_select_var_const(
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double 0.000000e+00
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %cmp1 = fcmp ord double %x, 0.000000e+00
+ %sel1 = select i1 %cmp1, double %x, double 0.000000e+00
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double 0.000000e+00
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_select_fabs_fcmp_une_select_var_const(double %x) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_une_select_var_const(
+; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], double [[X]], double 0.000000e+00
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SEL1]])
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp une double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], double [[SEL1]], double 0.000000e+00
+; CHECK-NEXT: ret double [[SEL2]]
+;
+ %cmp1 = fcmp ord double %x, 0.000000e+00
+ %sel1 = select i1 %cmp1, double %x, double 0.000000e+00
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp une double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double 0.000000e+00
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_select_fabs_fcmp_nnan_one_select_var_var(double %x, double %y) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_nnan_one_select_var_var(
+; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SEL1]])
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp nnan one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], double [[SEL1]], double [[Y]]
+; CHECK-NEXT: ret double [[SEL2]]
+;
+ %cmp1 = fcmp ord double %x, 0.000000e+00
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp nnan one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_select_fabs_rhs_fcmp_ogt_select_var_var(double %x, double %y, double %k) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_rhs_fcmp_ogt_select_var_var(
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ogt double [[K:%.*]], [[ABS]]
+; CHECK-NEXT: [[SEL:%.*]] = select nnan i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %cmp1 = fcmp ord double %x, 0.000000e+00
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call ninf double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp ninf ogt double %k, %abs
+ %sel2 = select nnan i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
; Make sure that we recognize the SPF correctly.
define float @test_select_nnan_nsz_fcmp_olt(float %x) {
>From 9dc2eb2f2e76fdbd6bc7bddb528852d4f9c04b63 Mon Sep 17 00:00:00 2001
From: imkiva <zengtao at iscas.ac.cn>
Date: Wed, 15 Apr 2026 13:08:11 +0800
Subject: [PATCH 2/4] [InstCombine] Use `isKnownNeverNaN`
---
.../InstCombine/InstCombineSelect.cpp | 57 ++++++--
.../Transforms/InstCombine/fcmp-select.ll | 124 ++++++++++++++++++
2 files changed, 169 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7ecb4ece56015..21556d8aabee1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3347,9 +3347,50 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
return ChangedFMF ? &SI : nullptr;
}
+static bool matchIsNaNTest(FCmpInst *Cmp, Value *X, bool MatchIsNaN,
+ InstCombinerImpl &IC) {
+ FCmpInst::Predicate ExpectedPred =
+ MatchIsNaN ? FCmpInst::FCMP_UNO : FCmpInst::FCMP_ORD;
+ if (Cmp->getPredicate() != ExpectedPred)
+ return false;
+
+ Value *Cmp0 = Cmp->getOperand(0), *Cmp1 = Cmp->getOperand(1);
+ if (Cmp0 == X && Cmp1 == X)
+ return true;
+
+ auto IsKnownNeverNaN = [&](Value *V) {
+ return match(V, m_NonNaN()) ||
+ isKnownNeverNaN(V, IC.getSimplifyQuery().getWithInstruction(Cmp));
+ };
+
+ return (Cmp0 == X && IsKnownNeverNaN(Cmp1)) ||
+ (Cmp1 == X && IsKnownNeverNaN(Cmp0));
+}
+
+// Match a select that returns X when X is not NaN, and Y otherwise.
+static Value *matchNaNScrubbedValue(SelectInst *SI, Value *Y,
+ InstCombinerImpl &IC) {
+ auto *Cmp = dyn_cast<FCmpInst>(SI->getCondition());
+ if (!Cmp || !Cmp->hasOneUse())
+ return nullptr;
+
+ Value *X;
+ bool MatchIsNaN;
+ if (SI->getFalseValue() == Y) {
+ X = SI->getTrueValue();
+ MatchIsNaN = false;
+ } else if (SI->getTrueValue() == Y) {
+ X = SI->getFalseValue();
+ MatchIsNaN = true;
+ } else {
+ return nullptr;
+ }
+
+ return matchIsNaNTest(Cmp, X, MatchIsNaN, IC) ? X : nullptr;
+}
+
// Fold a select of an ordered fcmp using fabs of a NaN-scrubbed value:
-// %ord = fcmp ord T %x, 0.0
-// %s = select i1 %ord, T %x, T %y
+// %s = select i1 (isnotnan T %x), T %x, T %y
// %a = call T @llvm.fabs.T(T %s)
// %c = fcmp <ordered-pred> T %a, %k
// %r = select i1 %c, T %s, T %y
@@ -3377,16 +3418,8 @@ foldSelectOfOrderedFAbsCmpOfNaNScrubbedValue(SelectInst &SI,
if (!InnerSel)
return nullptr;
- // Match: select (fcmp ord X, 0.0), X, Y
- auto *InnerCmp = dyn_cast<FCmpInst>(InnerSel->getCondition());
- if (!InnerCmp || !InnerCmp->hasOneUse() ||
- InnerCmp->getPredicate() != FCmpInst::FCMP_ORD ||
- InnerSel->getFalseValue() != Y)
- return nullptr;
-
- X = InnerSel->getTrueValue();
- if (InnerCmp->getOperand(0) != X ||
- !match(InnerCmp->getOperand(1), m_AnyZeroFP()))
+ X = matchNaNScrubbedValue(InnerSel, Y, IC);
+ if (!X)
return nullptr;
bool Swapped = false;
diff --git a/llvm/test/Transforms/InstCombine/fcmp-select.ll b/llvm/test/Transforms/InstCombine/fcmp-select.ll
index 0b4e9ebff1c92..4cc009c066865 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-select.ll
@@ -296,6 +296,130 @@ define double @test_fcmp_ord_select_fabs_fcmp_one_select_var_const(double %x) {
ret double %sel2
}
+define double @test_fcmp_ord_commuted_select_fabs_fcmp_one_select_var_const(double %x) {
+; CHECK-LABEL: @test_fcmp_ord_commuted_select_fabs_fcmp_one_select_var_const(
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double 0.000000e+00
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %cmp1 = fcmp ord double 0.000000e+00, %x
+ %sel1 = select i1 %cmp1, double %x, double 0.000000e+00
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double 0.000000e+00
+ ret double %sel2
+}
+
+define double @test_fcmp_uno_select_fabs_fcmp_one_select_var_var(double %x, double %y) {
+; CHECK-LABEL: @test_fcmp_uno_select_fabs_fcmp_one_select_var_var(
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %cmp1 = fcmp uno double %x, 0.000000e+00
+ %sel1 = select i1 %cmp1, double %y, double %x
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_select_fabs_fcmp_one_select_nonnan_const(double %x, double %y) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_one_select_nonnan_const(
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %cmp1 = fcmp ord double %x, 1.000000e+00
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_self_select_fabs_fcmp_one_select_var_var(double %x, double %y) {
+; CHECK-LABEL: @test_fcmp_ord_self_select_fabs_fcmp_one_select_var_var(
+; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %cmp1 = fcmp ord double %x, %x
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_select_fabs_fcmp_one_select_uitofp_nonnan(double %x, double %y, i32 %i) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_one_select_uitofp_nonnan(
+; CHECK: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %nonnan = uitofp i32 %i to double
+ %cmp1 = fcmp ord double %x, %nonnan
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_commuted_select_fabs_fcmp_one_select_sitofp_nonnan(double %x, double %y, i32 %i) {
+; CHECK-LABEL: @test_fcmp_ord_commuted_select_fabs_fcmp_one_select_sitofp_nonnan(
+; CHECK: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %nonnan = sitofp i32 %i to double
+ %cmp1 = fcmp ord double %nonnan, %x
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_uno_select_fabs_fcmp_one_select_uitofp_nonnan(double %x, double %y, i32 %i) {
+; CHECK-LABEL: @test_fcmp_uno_select_fabs_fcmp_one_select_uitofp_nonnan(
+; CHECK: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %nonnan = uitofp i32 %i to double
+ %cmp1 = fcmp uno double %x, %nonnan
+ %sel1 = select i1 %cmp1, double %y, double %x
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp one double %abs, 0x7FF0000000000000
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
+define double @test_fcmp_ord_select_fabs_rhs_fcmp_ogt_select_uitofp_nonnan(double %x, double %y, double %k, i32 %i) {
+; CHECK-LABEL: @test_fcmp_ord_select_fabs_rhs_fcmp_ogt_select_uitofp_nonnan(
+; CHECK: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[K:%.*]], [[ABS]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
+; CHECK-NEXT: ret double [[SEL]]
+;
+ %nonnan = uitofp i32 %i to double
+ %cmp1 = fcmp ord double %x, %nonnan
+ %sel1 = select i1 %cmp1, double %x, double %y
+ %abs = call double @llvm.fabs.f64(double %sel1)
+ %cmp2 = fcmp ogt double %k, %abs
+ %sel2 = select i1 %cmp2, double %sel1, double %y
+ ret double %sel2
+}
+
define double @test_fcmp_ord_select_fabs_fcmp_une_select_var_const(double %x) {
; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_une_select_var_const(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
>From 82fe8ccb8aa255cc2f250baa147a0c40bb8ddf9d Mon Sep 17 00:00:00 2001
From: imkiva <zengtao at iscas.ac.cn>
Date: Wed, 15 Apr 2026 13:13:31 +0800
Subject: [PATCH 3/4] format code
---
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 21556d8aabee1..1d90697f16e3b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3439,11 +3439,10 @@ foldSelectOfOrderedFAbsCmpOfNaNScrubbedValue(SelectInst &SI,
}
Value *NewAbs = IC.Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X);
- Value *NewCmp = Swapped
- ? IC.Builder.CreateFCmpFMF(OuterCmp->getPredicate(),
- OtherOp, NewAbs, OuterCmp)
- : IC.Builder.CreateFCmpFMF(OuterCmp->getPredicate(),
- NewAbs, OtherOp, OuterCmp);
+ Value *NewCmp = Swapped ? IC.Builder.CreateFCmpFMF(OuterCmp->getPredicate(),
+ OtherOp, NewAbs, OuterCmp)
+ : IC.Builder.CreateFCmpFMF(OuterCmp->getPredicate(),
+ NewAbs, OtherOp, OuterCmp);
Value *NewSel = IC.Builder.CreateSelectFMF(NewCmp, X, Y, &SI);
return IC.replaceInstUsesWith(SI, NewSel);
}
>From b4bb8149ffa8073fe5e27b28d3aa0d9e81b978a1 Mon Sep 17 00:00:00 2001
From: imkiva <zengtao at iscas.ac.cn>
Date: Mon, 20 Apr 2026 14:31:24 +0800
Subject: [PATCH 4/4] removed uno match case
---
.../InstCombine/InstCombineSelect.cpp | 69 +++++++------------
.../Transforms/InstCombine/fcmp-select.ll | 31 ---------
2 files changed, 26 insertions(+), 74 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 1d90697f16e3b..315d5159b9f9f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3347,20 +3347,20 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
return ChangedFMF ? &SI : nullptr;
}
-static bool matchIsNaNTest(FCmpInst *Cmp, Value *X, bool MatchIsNaN,
- InstCombinerImpl &IC) {
- FCmpInst::Predicate ExpectedPred =
- MatchIsNaN ? FCmpInst::FCMP_UNO : FCmpInst::FCMP_ORD;
- if (Cmp->getPredicate() != ExpectedPred)
+static bool matchIsNotNaNTest(Value *Cond, Value *X, InstCombinerImpl &IC) {
+ Instruction *CmpI;
+ Value *Cmp0, *Cmp1;
+ if (!match(Cond, m_OneUse(m_Instruction(
+ CmpI, m_SpecificFCmp(FCmpInst::FCMP_ORD, m_Value(Cmp0),
+ m_Value(Cmp1))))))
return false;
- Value *Cmp0 = Cmp->getOperand(0), *Cmp1 = Cmp->getOperand(1);
if (Cmp0 == X && Cmp1 == X)
return true;
auto IsKnownNeverNaN = [&](Value *V) {
return match(V, m_NonNaN()) ||
- isKnownNeverNaN(V, IC.getSimplifyQuery().getWithInstruction(Cmp));
+ isKnownNeverNaN(V, IC.getSimplifyQuery().getWithInstruction(CmpI));
};
return (Cmp0 == X && IsKnownNeverNaN(Cmp1)) ||
@@ -3368,25 +3368,12 @@ static bool matchIsNaNTest(FCmpInst *Cmp, Value *X, bool MatchIsNaN,
}
// Match a select that returns X when X is not NaN, and Y otherwise.
-static Value *matchNaNScrubbedValue(SelectInst *SI, Value *Y,
- InstCombinerImpl &IC) {
- auto *Cmp = dyn_cast<FCmpInst>(SI->getCondition());
- if (!Cmp || !Cmp->hasOneUse())
+static Value *matchNaNScrubbedValue(Value *V, Value *Y, InstCombinerImpl &IC) {
+ Value *Cond, *X;
+ if (!match(V, m_Select(m_Value(Cond), m_Value(X), m_Specific(Y))))
return nullptr;
- Value *X;
- bool MatchIsNaN;
- if (SI->getFalseValue() == Y) {
- X = SI->getTrueValue();
- MatchIsNaN = false;
- } else if (SI->getTrueValue() == Y) {
- X = SI->getFalseValue();
- MatchIsNaN = true;
- } else {
- return nullptr;
- }
-
- return matchIsNaNTest(Cmp, X, MatchIsNaN, IC) ? X : nullptr;
+ return matchIsNotNaNTest(Cond, X, IC) ? X : nullptr;
}
// Fold a select of an ordered fcmp using fabs of a NaN-scrubbed value:
@@ -3401,9 +3388,15 @@ static Value *matchNaNScrubbedValue(SelectInst *SI, Value *Y,
static Instruction *
foldSelectOfOrderedFAbsCmpOfNaNScrubbedValue(SelectInst &SI,
InstCombinerImpl &IC) {
- auto *OuterCmp = dyn_cast<FCmpInst>(SI.getCondition());
- if (!OuterCmp || !OuterCmp->hasOneUse() ||
- !FCmpInst::isOrdered(OuterCmp->getPredicate()))
+ Instruction *OuterCmpI;
+ Value *Cmp0, *Cmp1;
+ if (!match(SI.getCondition(),
+ m_OneUse(m_Instruction(OuterCmpI,
+ m_FCmp(m_Value(Cmp0), m_Value(Cmp1))))))
+ return nullptr;
+
+ auto *OuterCmp = cast<FCmpInst>(OuterCmpI);
+ if (!FCmpInst::isOrdered(OuterCmp->getPredicate()))
return nullptr;
// The NaN path now evaluates fabs(X) instead of fabs(Y), so preserving nnan
@@ -3412,28 +3405,18 @@ foldSelectOfOrderedFAbsCmpOfNaNScrubbedValue(SelectInst &SI,
return nullptr;
Value *Y = SI.getFalseValue();
- Value *X = nullptr;
-
- auto *InnerSel = dyn_cast<SelectInst>(SI.getTrueValue());
- if (!InnerSel)
- return nullptr;
-
- X = matchNaNScrubbedValue(InnerSel, Y, IC);
+ Value *InnerSel = SI.getTrueValue();
+ Value *X = matchNaNScrubbedValue(InnerSel, Y, IC);
if (!X)
return nullptr;
bool Swapped = false;
Value *OtherOp = nullptr;
- auto *FAbs = dyn_cast<IntrinsicInst>(OuterCmp->getOperand(0));
-
- if (FAbs && FAbs->hasOneUse() && FAbs->getIntrinsicID() == Intrinsic::fabs &&
- FAbs->getArgOperand(0) == InnerSel) {
- OtherOp = OuterCmp->getOperand(1);
- } else if ((FAbs = dyn_cast<IntrinsicInst>(OuterCmp->getOperand(1))) &&
- FAbs->hasOneUse() && FAbs->getIntrinsicID() == Intrinsic::fabs &&
- FAbs->getArgOperand(0) == InnerSel) {
+ if (match(Cmp0, m_OneUse(m_FAbs(m_Specific(InnerSel))))) {
+ OtherOp = Cmp1;
+ } else if (match(Cmp1, m_OneUse(m_FAbs(m_Specific(InnerSel))))) {
Swapped = true;
- OtherOp = OuterCmp->getOperand(0);
+ OtherOp = Cmp0;
} else {
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/fcmp-select.ll b/llvm/test/Transforms/InstCombine/fcmp-select.ll
index 4cc009c066865..9704be6a70844 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-select.ll
@@ -311,21 +311,6 @@ define double @test_fcmp_ord_commuted_select_fabs_fcmp_one_select_var_const(doub
ret double %sel2
}
-define double @test_fcmp_uno_select_fabs_fcmp_one_select_var_var(double %x, double %y) {
-; CHECK-LABEL: @test_fcmp_uno_select_fabs_fcmp_one_select_var_var(
-; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
-; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
-; CHECK-NEXT: ret double [[SEL]]
-;
- %cmp1 = fcmp uno double %x, 0.000000e+00
- %sel1 = select i1 %cmp1, double %y, double %x
- %abs = call double @llvm.fabs.f64(double %sel1)
- %cmp2 = fcmp one double %abs, 0x7FF0000000000000
- %sel2 = select i1 %cmp2, double %sel1, double %y
- ret double %sel2
-}
-
define double @test_fcmp_ord_select_fabs_fcmp_one_select_nonnan_const(double %x, double %y) {
; CHECK-LABEL: @test_fcmp_ord_select_fabs_fcmp_one_select_nonnan_const(
; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
@@ -388,22 +373,6 @@ define double @test_fcmp_ord_commuted_select_fabs_fcmp_one_select_sitofp_nonnan(
ret double %sel2
}
-define double @test_fcmp_uno_select_fabs_fcmp_one_select_uitofp_nonnan(double %x, double %y, i32 %i) {
-; CHECK-LABEL: @test_fcmp_uno_select_fabs_fcmp_one_select_uitofp_nonnan(
-; CHECK: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
-; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[ABS]], 0x7FF0000000000000
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[X]], double [[Y:%.*]]
-; CHECK-NEXT: ret double [[SEL]]
-;
- %nonnan = uitofp i32 %i to double
- %cmp1 = fcmp uno double %x, %nonnan
- %sel1 = select i1 %cmp1, double %y, double %x
- %abs = call double @llvm.fabs.f64(double %sel1)
- %cmp2 = fcmp one double %abs, 0x7FF0000000000000
- %sel2 = select i1 %cmp2, double %sel1, double %y
- ret double %sel2
-}
-
define double @test_fcmp_ord_select_fabs_rhs_fcmp_ogt_select_uitofp_nonnan(double %x, double %y, double %k, i32 %i) {
; CHECK-LABEL: @test_fcmp_ord_select_fabs_rhs_fcmp_ogt_select_uitofp_nonnan(
; CHECK: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
More information about the llvm-commits
mailing list