[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:33:13 PDT 2026
================
@@ -3347,6 +3347,106 @@ 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:
+// %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
+// =>
+// %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;
+
+ 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 &&
----------------
imkiva wrote:
Thanks. Fixed now
https://github.com/llvm/llvm-project/pull/192182
More information about the llvm-commits
mailing list