[llvm] ValueTracking: Identify implied fp classes by general fcmp (PR #66505)
Serge Pavlov via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 6 10:04:40 PST 2023
================
@@ -4245,6 +4245,140 @@ llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS,
return {Src, Mask};
}
+std::tuple<Value *, FPClassTest, FPClassTest>
+llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS,
+ const APFloat *ConstRHS, bool LookThroughSrc) {
+ auto [Val, ClassMask] =
+ fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc);
+ if (Val)
+ return {Val, ClassMask, ~ClassMask};
+
+ FPClassTest RHSClass = ConstRHS->classify();
+ assert((RHSClass == fcPosNormal || RHSClass == fcNegNormal ||
+ RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal) &&
+ "should have been recognized as an exact class test");
+
+ const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass;
+ const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass;
+
+ assert(IsNegativeRHS == ConstRHS->isNegative());
+ assert(IsPositiveRHS == !ConstRHS->isNegative());
+
+ Value *Src = LHS;
+ const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src)));
+
+ if (IsFabs)
+ RHSClass = llvm::inverse_fabs(RHSClass);
+
+ if (Pred == FCmpInst::FCMP_OEQ)
+ return {Src, RHSClass, fcAllFlags};
+
+ if (Pred == FCmpInst::FCMP_UEQ) {
+ FPClassTest Class = RHSClass | fcNan;
+ return {Src, Class, ~fcNan};
+ }
+
+ if (Pred == FCmpInst::FCMP_ONE)
+ return {Src, ~fcNan, RHSClass};
+
+ if (Pred == FCmpInst::FCMP_UNE)
+ return {Src, fcAllFlags, RHSClass};
+
+ if (IsNegativeRHS) {
+ // TODO: Handle fneg(fabs)
+ if (IsFabs) {
+ // fabs(x) o> -k -> fcmp ord x, x
+ // fabs(x) u> -k -> true
+ // fabs(x) o< -k -> false
+ // fabs(x) u< -k -> fcmp uno x, x
+ switch (Pred) {
+ case FCmpInst::FCMP_OGT:
+ case FCmpInst::FCMP_OGE:
+ return {Src, ~fcNan, fcNan};
+ case FCmpInst::FCMP_UGT:
+ case FCmpInst::FCMP_UGE:
+ return {Src, fcAllFlags, fcNone};
+ case FCmpInst::FCMP_OLT:
+ case FCmpInst::FCMP_OLE:
+ return {Src, fcNone, fcAllFlags};
+ case FCmpInst::FCMP_ULT:
+ case FCmpInst::FCMP_ULE:
+ return {Src, fcNan, ~fcNan};
+ default:
+ break;
+ }
+
+ return {nullptr, fcAllFlags, fcAllFlags};
+ }
+
+ FPClassTest ClassesLE = fcNegInf | fcNegNormal;
+ FPClassTest ClassesGE = fcPositive | fcNegZero | fcNegSubnormal;
+
+ if (ConstRHS->isDenormal())
+ ClassesLE |= fcNegSubnormal;
+ else
+ ClassesGE |= fcNegNormal;
+
+ switch (Pred) {
+ case FCmpInst::FCMP_OGT:
+ case FCmpInst::FCMP_OGE:
+ return {Src, ClassesGE, ~ClassesGE | RHSClass};
+ case FCmpInst::FCMP_UGT:
+ case FCmpInst::FCMP_UGE:
+ return {Src, ClassesGE | fcNan, ~(ClassesGE | fcNan) | RHSClass};
+ case FCmpInst::FCMP_OLT:
+ case FCmpInst::FCMP_OLE:
+ return {Src, ClassesLE, ~ClassesLE | RHSClass};
+ case FCmpInst::FCMP_ULT:
+ case FCmpInst::FCMP_ULE:
+ return {Src, ClassesLE | fcNan, ~(ClassesLE | fcNan) | RHSClass};
+ default:
+ break;
+ }
+ } else if (IsPositiveRHS) {
+ FPClassTest ClassesGE = fcPosNormal | fcPosInf;
+ FPClassTest ClassesLE = fcNegative | fcPosZero | fcPosNormal;
+ if (ConstRHS->isDenormal())
+ ClassesGE |= fcPosNormal;
+ else
+ ClassesLE |= fcPosSubnormal;
+
+ FPClassTest FalseClasses = RHSClass;
+ if (IsFabs) {
+ ClassesGE = llvm::inverse_fabs(ClassesGE);
+ ClassesLE = llvm::inverse_fabs(ClassesLE);
+ }
----------------
spavloff wrote:
One can expect that `IsPositiveRHS` should be symmetrical to `IsNegativeRHS` but here their implementations are different.
https://github.com/llvm/llvm-project/pull/66505
More information about the llvm-commits
mailing list