Author: ronlieb Date: 2025-05-21T19:30:12-04:00 New Revision: c5c50f0c35141a7d219d38a8196f19ec2ca6c433
URL: https://github.com/llvm/llvm-project/commit/c5c50f0c35141a7d219d38a8196f19ec2ca6c433 DIFF: https://github.com/llvm/llvm-project/commit/c5c50f0c35141a7d219d38a8196f19ec2ca6c433.diff LOG: Revert "[llvm] add GenericFloatingPointPredicateUtils (#140254)" This reverts commit d00d74bb2564103ae3cb5ac6b6ffecf7e1cc2238. Added: Modified: llvm/include/llvm/Analysis/ValueTracking.h llvm/lib/Analysis/CMakeLists.txt llvm/lib/Analysis/InstructionSimplify.cpp llvm/lib/Analysis/ValueTracking.cpp llvm/lib/CodeGen/CMakeLists.txt llvm/lib/CodeGen/CodeGenPrepare.cpp llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp llvm/unittests/Analysis/ValueTrackingTest.cpp Removed: llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h llvm/include/llvm/Analysis/FloatingPointPredicateUtils.h llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h llvm/lib/Analysis/FloatingPointPredicateUtils.cpp llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp ################################################################################ diff --git a/llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h b/llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h deleted file mode 100644 index 49c5fe0aed6e1..0000000000000 --- a/llvm/include/llvm/ADT/GenericFloatingPointPredicateUtils.h +++ /dev/null @@ -1,479 +0,0 @@ -//===- llvm/Support/GenericFloatingPointPredicateUtils.h -----*- C++-*-----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Utilities for dealing with flags related to floating point properties and -/// mode controls. -/// -//===----------------------------------------------------------------------===/ - -#ifndef LLVM_ADT_GENERICFLOATINGPOINTPREDICATEUTILS_H -#define LLVM_ADT_GENERICFLOATINGPOINTPREDICATEUTILS_H - -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/FloatingPointMode.h" -#include "llvm/IR/Instructions.h" -#include <optional> - -namespace llvm { - -template <typename ContextT> class GenericFloatingPointPredicateUtils { - using ValueRefT = typename ContextT::ValueRefT; - using FunctionT = typename ContextT::FunctionT; - - constexpr static ValueRefT Invalid = {}; - -private: - static DenormalMode queryDenormalMode(const FunctionT &F, ValueRefT Val); - - static bool lookThroughFAbs(const FunctionT &F, ValueRefT LHS, - ValueRefT &Src); - - static std::optional<APFloat> matchConstantFloat(const FunctionT &F, - ValueRefT Val); - - /// Return the return value for fcmpImpliesClass for a compare that produces - /// an exact class test. - static std::tuple<ValueRefT, FPClassTest, FPClassTest> - exactClass(ValueRefT V, FPClassTest M) { - return {V, M, ~M}; - } - -public: - /// Returns a pair of values, which if passed to llvm.is.fpclass, returns the - /// same result as an fcmp with the given operands. - static std::pair<ValueRefT, FPClassTest> - fcmpToClassTest(FCmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - ValueRefT RHS, bool LookThroughSrc) { - std::optional<APFloat> ConstRHS = matchConstantFloat(F, RHS); - if (!ConstRHS) - return {Invalid, fcAllFlags}; - - return fcmpToClassTest(Pred, F, LHS, *ConstRHS, LookThroughSrc); - } - - static std::pair<ValueRefT, FPClassTest> - fcmpToClassTest(FCmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - const APFloat &ConstRHS, bool LookThroughSrc) { - - auto [Src, ClassIfTrue, ClassIfFalse] = - fcmpImpliesClass(Pred, F, LHS, ConstRHS, LookThroughSrc); - - if (Src && ClassIfTrue == ~ClassIfFalse) - return {Src, ClassIfTrue}; - - return {Invalid, fcAllFlags}; - } - - /// Compute the possible floating-point classes that \p LHS could be based on - /// fcmp \Pred \p LHS, \p RHS. - /// - /// \returns { TestedValue, ClassesIfTrue, ClassesIfFalse } - /// - /// If the compare returns an exact class test, ClassesIfTrue == - /// ~ClassesIfFalse - /// - /// This is a less exact version of fcmpToClassTest (e.g. fcmpToClassTest will - /// only succeed for a test of x > 0 implies positive, but not x > 1). - /// - /// If \p LookThroughSrc is true, consider the input value when computing the - /// mask. This may look through sign bit operations. - /// - /// If \p LookThroughSrc is false, ignore the source value (i.e. the first - /// pair element will always be LHS. - /// - static std::tuple<ValueRefT, FPClassTest, FPClassTest> - fcmpImpliesClass(CmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - FPClassTest RHSClass, bool LookThroughSrc) { - assert(RHSClass != fcNone); - ValueRefT Src = LHS; - - if (Pred == FCmpInst::FCMP_TRUE) - return exactClass(Src, fcAllFlags); - - if (Pred == FCmpInst::FCMP_FALSE) - return exactClass(Src, fcNone); - - const FPClassTest OrigClass = RHSClass; - - const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass; - const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass; - const bool IsNaN = (RHSClass & ~fcNan) == fcNone; - - if (IsNaN) { - // fcmp o__ x, nan -> false - // fcmp u__ x, nan -> true - return exactClass(Src, CmpInst::isOrdered(Pred) ? fcNone : fcAllFlags); - } - - // fcmp ord x, zero|normal|subnormal|inf -> ~fcNan - if (Pred == FCmpInst::FCMP_ORD) - return exactClass(Src, ~fcNan); - - // fcmp uno x, zero|normal|subnormal|inf -> fcNan - if (Pred == FCmpInst::FCMP_UNO) - return exactClass(Src, fcNan); - - const bool IsFabs = LookThroughSrc && lookThroughFAbs(F, LHS, Src); - if (IsFabs) - RHSClass = llvm::inverse_fabs(RHSClass); - - const bool IsZero = (OrigClass & fcZero) == OrigClass; - if (IsZero) { - assert(Pred != FCmpInst::FCMP_ORD && Pred != FCmpInst::FCMP_UNO); - // Compares with fcNone are only exactly equal to fcZero if input - // denormals are not flushed. - // TODO: Handle DAZ by expanding masks to cover subnormal cases. - DenormalMode Mode = queryDenormalMode(F, LHS); - if (Mode.Input != DenormalMode::IEEE) - return {Invalid, fcAllFlags, fcAllFlags}; - - switch (Pred) { - case FCmpInst::FCMP_OEQ: // Match x == 0.0 - return exactClass(Src, fcZero); - case FCmpInst::FCMP_UEQ: // Match isnan(x) || (x == 0.0) - return exactClass(Src, fcZero | fcNan); - case FCmpInst::FCMP_UNE: // Match (x != 0.0) - return exactClass(Src, ~fcZero); - case FCmpInst::FCMP_ONE: // Match !isnan(x) && x != 0.0 - return exactClass(Src, ~fcNan & ~fcZero); - case FCmpInst::FCMP_ORD: - // Canonical form of ord/uno is with a zero. We could also handle - // non-canonical other non-NaN constants or LHS == RHS. - return exactClass(Src, ~fcNan); - case FCmpInst::FCMP_UNO: - return exactClass(Src, fcNan); - case FCmpInst::FCMP_OGT: // x > 0 - return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf); - case FCmpInst::FCMP_UGT: // isnan(x) || x > 0 - return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf | fcNan); - case FCmpInst::FCMP_OGE: // x >= 0 - return exactClass(Src, fcPositive | fcNegZero); - case FCmpInst::FCMP_UGE: // isnan(x) || x >= 0 - return exactClass(Src, fcPositive | fcNegZero | fcNan); - case FCmpInst::FCMP_OLT: // x < 0 - return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf); - case FCmpInst::FCMP_ULT: // isnan(x) || x < 0 - return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf | fcNan); - case FCmpInst::FCMP_OLE: // x <= 0 - return exactClass(Src, fcNegative | fcPosZero); - case FCmpInst::FCMP_ULE: // isnan(x) || x <= 0 - return exactClass(Src, fcNegative | fcPosZero | fcNan); - default: - llvm_unreachable("all compare types are handled"); - } - - return {Invalid, fcAllFlags, fcAllFlags}; - } - - const bool IsDenormalRHS = (OrigClass & fcSubnormal) == OrigClass; - - const bool IsInf = (OrigClass & fcInf) == OrigClass; - if (IsInf) { - FPClassTest Mask = fcAllFlags; - - switch (Pred) { - case FCmpInst::FCMP_OEQ: - case FCmpInst::FCMP_UNE: { - // Match __builtin_isinf patterns - // - // fcmp oeq x, +inf -> is_fpclass x, fcPosInf - // fcmp oeq fabs(x), +inf -> is_fpclass x, fcInf - // fcmp oeq x, -inf -> is_fpclass x, fcNegInf - // fcmp oeq fabs(x), -inf -> is_fpclass x, 0 -> false - // - // fcmp une x, +inf -> is_fpclass x, ~fcPosInf - // fcmp une fabs(x), +inf -> is_fpclass x, ~fcInf - // fcmp une x, -inf -> is_fpclass x, ~fcNegInf - // fcmp une fabs(x), -inf -> is_fpclass x, fcAllFlags -> true - if (IsNegativeRHS) { - Mask = fcNegInf; - if (IsFabs) - Mask = fcNone; - } else { - Mask = fcPosInf; - if (IsFabs) - Mask |= fcNegInf; - } - break; - } - case FCmpInst::FCMP_ONE: - case FCmpInst::FCMP_UEQ: { - // Match __builtin_isinf patterns - // fcmp one x, -inf -> is_fpclass x, fcNegInf - // fcmp one fabs(x), -inf -> is_fpclass x, ~fcNegInf & ~fcNan - // fcmp one x, +inf -> is_fpclass x, ~fcNegInf & ~fcNan - // fcmp one fabs(x), +inf -> is_fpclass x, ~fcInf & fcNan - // - // fcmp ueq x, +inf -> is_fpclass x, fcPosInf|fcNan - // fcmp ueq (fabs x), +inf -> is_fpclass x, fcInf|fcNan - // fcmp ueq x, -inf -> is_fpclass x, fcNegInf|fcNan - // fcmp ueq fabs(x), -inf -> is_fpclass x, fcNan - if (IsNegativeRHS) { - Mask = ~fcNegInf & ~fcNan; - if (IsFabs) - Mask = ~fcNan; - } else { - Mask = ~fcPosInf & ~fcNan; - if (IsFabs) - Mask &= ~fcNegInf; - } - - break; - } - case FCmpInst::FCMP_OLT: - case FCmpInst::FCMP_UGE: { - if (IsNegativeRHS) { - // No value is ordered and less than negative infinity. - // All values are unordered with or at least negative infinity. - // fcmp olt x, -inf -> false - // fcmp uge x, -inf -> true - Mask = fcNone; - break; - } - - // fcmp olt fabs(x), +inf -> fcFinite - // fcmp uge fabs(x), +inf -> ~fcFinite - // fcmp olt x, +inf -> fcFinite|fcNegInf - // fcmp uge x, +inf -> ~(fcFinite|fcNegInf) - Mask = fcFinite; - if (!IsFabs) - Mask |= fcNegInf; - break; - } - case FCmpInst::FCMP_OGE: - case FCmpInst::FCMP_ULT: { - if (IsNegativeRHS) { - // fcmp oge x, -inf -> ~fcNan - // fcmp oge fabs(x), -inf -> ~fcNan - // fcmp ult x, -inf -> fcNan - // fcmp ult fabs(x), -inf -> fcNan - Mask = ~fcNan; - break; - } - - // fcmp oge fabs(x), +inf -> fcInf - // fcmp oge x, +inf -> fcPosInf - // fcmp ult fabs(x), +inf -> ~fcInf - // fcmp ult x, +inf -> ~fcPosInf - Mask = fcPosInf; - if (IsFabs) - Mask |= fcNegInf; - break; - } - case FCmpInst::FCMP_OGT: - case FCmpInst::FCMP_ULE: { - if (IsNegativeRHS) { - // fcmp ogt x, -inf -> fcmp one x, -inf - // fcmp ogt fabs(x), -inf -> fcmp ord x, x - // fcmp ule x, -inf -> fcmp ueq x, -inf - // fcmp ule fabs(x), -inf -> fcmp uno x, x - Mask = IsFabs ? ~fcNan : ~(fcNegInf | fcNan); - break; - } - - // No value is ordered and greater than infinity. - Mask = fcNone; - break; - } - case FCmpInst::FCMP_OLE: - case FCmpInst::FCMP_UGT: { - if (IsNegativeRHS) { - Mask = IsFabs ? fcNone : fcNegInf; - break; - } - - // fcmp ole x, +inf -> fcmp ord x, x - // fcmp ole fabs(x), +inf -> fcmp ord x, x - // fcmp ole x, -inf -> fcmp oeq x, -inf - // fcmp ole fabs(x), -inf -> false - Mask = ~fcNan; - break; - } - default: - llvm_unreachable("all compare types are handled"); - } - - // Invert the comparison for the unordered cases. - if (FCmpInst::isUnordered(Pred)) - Mask = ~Mask; - - return exactClass(Src, Mask); - } - - 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 | fcNan}; - - if (Pred == FCmpInst::FCMP_UNE) - return {Src, fcAllFlags, RHSClass}; - - assert((RHSClass == fcNone || RHSClass == fcPosNormal || - RHSClass == fcNegNormal || RHSClass == fcNormal || - RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal || - RHSClass == fcSubnormal) && - "should have been recognized as an exact class test"); - - 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 {Invalid, fcAllFlags, fcAllFlags}; - } - - FPClassTest ClassesLE = fcNegInf | fcNegNormal; - FPClassTest ClassesGE = fcPositive | fcNegZero | fcNegSubnormal; - - if (IsDenormalRHS) - 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 | fcPosSubnormal; - if (IsDenormalRHS) - ClassesGE |= fcPosSubnormal; - else - ClassesLE |= fcPosNormal; - - if (IsFabs) { - ClassesGE = llvm::inverse_fabs(ClassesGE); - ClassesLE = llvm::inverse_fabs(ClassesLE); - } - - 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; - } - } - - return {Invalid, fcAllFlags, fcAllFlags}; - } - - static std::tuple<ValueRefT, FPClassTest, FPClassTest> - fcmpImpliesClass(CmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - const APFloat &ConstRHS, bool LookThroughSrc) { - // We can refine checks against smallest normal / largest denormal to an - // exact class test. - if (!ConstRHS.isNegative() && ConstRHS.isSmallestNormalized()) { - ValueRefT Src = LHS; - const bool IsFabs = LookThroughSrc && lookThroughFAbs(F, LHS, Src); - - FPClassTest Mask; - // Match pattern that's used in __builtin_isnormal. - switch (Pred) { - case FCmpInst::FCMP_OLT: - case FCmpInst::FCMP_UGE: { - // fcmp olt x, smallest_normal -> - // fcNegInf|fcNegNormal|fcSubnormal|fcZero fcmp olt fabs(x), - // smallest_normal -> fcSubnormal|fcZero fcmp uge x, smallest_normal -> - // fcNan|fcPosNormal|fcPosInf fcmp uge fabs(x), smallest_normal -> - // ~(fcSubnormal|fcZero) - Mask = fcZero | fcSubnormal; - if (!IsFabs) - Mask |= fcNegNormal | fcNegInf; - - break; - } - case FCmpInst::FCMP_OGE: - case FCmpInst::FCMP_ULT: { - // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf - // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal - // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf) - // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal) - Mask = fcPosInf | fcPosNormal; - if (IsFabs) - Mask |= fcNegInf | fcNegNormal; - break; - } - default: - return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), - LookThroughSrc); - } - - // Invert the comparison for the unordered cases. - if (FCmpInst::isUnordered(Pred)) - Mask = ~Mask; - - return exactClass(Src, Mask); - } - - return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), LookThroughSrc); - } - - static std::tuple<ValueRefT, FPClassTest, FPClassTest> - fcmpImpliesClass(CmpInst::Predicate Pred, const FunctionT &F, ValueRefT LHS, - ValueRefT RHS, bool LookThroughSrc) { - std::optional<APFloat> ConstRHS = matchConstantFloat(F, RHS); - if (!ConstRHS) - return {Invalid, fcAllFlags, fcAllFlags}; - - // TODO: Just call computeKnownFPClass for RHS to handle non-constants. - return fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); - } -}; - -} // namespace llvm - -#endif // LLVM_ADT_GENERICFLOATINGPOINTPREDICATEUTILS_H diff --git a/llvm/include/llvm/Analysis/FloatingPointPredicateUtils.h b/llvm/include/llvm/Analysis/FloatingPointPredicateUtils.h deleted file mode 100644 index 96fdbf48d8b43..0000000000000 --- a/llvm/include/llvm/Analysis/FloatingPointPredicateUtils.h +++ /dev/null @@ -1,73 +0,0 @@ -//===- llvm/Analysis/FloatingPointPredicateUtils.h ------------*- C++ -*---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_FLOATINGPOINTPREDICATEUTILS_H -#define LLVM_ANALYSIS_FLOATINGPOINTPREDICATEUTILS_H - -#include "llvm/ADT/GenericFloatingPointPredicateUtils.h" -#include "llvm/IR/SSAContext.h" - -namespace llvm { - -using FloatingPointPredicateUtils = - GenericFloatingPointPredicateUtils<SSAContext>; - -/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the -/// same result as an fcmp with the given operands. -/// -/// If \p LookThroughSrc is true, consider the input value when computing the -/// mask. -/// -/// If \p LookThroughSrc is false, ignore the source value (i.e. the first pair -/// element will always be LHS. -inline std::pair<Value *, FPClassTest> -fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, - Value *RHS, bool LookThroughSrc = true) { - return FloatingPointPredicateUtils::fcmpToClassTest(Pred, F, LHS, RHS, - LookThroughSrc = true); -} - -/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the -/// same result as an fcmp with the given operands. -/// -/// If \p LookThroughSrc is true, consider the input value when computing the -/// mask. -/// -/// If \p LookThroughSrc is false, ignore the source value (i.e. the first pair -/// element will always be LHS. -inline std::pair<Value *, FPClassTest> -fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, - const APFloat *ConstRHS, bool LookThroughSrc = true) { - return FloatingPointPredicateUtils::fcmpToClassTest(Pred, F, LHS, *ConstRHS, - LookThroughSrc); -} - -inline std::tuple<Value *, FPClassTest, FPClassTest> -fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, - FPClassTest RHSClass, bool LookThroughSrc = true) { - return FloatingPointPredicateUtils::fcmpImpliesClass(Pred, F, LHS, RHSClass, - LookThroughSrc); -} - -inline std::tuple<Value *, FPClassTest, FPClassTest> -fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, - const APFloat &ConstRHS, bool LookThroughSrc = true) { - return FloatingPointPredicateUtils::fcmpImpliesClass(Pred, F, LHS, ConstRHS, - LookThroughSrc); -} - -inline std::tuple<Value *, FPClassTest, FPClassTest> -fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, - Value *RHS, bool LookThroughSrc = true) { - return FloatingPointPredicateUtils::fcmpImpliesClass(Pred, F, LHS, RHS, - LookThroughSrc); -} - -} // namespace llvm - -#endif // LLVM_ANALYSIS_FLOATINGPOINTPREDICATEUTILS_H diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 919e575ea0236..61dbb07e7128e 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -213,6 +213,49 @@ Intrinsic::ID getIntrinsicForCallSite(const CallBase &CB, bool isSignBitCheck(ICmpInst::Predicate Pred, const APInt &RHS, bool &TrueIfSigned); +/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the +/// same result as an fcmp with the given operands. +/// +/// If \p LookThroughSrc is true, consider the input value when computing the +/// mask. +/// +/// If \p LookThroughSrc is false, ignore the source value (i.e. the first pair +/// element will always be LHS. +std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred, + const Function &F, Value *LHS, + Value *RHS, + bool LookThroughSrc = true); +std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred, + const Function &F, Value *LHS, + const APFloat *ConstRHS, + bool LookThroughSrc = true); + +/// Compute the possible floating-point classes that \p LHS could be based on +/// fcmp \Pred \p LHS, \p RHS. +/// +/// \returns { TestedValue, ClassesIfTrue, ClassesIfFalse } +/// +/// If the compare returns an exact class test, ClassesIfTrue == ~ClassesIfFalse +/// +/// This is a less exact version of fcmpToClassTest (e.g. fcmpToClassTest will +/// only succeed for a test of x > 0 implies positive, but not x > 1). +/// +/// If \p LookThroughSrc is true, consider the input value when computing the +/// mask. This may look through sign bit operations. +/// +/// If \p LookThroughSrc is false, ignore the source value (i.e. the first pair +/// element will always be LHS. +/// +std::tuple<Value *, FPClassTest, FPClassTest> +fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + Value *RHS, bool LookThroughSrc = true); +std::tuple<Value *, FPClassTest, FPClassTest> +fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + FPClassTest RHS, bool LookThroughSrc = true); +std::tuple<Value *, FPClassTest, FPClassTest> +fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + const APFloat &RHS, bool LookThroughSrc = true); + /// Determine which floating-point classes are valid for \p V, and return them /// in KnownFPClass bit sets. /// diff --git a/llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h b/llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h deleted file mode 100644 index 1a965665af278..0000000000000 --- a/llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- MachineFloatingPointModeUtils.h -----*- C++ ---------------------*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_MACHINEFLOATINGPOINTPREDICATEUTILS_H -#define LLVM_CODEGEN_MACHINEFLOATINGPOINTPREDICATEUTILS_H - -#include "llvm/ADT/GenericFloatingPointPredicateUtils.h" -#include "llvm/CodeGen/MachineSSAContext.h" - -namespace llvm { - -using MachineFloatingPointPredicateUtils = - GenericFloatingPointPredicateUtils<MachineSSAContext>; - -/// Compute the possible floating-point classes that \p LHS could be based on -/// fcmp \Pred \p LHS, \p RHS. -/// -/// \returns { TestedValue, ClassesIfTrue, ClassesIfFalse } -/// -/// If the compare returns an exact class test, ClassesIfTrue == -/// ~ClassesIfFalse -/// -/// This is a less exact version of fcmpToClassTest (e.g. fcmpToClassTest will -/// only succeed for a test of x > 0 implies positive, but not x > 1). -/// -/// If \p LookThroughSrc is true, consider the input value when computing the -/// mask. This may look through sign bit operations. -/// -/// If \p LookThroughSrc is false, ignore the source value (i.e. the first -/// pair element will always be LHS. -/// -inline std::tuple<Register, FPClassTest, FPClassTest> -fcmpImpliesClass(CmpInst::Predicate Pred, const MachineFunction &MF, - Register LHS, Register RHS, bool LookThroughSrc = true) { - return MachineFloatingPointPredicateUtils::fcmpImpliesClass( - Pred, MF, LHS, RHS, LookThroughSrc); -} - -} // namespace llvm - -#endif // LLVM_CODEGEN_MACHINEFLOATINGPOINTPREDICATEUTILS_H diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index e884f11f0f758..a17a75e6fbcac 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -74,7 +74,6 @@ add_llvm_component_library(LLVMAnalysis DXILResource.cpp DXILMetadataAnalysis.cpp EphemeralValuesCache.cpp - FloatingPointPredicateUtils.cpp FunctionPropertiesAnalysis.cpp GlobalsModRef.cpp GuardUtils.cpp diff --git a/llvm/lib/Analysis/FloatingPointPredicateUtils.cpp b/llvm/lib/Analysis/FloatingPointPredicateUtils.cpp deleted file mode 100644 index 4985f3dec7dce..0000000000000 --- a/llvm/lib/Analysis/FloatingPointPredicateUtils.cpp +++ /dev/null @@ -1,41 +0,0 @@ -//===- FloatingPointPredicateUtils.cpp ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/FloatingPointPredicateUtils.h" -#include "llvm/IR/PatternMatch.h" -#include <optional> - -namespace llvm { - -using namespace PatternMatch; - -template <> -DenormalMode FloatingPointPredicateUtils::queryDenormalMode(const Function &F, - Value *Val) { - Type *Ty = Val->getType()->getScalarType(); - return F.getDenormalMode(Ty->getFltSemantics()); -} - -template <> -bool FloatingPointPredicateUtils::lookThroughFAbs(const Function &F, Value *LHS, - Value *&Src) { - return match(LHS, m_FAbs(m_Value(Src))); -} - -template <> -std::optional<APFloat> -FloatingPointPredicateUtils::matchConstantFloat(const Function &F, Value *Val) { - const APFloat *ConstVal; - - if (!match(Val, m_APFloatAllowPoison(ConstVal))) - return std::nullopt; - - return *ConstVal; -} - -} // namespace llvm diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 23e147ba8c6a1..85e3be9cc45c3 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -26,7 +26,6 @@ #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/CmpInstAnalysis.h" #include "llvm/Analysis/ConstantFolding.h" -#include "llvm/Analysis/FloatingPointPredicateUtils.h" #include "llvm/Analysis/InstSimplifyFolder.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/LoopAnalysisManager.h" diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 5b9338b500ecc..8405678aa9680 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -15,7 +15,6 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallPtrSet.h" @@ -28,7 +27,6 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/DomConditionCache.h" -#include "llvm/Analysis/FloatingPointPredicateUtils.h" #include "llvm/Analysis/GuardUtils.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/Loads.h" @@ -4500,6 +4498,13 @@ Intrinsic::ID llvm::getIntrinsicForCallSite(const CallBase &CB, return Intrinsic::not_intrinsic; } +/// Return true if it's possible to assume IEEE treatment of input denormals in +/// \p F for \p Val. +static bool inputDenormalIsIEEE(const Function &F, const Type *Ty) { + Ty = Ty->getScalarType(); + return F.getDenormalMode(Ty->getFltSemantics()).Input == DenormalMode::IEEE; +} + static bool outputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { Ty = Ty->getScalarType(); DenormalMode Mode = F.getDenormalMode(Ty->getFltSemantics()); @@ -4545,6 +4550,421 @@ bool llvm::isSignBitCheck(ICmpInst::Predicate Pred, const APInt &RHS, } } +/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the +/// same result as an fcmp with the given operands. +std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred, + const Function &F, + Value *LHS, Value *RHS, + bool LookThroughSrc) { + const APFloat *ConstRHS; + if (!match(RHS, m_APFloatAllowPoison(ConstRHS))) + return {nullptr, fcAllFlags}; + + return fcmpToClassTest(Pred, F, LHS, ConstRHS, LookThroughSrc); +} + +std::pair<Value *, FPClassTest> +llvm::fcmpToClassTest(FCmpInst::Predicate Pred, const Function &F, Value *LHS, + const APFloat *ConstRHS, bool LookThroughSrc) { + + auto [Src, ClassIfTrue, ClassIfFalse] = + fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); + if (Src && ClassIfTrue == ~ClassIfFalse) + return {Src, ClassIfTrue}; + return {nullptr, fcAllFlags}; +} + +/// Return the return value for fcmpImpliesClass for a compare that produces an +/// exact class test. +static std::tuple<Value *, FPClassTest, FPClassTest> exactClass(Value *V, + FPClassTest M) { + return {V, M, ~M}; +} + +std::tuple<Value *, FPClassTest, FPClassTest> +llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + FPClassTest RHSClass, bool LookThroughSrc) { + assert(RHSClass != fcNone); + Value *Src = LHS; + + if (Pred == FCmpInst::FCMP_TRUE) + return exactClass(Src, fcAllFlags); + + if (Pred == FCmpInst::FCMP_FALSE) + return exactClass(Src, fcNone); + + const FPClassTest OrigClass = RHSClass; + + const bool IsNegativeRHS = (RHSClass & fcNegative) == RHSClass; + const bool IsPositiveRHS = (RHSClass & fcPositive) == RHSClass; + const bool IsNaN = (RHSClass & ~fcNan) == fcNone; + + if (IsNaN) { + // fcmp o__ x, nan -> false + // fcmp u__ x, nan -> true + return exactClass(Src, CmpInst::isOrdered(Pred) ? fcNone : fcAllFlags); + } + + // fcmp ord x, zero|normal|subnormal|inf -> ~fcNan + if (Pred == FCmpInst::FCMP_ORD) + return exactClass(Src, ~fcNan); + + // fcmp uno x, zero|normal|subnormal|inf -> fcNan + if (Pred == FCmpInst::FCMP_UNO) + return exactClass(Src, fcNan); + + const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); + if (IsFabs) + RHSClass = llvm::inverse_fabs(RHSClass); + + const bool IsZero = (OrigClass & fcZero) == OrigClass; + if (IsZero) { + assert(Pred != FCmpInst::FCMP_ORD && Pred != FCmpInst::FCMP_UNO); + // Compares with fcNone are only exactly equal to fcZero if input denormals + // are not flushed. + // TODO: Handle DAZ by expanding masks to cover subnormal cases. + if (!inputDenormalIsIEEE(F, LHS->getType())) + return {nullptr, fcAllFlags, fcAllFlags}; + + switch (Pred) { + case FCmpInst::FCMP_OEQ: // Match x == 0.0 + return exactClass(Src, fcZero); + case FCmpInst::FCMP_UEQ: // Match isnan(x) || (x == 0.0) + return exactClass(Src, fcZero | fcNan); + case FCmpInst::FCMP_UNE: // Match (x != 0.0) + return exactClass(Src, ~fcZero); + case FCmpInst::FCMP_ONE: // Match !isnan(x) && x != 0.0 + return exactClass(Src, ~fcNan & ~fcZero); + case FCmpInst::FCMP_ORD: + // Canonical form of ord/uno is with a zero. We could also handle + // non-canonical other non-NaN constants or LHS == RHS. + return exactClass(Src, ~fcNan); + case FCmpInst::FCMP_UNO: + return exactClass(Src, fcNan); + case FCmpInst::FCMP_OGT: // x > 0 + return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf); + case FCmpInst::FCMP_UGT: // isnan(x) || x > 0 + return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf | fcNan); + case FCmpInst::FCMP_OGE: // x >= 0 + return exactClass(Src, fcPositive | fcNegZero); + case FCmpInst::FCMP_UGE: // isnan(x) || x >= 0 + return exactClass(Src, fcPositive | fcNegZero | fcNan); + case FCmpInst::FCMP_OLT: // x < 0 + return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf); + case FCmpInst::FCMP_ULT: // isnan(x) || x < 0 + return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf | fcNan); + case FCmpInst::FCMP_OLE: // x <= 0 + return exactClass(Src, fcNegative | fcPosZero); + case FCmpInst::FCMP_ULE: // isnan(x) || x <= 0 + return exactClass(Src, fcNegative | fcPosZero | fcNan); + default: + llvm_unreachable("all compare types are handled"); + } + + return {nullptr, fcAllFlags, fcAllFlags}; + } + + const bool IsDenormalRHS = (OrigClass & fcSubnormal) == OrigClass; + + const bool IsInf = (OrigClass & fcInf) == OrigClass; + if (IsInf) { + FPClassTest Mask = fcAllFlags; + + switch (Pred) { + case FCmpInst::FCMP_OEQ: + case FCmpInst::FCMP_UNE: { + // Match __builtin_isinf patterns + // + // fcmp oeq x, +inf -> is_fpclass x, fcPosInf + // fcmp oeq fabs(x), +inf -> is_fpclass x, fcInf + // fcmp oeq x, -inf -> is_fpclass x, fcNegInf + // fcmp oeq fabs(x), -inf -> is_fpclass x, 0 -> false + // + // fcmp une x, +inf -> is_fpclass x, ~fcPosInf + // fcmp une fabs(x), +inf -> is_fpclass x, ~fcInf + // fcmp une x, -inf -> is_fpclass x, ~fcNegInf + // fcmp une fabs(x), -inf -> is_fpclass x, fcAllFlags -> true + if (IsNegativeRHS) { + Mask = fcNegInf; + if (IsFabs) + Mask = fcNone; + } else { + Mask = fcPosInf; + if (IsFabs) + Mask |= fcNegInf; + } + break; + } + case FCmpInst::FCMP_ONE: + case FCmpInst::FCMP_UEQ: { + // Match __builtin_isinf patterns + // fcmp one x, -inf -> is_fpclass x, fcNegInf + // fcmp one fabs(x), -inf -> is_fpclass x, ~fcNegInf & ~fcNan + // fcmp one x, +inf -> is_fpclass x, ~fcNegInf & ~fcNan + // fcmp one fabs(x), +inf -> is_fpclass x, ~fcInf & fcNan + // + // fcmp ueq x, +inf -> is_fpclass x, fcPosInf|fcNan + // fcmp ueq (fabs x), +inf -> is_fpclass x, fcInf|fcNan + // fcmp ueq x, -inf -> is_fpclass x, fcNegInf|fcNan + // fcmp ueq fabs(x), -inf -> is_fpclass x, fcNan + if (IsNegativeRHS) { + Mask = ~fcNegInf & ~fcNan; + if (IsFabs) + Mask = ~fcNan; + } else { + Mask = ~fcPosInf & ~fcNan; + if (IsFabs) + Mask &= ~fcNegInf; + } + + break; + } + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_UGE: { + if (IsNegativeRHS) { + // No value is ordered and less than negative infinity. + // All values are unordered with or at least negative infinity. + // fcmp olt x, -inf -> false + // fcmp uge x, -inf -> true + Mask = fcNone; + break; + } + + // fcmp olt fabs(x), +inf -> fcFinite + // fcmp uge fabs(x), +inf -> ~fcFinite + // fcmp olt x, +inf -> fcFinite|fcNegInf + // fcmp uge x, +inf -> ~(fcFinite|fcNegInf) + Mask = fcFinite; + if (!IsFabs) + Mask |= fcNegInf; + break; + } + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_ULT: { + if (IsNegativeRHS) { + // fcmp oge x, -inf -> ~fcNan + // fcmp oge fabs(x), -inf -> ~fcNan + // fcmp ult x, -inf -> fcNan + // fcmp ult fabs(x), -inf -> fcNan + Mask = ~fcNan; + break; + } + + // fcmp oge fabs(x), +inf -> fcInf + // fcmp oge x, +inf -> fcPosInf + // fcmp ult fabs(x), +inf -> ~fcInf + // fcmp ult x, +inf -> ~fcPosInf + Mask = fcPosInf; + if (IsFabs) + Mask |= fcNegInf; + break; + } + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_ULE: { + if (IsNegativeRHS) { + // fcmp ogt x, -inf -> fcmp one x, -inf + // fcmp ogt fabs(x), -inf -> fcmp ord x, x + // fcmp ule x, -inf -> fcmp ueq x, -inf + // fcmp ule fabs(x), -inf -> fcmp uno x, x + Mask = IsFabs ? ~fcNan : ~(fcNegInf | fcNan); + break; + } + + // No value is ordered and greater than infinity. + Mask = fcNone; + break; + } + case FCmpInst::FCMP_OLE: + case FCmpInst::FCMP_UGT: { + if (IsNegativeRHS) { + Mask = IsFabs ? fcNone : fcNegInf; + break; + } + + // fcmp ole x, +inf -> fcmp ord x, x + // fcmp ole fabs(x), +inf -> fcmp ord x, x + // fcmp ole x, -inf -> fcmp oeq x, -inf + // fcmp ole fabs(x), -inf -> false + Mask = ~fcNan; + break; + } + default: + llvm_unreachable("all compare types are handled"); + } + + // Invert the comparison for the unordered cases. + if (FCmpInst::isUnordered(Pred)) + Mask = ~Mask; + + return exactClass(Src, Mask); + } + + 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 | fcNan}; + + if (Pred == FCmpInst::FCMP_UNE) + return {Src, fcAllFlags, RHSClass}; + + assert((RHSClass == fcNone || RHSClass == fcPosNormal || + RHSClass == fcNegNormal || RHSClass == fcNormal || + RHSClass == fcPosSubnormal || RHSClass == fcNegSubnormal || + RHSClass == fcSubnormal) && + "should have been recognized as an exact class test"); + + 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 (IsDenormalRHS) + 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 | fcPosSubnormal; + if (IsDenormalRHS) + ClassesGE |= fcPosSubnormal; + else + ClassesLE |= fcPosNormal; + + if (IsFabs) { + ClassesGE = llvm::inverse_fabs(ClassesGE); + ClassesLE = llvm::inverse_fabs(ClassesLE); + } + + 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; + } + } + + return {nullptr, fcAllFlags, fcAllFlags}; +} + +std::tuple<Value *, FPClassTest, FPClassTest> +llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + const APFloat &ConstRHS, bool LookThroughSrc) { + // We can refine checks against smallest normal / largest denormal to an + // exact class test. + if (!ConstRHS.isNegative() && ConstRHS.isSmallestNormalized()) { + Value *Src = LHS; + const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src))); + + FPClassTest Mask; + // Match pattern that's used in __builtin_isnormal. + switch (Pred) { + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_UGE: { + // fcmp olt x, smallest_normal -> fcNegInf|fcNegNormal|fcSubnormal|fcZero + // fcmp olt fabs(x), smallest_normal -> fcSubnormal|fcZero + // fcmp uge x, smallest_normal -> fcNan|fcPosNormal|fcPosInf + // fcmp uge fabs(x), smallest_normal -> ~(fcSubnormal|fcZero) + Mask = fcZero | fcSubnormal; + if (!IsFabs) + Mask |= fcNegNormal | fcNegInf; + + break; + } + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_ULT: { + // fcmp oge x, smallest_normal -> fcPosNormal | fcPosInf + // fcmp oge fabs(x), smallest_normal -> fcInf | fcNormal + // fcmp ult x, smallest_normal -> ~(fcPosNormal | fcPosInf) + // fcmp ult fabs(x), smallest_normal -> ~(fcInf | fcNormal) + Mask = fcPosInf | fcPosNormal; + if (IsFabs) + Mask |= fcNegInf | fcNegNormal; + break; + } + default: + return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), + LookThroughSrc); + } + + // Invert the comparison for the unordered cases. + if (FCmpInst::isUnordered(Pred)) + Mask = ~Mask; + + return exactClass(Src, Mask); + } + + return fcmpImpliesClass(Pred, F, LHS, ConstRHS.classify(), LookThroughSrc); +} + +std::tuple<Value *, FPClassTest, FPClassTest> +llvm::fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, + Value *RHS, bool LookThroughSrc) { + const APFloat *ConstRHS; + if (!match(RHS, m_APFloatAllowPoison(ConstRHS))) + return {nullptr, fcAllFlags, fcAllFlags}; + + // TODO: Just call computeKnownFPClass for RHS to handle non-constants. + return fcmpImpliesClass(Pred, F, LHS, *ConstRHS, LookThroughSrc); +} + static void computeKnownFPClassFromCond(const Value *V, Value *Cond, unsigned Depth, bool CondIsTrue, const Instruction *CxtI, diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index dcf7c08d499e1..5dd6413431255 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -119,7 +119,6 @@ add_llvm_component_library(LLVMCodeGen MachineCycleAnalysis.cpp MachineDebugify.cpp MachineDomTreeUpdater.cpp - MachineFloatingPointPredicateUtils.cpp MachineDominanceFrontier.cpp MachineDominators.cpp MachineFrameInfo.cpp diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index 52263026d6cea..76f27623c8656 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -24,7 +24,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BranchProbabilityInfo.h" -#include "llvm/Analysis/FloatingPointPredicateUtils.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ProfileSummaryInfo.h" diff --git a/llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp b/llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp deleted file mode 100644 index 3f640ded22c55..0000000000000 --- a/llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//===- MachineFloatingPointPredicateUtils.cpp -----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/MachineFloatingPointPredicateUtils.h" -#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" -#include "llvm/CodeGen/LowLevelTypeUtils.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/MachineSSAContext.h" -#include "llvm/IR/Constants.h" -#include <optional> - -namespace llvm { - -using namespace MIPatternMatch; - -template <> -DenormalMode -MachineFloatingPointPredicateUtils::queryDenormalMode(const MachineFunction &MF, - Register Val) { - const MachineRegisterInfo &MRI = MF.getRegInfo(); - LLT Ty = MRI.getType(Val).getScalarType(); - return MF.getDenormalMode(getFltSemanticForLLT(Ty)); -} - -template <> -bool MachineFloatingPointPredicateUtils::lookThroughFAbs( - const MachineFunction &MF, Register LHS, Register &Src) { - const MachineRegisterInfo &MRI = MF.getRegInfo(); - return mi_match(LHS, MRI, m_GFabs(m_Reg(Src))); -} - -template <> -std::optional<APFloat> MachineFloatingPointPredicateUtils::matchConstantFloat( - const MachineFunction &MF, Register Val) { - const MachineRegisterInfo &MRI = MF.getRegInfo(); - const ConstantFP *ConstVal; - if (mi_match(Val, MRI, m_GFCst(ConstVal))) - return ConstVal->getValueAPF(); - - return std::nullopt; -} - -} // namespace llvm diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index d90c22672a5ec..508aef63a3128 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -12,7 +12,6 @@ #include "InstCombineInternal.h" #include "llvm/Analysis/CmpInstAnalysis.h" -#include "llvm/Analysis/FloatingPointPredicateUtils.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Intrinsics.h" diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp index a5050542b8186..e1baa389bbc66 100644 --- a/llvm/unittests/Analysis/ValueTrackingTest.cpp +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -8,7 +8,6 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/AssumptionCache.h" -#include "llvm/Analysis/FloatingPointPredicateUtils.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Dominators.h" _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits