[llvm] [InstCombine] Fold (|x| + |y|) == 0 into (x == 0) && (y == 0) (PR #200702)
Aayush Shrivastava via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 2 02:57:15 PDT 2026
================
@@ -8681,6 +8681,89 @@ static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombinerImpl &IC) {
}
}
+/// Return true if V is always non-negative (i.e., never strictly negative).
+/// Recognises:
+/// 1. llvm.fabs(x) - always >= 0
+/// 2. Abs-like select patterns - select(fcmp P x, 0), x, fneg(x)) where P
+/// guarantees the true arm is non-negative, and variants thereof.
+///
+/// -0.0 and NaN are allowed: oeq/une compare treats +0 == -0, and NaN
+/// propagates identically on both sides of the surrounding transformation.
+static bool isFPAbsLike(Value *V) {
+ // fabs intrinsic is always non-negative.
+ if (match(V, m_FAbs(m_Value())))
+ return true;
+
+ // Abs-select pattern: (cond ? x : fneg(x)) or (cond ? fneg(x) : x) where
+ // the condition on x with respect to zero ensures the chosen arm is >= 0.
+ Value *Cond, *TrueVal, *FalseVal;
+ if (!match(V, m_Select(m_Value(Cond), m_Value(TrueVal), m_Value(FalseVal))))
+ return false;
+
+ for (bool Swap : {false, true}) {
+ Value *PosArm = Swap ? FalseVal : TrueVal;
+ Value *NegArm = Swap ? TrueVal : FalseVal;
+
+ // Condition must compare PosArm against zero.
+ CmpPredicate Pred;
+ if (!match(Cond, m_FCmp(Pred, m_Specific(PosArm), m_AnyZeroFP())))
+ continue;
+ // The other arm must be the negation of PosArm.
+ if (!match(NegArm, m_FNeg(m_Specific(PosArm))))
+ continue;
+
+ // When Swap=false the condition is TRUE - we pick PosArm - EffPred = Pred.
+ // When Swap=true the condition is FALSE - we pick PosArm EffPred =
+ // !Pred.
+ FCmpInst::Predicate EffPred =
+ Swap ? FCmpInst::getInversePredicate(Pred) : (FCmpInst::Predicate)Pred;
+
+ // EffPred must imply PosArm >= 0 when it holds (OGE/OGT/UGE/UGT on zero).
+ if (EffPred == FCmpInst::FCMP_OGE || EffPred == FCmpInst::FCMP_OGT ||
+ EffPred == FCmpInst::FCMP_UGE || EffPred == FCmpInst::FCMP_UGT)
+ return true;
+ }
+ return false;
+}
+
+/// Fold: fcmp oeq/une (fadd A, B), 0.0 where A and B are both non-negative.
+/// oeq -> (fcmp oeq A, 0.0) and (fcmp oeq B, 0.0)
+/// une -> (fcmp une A, 0.0) or (fcmp une B, 0.0)
+///
+/// If both addends are non-negative (e.g. fabs(x) or abs-like selects), their
+/// sum equals zero iff both are zero. NaN propagates symmetrically on both
+/// sides, so the transformation is always sound for oeq and une.
+static Instruction *foldFAbsSumFCmpZero(FCmpInst &I, InstCombinerImpl &IC) {
+ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
+ CmpInst::Predicate Pred = I.getPredicate();
+
+ if (Pred != FCmpInst::FCMP_OEQ && Pred != FCmpInst::FCMP_UNE)
+ return nullptr;
+
+ if (!match(Op1, m_AnyZeroFP()))
+ return nullptr;
+
+ Value *A, *B;
+ if (!match(Op0, m_FAdd(m_Value(A), m_Value(B))))
+ return nullptr;
+
+ if (!isFPAbsLike(A) || !isFPAbsLike(B))
----------------
iamaayushrivastava wrote:
Done. The check now goes through `cannotBeOrderedLessThanZero()`, which generalizes well beyond `llvm.fabs()`. Kept the `select(fcmp Pred X, 0), X, fneg(X))` matcher as a fallback since `computeKnownFPClass` can't see through it. That's the exact pattern from the reported issue, so I kept it rather than dropping it.
https://github.com/llvm/llvm-project/pull/200702
More information about the llvm-commits
mailing list