diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 67f9f24c3b7a4..f927838c843ac 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -34,6 +34,7 @@ class DominatorTree; class GEPOperator; class WithOverflowInst; struct KnownBits; +struct KnownFPClass; class Loop; class LoopInfo; class MDNode; @@ -255,244 +256,6 @@ std::tuple fcmpImpliesClass(CmpInst::Predicate Pred, const Function &F, Value *LHS, const APFloat &RHS, bool LookThroughSrc = true); -struct KnownFPClass { - /// Floating-point classes the value could be one of. - FPClassTest KnownFPClasses = fcAllFlags; - - /// std::nullopt if the sign bit is unknown, true if the sign bit is - /// definitely set or false if the sign bit is definitely unset. - std::optional SignBit; - - bool operator==(KnownFPClass Other) const { - return KnownFPClasses == Other.KnownFPClasses && SignBit == Other.SignBit; - } - - /// Return true if it's known this can never be one of the mask entries. - bool isKnownNever(FPClassTest Mask) const { - return (KnownFPClasses & Mask) == fcNone; - } - - bool isKnownAlways(FPClassTest Mask) const { return isKnownNever(~Mask); } - - bool isUnknown() const { - return KnownFPClasses == fcAllFlags && !SignBit; - } - - /// Return true if it's known this can never be a nan. - bool isKnownNeverNaN() const { - return isKnownNever(fcNan); - } - - /// Return true if it's known this must always be a nan. - bool isKnownAlwaysNaN() const { return isKnownAlways(fcNan); } - - /// Return true if it's known this can never be an infinity. - bool isKnownNeverInfinity() const { - return isKnownNever(fcInf); - } - - /// Return true if it's known this can never be +infinity. - bool isKnownNeverPosInfinity() const { - return isKnownNever(fcPosInf); - } - - /// Return true if it's known this can never be -infinity. - bool isKnownNeverNegInfinity() const { - return isKnownNever(fcNegInf); - } - - /// Return true if it's known this can never be a subnormal - bool isKnownNeverSubnormal() const { - return isKnownNever(fcSubnormal); - } - - /// Return true if it's known this can never be a positive subnormal - bool isKnownNeverPosSubnormal() const { - return isKnownNever(fcPosSubnormal); - } - - /// Return true if it's known this can never be a negative subnormal - bool isKnownNeverNegSubnormal() const { - return isKnownNever(fcNegSubnormal); - } - - /// Return true if it's known this can never be a zero. This means a literal - /// [+-]0, and does not include denormal inputs implicitly treated as [+-]0. - bool isKnownNeverZero() const { - return isKnownNever(fcZero); - } - - /// Return true if it's known this can never be a literal positive zero. - bool isKnownNeverPosZero() const { - return isKnownNever(fcPosZero); - } - - /// Return true if it's known this can never be a negative zero. This means a - /// literal -0 and does not include denormal inputs implicitly treated as -0. - bool isKnownNeverNegZero() const { - return isKnownNever(fcNegZero); - } - - /// Return true if it's know this can never be interpreted as a zero. This - /// extends isKnownNeverZero to cover the case where the assumed - /// floating-point mode for the function interprets denormals as zero. - bool isKnownNeverLogicalZero(const Function &F, Type *Ty) const; - - /// Return true if it's know this can never be interpreted as a negative zero. - bool isKnownNeverLogicalNegZero(const Function &F, Type *Ty) const; - - /// Return true if it's know this can never be interpreted as a positive zero. - bool isKnownNeverLogicalPosZero(const Function &F, Type *Ty) const; - - static constexpr FPClassTest OrderedLessThanZeroMask = - fcNegSubnormal | fcNegNormal | fcNegInf; - static constexpr FPClassTest OrderedGreaterThanZeroMask = - fcPosSubnormal | fcPosNormal | fcPosInf; - - /// Return true if we can prove that the analyzed floating-point value is - /// either NaN or never less than -0.0. - /// - /// NaN --> true - /// +0 --> true - /// -0 --> true - /// x > +0 --> true - /// x < -0 --> false - bool cannotBeOrderedLessThanZero() const { - return isKnownNever(OrderedLessThanZeroMask); - } - - /// Return true if we can prove that the analyzed floating-point value is - /// either NaN or never greater than -0.0. - /// NaN --> true - /// +0 --> true - /// -0 --> true - /// x > +0 --> false - /// x < -0 --> true - bool cannotBeOrderedGreaterThanZero() const { - return isKnownNever(OrderedGreaterThanZeroMask); - } - - KnownFPClass &operator|=(const KnownFPClass &RHS) { - KnownFPClasses = KnownFPClasses | RHS.KnownFPClasses; - - if (SignBit != RHS.SignBit) - SignBit = std::nullopt; - return *this; - } - - void knownNot(FPClassTest RuleOut) { - KnownFPClasses = KnownFPClasses & ~RuleOut; - if (isKnownNever(fcNan) && !SignBit) { - if (isKnownNever(fcNegative)) - SignBit = false; - else if (isKnownNever(fcPositive)) - SignBit = true; - } - } - - void fneg() { - KnownFPClasses = llvm::fneg(KnownFPClasses); - if (SignBit) - SignBit = !*SignBit; - } - - void fabs() { - if (KnownFPClasses & fcNegZero) - KnownFPClasses |= fcPosZero; - - if (KnownFPClasses & fcNegInf) - KnownFPClasses |= fcPosInf; - - if (KnownFPClasses & fcNegSubnormal) - KnownFPClasses |= fcPosSubnormal; - - if (KnownFPClasses & fcNegNormal) - KnownFPClasses |= fcPosNormal; - - signBitMustBeZero(); - } - - /// Return true if the sign bit must be 0, ignoring the sign of nans. - bool signBitIsZeroOrNaN() const { - return isKnownNever(fcNegative); - } - - /// Assume the sign bit is zero. - void signBitMustBeZero() { - KnownFPClasses &= (fcPositive | fcNan); - SignBit = false; - } - - /// Assume the sign bit is one. - void signBitMustBeOne() { - KnownFPClasses &= (fcNegative | fcNan); - SignBit = true; - } - - void copysign(const KnownFPClass &Sign) { - // Don't know anything about the sign of the source. Expand the possible set - // to its opposite sign pair. - if (KnownFPClasses & fcZero) - KnownFPClasses |= fcZero; - if (KnownFPClasses & fcSubnormal) - KnownFPClasses |= fcSubnormal; - if (KnownFPClasses & fcNormal) - KnownFPClasses |= fcNormal; - if (KnownFPClasses & fcInf) - KnownFPClasses |= fcInf; - - // Sign bit is exactly preserved even for nans. - SignBit = Sign.SignBit; - - // Clear sign bits based on the input sign mask. - if (Sign.isKnownNever(fcPositive | fcNan) || (SignBit && *SignBit)) - KnownFPClasses &= (fcNegative | fcNan); - if (Sign.isKnownNever(fcNegative | fcNan) || (SignBit && !*SignBit)) - KnownFPClasses &= (fcPositive | fcNan); - } - - // Propagate knowledge that a non-NaN source implies the result can also not - // be a NaN. For unconstrained operations, signaling nans are not guaranteed - // to be quieted but cannot be introduced. - void propagateNaN(const KnownFPClass &Src, bool PreserveSign = false) { - if (Src.isKnownNever(fcNan)) { - knownNot(fcNan); - if (PreserveSign) - SignBit = Src.SignBit; - } else if (Src.isKnownNever(fcSNan)) - knownNot(fcSNan); - } - - /// Propagate knowledge from a source value that could be a denormal or - /// zero. We have to be conservative since output flushing is not guaranteed, - /// so known-never-zero may not hold. - /// - /// This assumes a copy-like operation and will replace any currently known - /// information. - void propagateDenormal(const KnownFPClass &Src, const Function &F, Type *Ty); - - /// Report known classes if \p Src is evaluated through a potentially - /// canonicalizing operation. We can assume signaling nans will not be - /// introduced, but cannot assume a denormal will be flushed under FTZ/DAZ. - /// - /// This assumes a copy-like operation and will replace any currently known - /// information. - void propagateCanonicalizingSrc(const KnownFPClass &Src, const Function &F, - Type *Ty); - - void resetAll() { *this = KnownFPClass(); } -}; - -inline KnownFPClass operator|(KnownFPClass LHS, const KnownFPClass &RHS) { - LHS |= RHS; - return LHS; -} - -inline KnownFPClass operator|(const KnownFPClass &LHS, KnownFPClass &&RHS) { - RHS |= LHS; - return std::move(RHS); -} - /// Determine which floating-point classes are valid for \p V, and return them /// in KnownFPClass bit sets. /// @@ -510,56 +273,30 @@ KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, KnownFPClass computeKnownFPClass(const Value *V, FPClassTest InterestedClasses, unsigned Depth, const SimplifyQuery &SQ); -inline KnownFPClass computeKnownFPClass( - const Value *V, const DataLayout &DL, - FPClassTest InterestedClasses = fcAllFlags, unsigned Depth = 0, - const TargetLibraryInfo *TLI = nullptr, AssumptionCache *AC = nullptr, - const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr, - bool UseInstrInfo = true) { - return computeKnownFPClass( - V, InterestedClasses, Depth, - SimplifyQuery(DL, TLI, DT, AC, CxtI, UseInstrInfo)); -} +KnownFPClass computeKnownFPClass(const Value *V, const DataLayout &DL, + FPClassTest InterestedClasses = fcAllFlags, + unsigned Depth = 0, + const TargetLibraryInfo *TLI = nullptr, + AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr, + const DominatorTree *DT = nullptr, + bool UseInstrInfo = true); /// Wrapper to account for known fast math flags at the use instruction. -inline KnownFPClass -computeKnownFPClass(const Value *V, const APInt &DemandedElts, - FastMathFlags FMF, FPClassTest InterestedClasses, - unsigned Depth, const SimplifyQuery &SQ) { - if (FMF.noNaNs()) - InterestedClasses &= ~fcNan; - if (FMF.noInfs()) - InterestedClasses &= ~fcInf; - - KnownFPClass Result = - computeKnownFPClass(V, DemandedElts, InterestedClasses, Depth, SQ); - - if (FMF.noNaNs()) - Result.KnownFPClasses &= ~fcNan; - if (FMF.noInfs()) - Result.KnownFPClasses &= ~fcInf; - return Result; -} +KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, + FastMathFlags FMF, + FPClassTest InterestedClasses, unsigned Depth, + const SimplifyQuery &SQ); -inline KnownFPClass computeKnownFPClass(const Value *V, FastMathFlags FMF, - FPClassTest InterestedClasses, - unsigned Depth, - const SimplifyQuery &SQ) { - auto *FVTy = dyn_cast(V->getType()); - APInt DemandedElts = - FVTy ? APInt::getAllOnes(FVTy->getNumElements()) : APInt(1, 1); - return computeKnownFPClass(V, DemandedElts, FMF, InterestedClasses, Depth, - SQ); -} +KnownFPClass computeKnownFPClass(const Value *V, FastMathFlags FMF, + FPClassTest InterestedClasses, unsigned Depth, + const SimplifyQuery &SQ); /// Return true if we can prove that the specified FP value is never equal to /// -0.0. Users should use caution when considering PreserveSign /// denormal-fp-math. -inline bool cannotBeNegativeZero(const Value *V, unsigned Depth, - const SimplifyQuery &SQ) { - KnownFPClass Known = computeKnownFPClass(V, fcNegZero, Depth, SQ); - return Known.isKnownNeverNegZero(); -} +bool cannotBeNegativeZero(const Value *V, unsigned Depth, + const SimplifyQuery &SQ); /// Return true if we can prove that the specified FP value is either NaN or /// never less than -0.0. @@ -569,46 +306,29 @@ inline bool cannotBeNegativeZero(const Value *V, unsigned Depth, /// -0 --> true /// x > +0 --> true /// x < -0 --> false -inline bool cannotBeOrderedLessThanZero(const Value *V, unsigned Depth, - const SimplifyQuery &SQ) { - KnownFPClass Known = - computeKnownFPClass(V, KnownFPClass::OrderedLessThanZeroMask, Depth, SQ); - return Known.cannotBeOrderedLessThanZero(); -} +bool cannotBeOrderedLessThanZero(const Value *V, unsigned Depth, + const SimplifyQuery &SQ); /// Return true if the floating-point scalar value is not an infinity or if /// the floating-point vector value has no infinities. Return false if a value /// could ever be infinity. -inline bool isKnownNeverInfinity(const Value *V, unsigned Depth, - const SimplifyQuery &SQ) { - KnownFPClass Known = computeKnownFPClass(V, fcInf, Depth, SQ); - return Known.isKnownNeverInfinity(); -} +bool isKnownNeverInfinity(const Value *V, unsigned Depth, + const SimplifyQuery &SQ); /// Return true if the floating-point value can never contain a NaN or infinity. -inline bool isKnownNeverInfOrNaN(const Value *V, unsigned Depth, - const SimplifyQuery &SQ) { - KnownFPClass Known = computeKnownFPClass(V, fcInf | fcNan, Depth, SQ); - return Known.isKnownNeverNaN() && Known.isKnownNeverInfinity(); -} +bool isKnownNeverInfOrNaN(const Value *V, unsigned Depth, + const SimplifyQuery &SQ); /// Return true if the floating-point scalar value is not a NaN or if the /// floating-point vector value has no NaN elements. Return false if a value /// could ever be NaN. -inline bool isKnownNeverNaN(const Value *V, unsigned Depth, - const SimplifyQuery &SQ) { - KnownFPClass Known = computeKnownFPClass(V, fcNan, Depth, SQ); - return Known.isKnownNeverNaN(); -} +bool isKnownNeverNaN(const Value *V, unsigned Depth, const SimplifyQuery &SQ); /// Return false if we can prove that the specified FP value's sign bit is 0. /// Return true if we can prove that the specified FP value's sign bit is 1. /// Otherwise return std::nullopt. -inline std::optional computeKnownFPSignBit(const Value *V, unsigned Depth, - const SimplifyQuery &SQ) { - KnownFPClass Known = computeKnownFPClass(V, fcAllFlags, Depth, SQ); - return Known.SignBit; -} +std::optional computeKnownFPSignBit(const Value *V, unsigned Depth, + const SimplifyQuery &SQ); /// If the specified value can be set by repeating the same byte in memory, /// return the i8 value that it is represented with. This is true for all i8 diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h new file mode 100644 index 0000000000000..9ebdf260e0ec7 --- /dev/null +++ b/llvm/include/llvm/Support/KnownFPClass.h @@ -0,0 +1,237 @@ +//===- llvm/Support/KnownFPClass.h - Stores known fpclass -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains a class for representing known fpclasses used by +// computeKnownFPClass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_KNOWNFPCLASS_H +#define LLVM_SUPPORT_KNOWNFPCLASS_H + +#include "llvm/ADT/FloatingPointMode.h" +#include + +namespace llvm { + +struct KnownFPClass { + /// Floating-point classes the value could be one of. + FPClassTest KnownFPClasses = fcAllFlags; + + /// std::nullopt if the sign bit is unknown, true if the sign bit is + /// definitely set or false if the sign bit is definitely unset. + std::optional SignBit; + + bool operator==(KnownFPClass Other) const { + return KnownFPClasses == Other.KnownFPClasses && SignBit == Other.SignBit; + } + + /// Return true if it's known this can never be one of the mask entries. + bool isKnownNever(FPClassTest Mask) const { + return (KnownFPClasses & Mask) == fcNone; + } + + bool isKnownAlways(FPClassTest Mask) const { return isKnownNever(~Mask); } + + bool isUnknown() const { return KnownFPClasses == fcAllFlags && !SignBit; } + + /// Return true if it's known this can never be a nan. + bool isKnownNeverNaN() const { return isKnownNever(fcNan); } + + /// Return true if it's known this must always be a nan. + bool isKnownAlwaysNaN() const { return isKnownAlways(fcNan); } + + /// Return true if it's known this can never be an infinity. + bool isKnownNeverInfinity() const { return isKnownNever(fcInf); } + + /// Return true if it's known this can never be +infinity. + bool isKnownNeverPosInfinity() const { return isKnownNever(fcPosInf); } + + /// Return true if it's known this can never be -infinity. + bool isKnownNeverNegInfinity() const { return isKnownNever(fcNegInf); } + + /// Return true if it's known this can never be a subnormal + bool isKnownNeverSubnormal() const { return isKnownNever(fcSubnormal); } + + /// Return true if it's known this can never be a positive subnormal + bool isKnownNeverPosSubnormal() const { return isKnownNever(fcPosSubnormal); } + + /// Return true if it's known this can never be a negative subnormal + bool isKnownNeverNegSubnormal() const { return isKnownNever(fcNegSubnormal); } + + /// Return true if it's known this can never be a zero. This means a literal + /// [+-]0, and does not include denormal inputs implicitly treated as [+-]0. + bool isKnownNeverZero() const { return isKnownNever(fcZero); } + + /// Return true if it's known this can never be a literal positive zero. + bool isKnownNeverPosZero() const { return isKnownNever(fcPosZero); } + + /// Return true if it's known this can never be a negative zero. This means a + /// literal -0 and does not include denormal inputs implicitly treated as -0. + bool isKnownNeverNegZero() const { return isKnownNever(fcNegZero); } + + /// Return true if it's know this can never be interpreted as a zero. This + /// extends isKnownNeverZero to cover the case where the assumed + /// floating-point mode for the function interprets denormals as zero. + bool isKnownNeverLogicalZero(DenormalMode Mode) const; + + /// Return true if it's know this can never be interpreted as a negative zero. + bool isKnownNeverLogicalNegZero(DenormalMode Mode) const; + + /// Return true if it's know this can never be interpreted as a positive zero. + bool isKnownNeverLogicalPosZero(DenormalMode Mode) const; + + static constexpr FPClassTest OrderedLessThanZeroMask = + fcNegSubnormal | fcNegNormal | fcNegInf; + static constexpr FPClassTest OrderedGreaterThanZeroMask = + fcPosSubnormal | fcPosNormal | fcPosInf; + + /// Return true if we can prove that the analyzed floating-point value is + /// either NaN or never less than -0.0. + /// + /// NaN --> true + /// +0 --> true + /// -0 --> true + /// x > +0 --> true + /// x < -0 --> false + bool cannotBeOrderedLessThanZero() const { + return isKnownNever(OrderedLessThanZeroMask); + } + + /// Return true if we can prove that the analyzed floating-point value is + /// either NaN or never greater than -0.0. + /// NaN --> true + /// +0 --> true + /// -0 --> true + /// x > +0 --> false + /// x < -0 --> true + bool cannotBeOrderedGreaterThanZero() const { + return isKnownNever(OrderedGreaterThanZeroMask); + } + + KnownFPClass &operator|=(const KnownFPClass &RHS) { + KnownFPClasses = KnownFPClasses | RHS.KnownFPClasses; + + if (SignBit != RHS.SignBit) + SignBit = std::nullopt; + return *this; + } + + void knownNot(FPClassTest RuleOut) { + KnownFPClasses = KnownFPClasses & ~RuleOut; + if (isKnownNever(fcNan) && !SignBit) { + if (isKnownNever(fcNegative)) + SignBit = false; + else if (isKnownNever(fcPositive)) + SignBit = true; + } + } + + void fneg() { + KnownFPClasses = llvm::fneg(KnownFPClasses); + if (SignBit) + SignBit = !*SignBit; + } + + void fabs() { + if (KnownFPClasses & fcNegZero) + KnownFPClasses |= fcPosZero; + + if (KnownFPClasses & fcNegInf) + KnownFPClasses |= fcPosInf; + + if (KnownFPClasses & fcNegSubnormal) + KnownFPClasses |= fcPosSubnormal; + + if (KnownFPClasses & fcNegNormal) + KnownFPClasses |= fcPosNormal; + + signBitMustBeZero(); + } + + /// Return true if the sign bit must be 0, ignoring the sign of nans. + bool signBitIsZeroOrNaN() const { return isKnownNever(fcNegative); } + + /// Assume the sign bit is zero. + void signBitMustBeZero() { + KnownFPClasses &= (fcPositive | fcNan); + SignBit = false; + } + + /// Assume the sign bit is one. + void signBitMustBeOne() { + KnownFPClasses &= (fcNegative | fcNan); + SignBit = true; + } + + void copysign(const KnownFPClass &Sign) { + // Don't know anything about the sign of the source. Expand the possible set + // to its opposite sign pair. + if (KnownFPClasses & fcZero) + KnownFPClasses |= fcZero; + if (KnownFPClasses & fcSubnormal) + KnownFPClasses |= fcSubnormal; + if (KnownFPClasses & fcNormal) + KnownFPClasses |= fcNormal; + if (KnownFPClasses & fcInf) + KnownFPClasses |= fcInf; + + // Sign bit is exactly preserved even for nans. + SignBit = Sign.SignBit; + + // Clear sign bits based on the input sign mask. + if (Sign.isKnownNever(fcPositive | fcNan) || (SignBit && *SignBit)) + KnownFPClasses &= (fcNegative | fcNan); + if (Sign.isKnownNever(fcNegative | fcNan) || (SignBit && !*SignBit)) + KnownFPClasses &= (fcPositive | fcNan); + } + + // Propagate knowledge that a non-NaN source implies the result can also not + // be a NaN. For unconstrained operations, signaling nans are not guaranteed + // to be quieted but cannot be introduced. + void propagateNaN(const KnownFPClass &Src, bool PreserveSign = false) { + if (Src.isKnownNever(fcNan)) { + knownNot(fcNan); + if (PreserveSign) + SignBit = Src.SignBit; + } else if (Src.isKnownNever(fcSNan)) + knownNot(fcSNan); + } + + /// Propagate knowledge from a source value that could be a denormal or + /// zero. We have to be conservative since output flushing is not guaranteed, + /// so known-never-zero may not hold. + /// + /// This assumes a copy-like operation and will replace any currently known + /// information. + void propagateDenormal(const KnownFPClass &Src, DenormalMode Mode); + + /// Report known classes if \p Src is evaluated through a potentially + /// canonicalizing operation. We can assume signaling nans will not be + /// introduced, but cannot assume a denormal will be flushed under FTZ/DAZ. + /// + /// This assumes a copy-like operation and will replace any currently known + /// information. + void propagateCanonicalizingSrc(const KnownFPClass &Src, DenormalMode Mode); + + void resetAll() { *this = KnownFPClass(); } +}; + +inline KnownFPClass operator|(KnownFPClass LHS, const KnownFPClass &RHS) { + LHS |= RHS; + return LHS; +} + +inline KnownFPClass operator|(const KnownFPClass &LHS, KnownFPClass &&RHS) { + RHS |= LHS; + return std::move(RHS); +} + +} // namespace llvm + +#endif diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 1c33c6bebdd1b..718d272dd0ac7 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -43,6 +43,7 @@ #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Statepoint.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include #include using namespace llvm; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 880781742fae0..fc0c74942c6d8 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -71,6 +71,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Support/MathExtras.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include @@ -4471,91 +4472,12 @@ static bool inputDenormalIsIEEE(const Function &F, const Type *Ty) { return F.getDenormalMode(Ty->getFltSemantics()).Input == DenormalMode::IEEE; } -static bool inputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { - Ty = Ty->getScalarType(); - DenormalMode Mode = F.getDenormalMode(Ty->getFltSemantics()); - return Mode.Input == DenormalMode::IEEE || - Mode.Input == DenormalMode::PositiveZero; -} - static bool outputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { Ty = Ty->getScalarType(); DenormalMode Mode = F.getDenormalMode(Ty->getFltSemantics()); return Mode.Output == DenormalMode::IEEE || Mode.Output == DenormalMode::PositiveZero; } - -bool KnownFPClass::isKnownNeverLogicalZero(const Function &F, Type *Ty) const { - return isKnownNeverZero() && - (isKnownNeverSubnormal() || inputDenormalIsIEEE(F, Ty)); -} - -bool KnownFPClass::isKnownNeverLogicalNegZero(const Function &F, - Type *Ty) const { - return isKnownNeverNegZero() && - (isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(F, Ty)); -} - -bool KnownFPClass::isKnownNeverLogicalPosZero(const Function &F, - Type *Ty) const { - if (!isKnownNeverPosZero()) - return false; - - // If we know there are no denormals, nothing can be flushed to zero. - if (isKnownNeverSubnormal()) - return true; - - DenormalMode Mode = F.getDenormalMode(Ty->getScalarType()->getFltSemantics()); - switch (Mode.Input) { - case DenormalMode::IEEE: - return true; - case DenormalMode::PreserveSign: - // Negative subnormal won't flush to +0 - return isKnownNeverPosSubnormal(); - case DenormalMode::PositiveZero: - default: - // Both positive and negative subnormal could flush to +0 - return false; - } - - llvm_unreachable("covered switch over denormal mode"); -} - -void KnownFPClass::propagateDenormal(const KnownFPClass &Src, const Function &F, - Type *Ty) { - KnownFPClasses = Src.KnownFPClasses; - // If we aren't assuming the source can't be a zero, we don't have to check if - // a denormal input could be flushed. - if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero()) - return; - - // If we know the input can't be a denormal, it can't be flushed to 0. - if (Src.isKnownNeverSubnormal()) - return; - - DenormalMode Mode = F.getDenormalMode(Ty->getScalarType()->getFltSemantics()); - - if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE()) - KnownFPClasses |= fcPosZero; - - if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) { - if (Mode != DenormalMode::getPositiveZero()) - KnownFPClasses |= fcNegZero; - - if (Mode.Input == DenormalMode::PositiveZero || - Mode.Output == DenormalMode::PositiveZero || - Mode.Input == DenormalMode::Dynamic || - Mode.Output == DenormalMode::Dynamic) - KnownFPClasses |= fcPosZero; - } -} - -void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src, - const Function &F, Type *Ty) { - propagateDenormal(Src, F, Ty); - propagateNaN(Src, /*PreserveSign=*/true); -} - /// Given an exploded icmp instruction, return true if the comparison only /// checks the sign bit. If it only checks the sign bit, set TrueIfSigned if /// the result of the comparison is true when the input value is signed. @@ -5378,8 +5300,12 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, // If the input denormal mode could be PreserveSign, a negative // subnormal input could produce a negative zero output. const Function *F = II->getFunction(); + const fltSemantics &FltSem = + II->getType()->getScalarType()->getFltSemantics(); + if (Q.IIQ.hasNoSignedZeros(II) || - (F && KnownSrc.isKnownNeverLogicalNegZero(*F, II->getType()))) + (F && + KnownSrc.isKnownNeverLogicalNegZero(F->getDenormalMode(FltSem)))) Known.knownNot(fcNegZero); break; @@ -5639,7 +5565,15 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, Known.knownNot(fcNan); const Function *F = II->getFunction(); - if (F && KnownSrc.isKnownNeverLogicalZero(*F, II->getType())) + + if (!F) + break; + + const fltSemantics &FltSem = + II->getType()->getScalarType()->getFltSemantics(); + DenormalMode Mode = F->getDenormalMode(FltSem); + + if (KnownSrc.isKnownNeverLogicalZero(Mode)) Known.knownNot(fcNegInf); break; @@ -5712,9 +5646,11 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, const Function *F = II->getFunction(); const APInt *ConstVal = ExpRange.getSingleElement(); + const fltSemantics &FltSem = + II->getType()->getScalarType()->getFltSemantics(); if (ConstVal && ConstVal->isZero()) { // ldexp(x, 0) -> x, so propagate everything. - Known.propagateCanonicalizingSrc(KnownSrc, *F, II->getType()); + Known.propagateCanonicalizingSrc(KnownSrc, F->getDenormalMode(FltSem)); } else if (ExpRange.isAllNegative()) { // If we know the power is <= 0, can't introduce inf if (KnownSrc.isKnownNeverPosInfinity()) @@ -5727,9 +5663,11 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, Known.knownNot(fcPosSubnormal); if (KnownSrc.isKnownNeverNegSubnormal()) Known.knownNot(fcNegSubnormal); - if (F && KnownSrc.isKnownNeverLogicalPosZero(*F, II->getType())) + if (F && + KnownSrc.isKnownNeverLogicalPosZero(F->getDenormalMode(FltSem))) Known.knownNot(fcPosZero); - if (F && KnownSrc.isKnownNeverLogicalNegZero(*F, II->getType())) + if (F && + KnownSrc.isKnownNeverLogicalNegZero(F->getDenormalMode(FltSem))) Known.knownNot(fcNegZero); } @@ -5806,9 +5744,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, if (!F) break; + const fltSemantics &FltSem = + Op->getType()->getScalarType()->getFltSemantics(); + DenormalMode Mode = F->getDenormalMode(FltSem); + // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0. - if ((KnownLHS.isKnownNeverLogicalNegZero(*F, Op->getType()) || - KnownRHS.isKnownNeverLogicalNegZero(*F, Op->getType())) && + if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) || + KnownRHS.isKnownNeverLogicalNegZero(Mode)) && // Make sure output negative denormal can't flush to -0 outputDenormalIsIEEEOrPosZero(*F, Op->getType())) Known.knownNot(fcNegZero); @@ -5816,9 +5758,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, if (!F) break; + const fltSemantics &FltSem = + Op->getType()->getScalarType()->getFltSemantics(); + DenormalMode Mode = F->getDenormalMode(FltSem); + // Only fsub -0, +0 can return -0 - if ((KnownLHS.isKnownNeverLogicalNegZero(*F, Op->getType()) || - KnownRHS.isKnownNeverLogicalPosZero(*F, Op->getType())) && + if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) || + KnownRHS.isKnownNeverLogicalPosZero(Mode)) && // Make sure output negative denormal can't flush to -0 outputDenormalIsIEEEOrPosZero(*F, Op->getType())) Known.knownNot(fcNegZero); @@ -5866,10 +5812,14 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, if (!F) break; + Type *OpTy = Op->getType()->getScalarType(); + const fltSemantics &FltSem = OpTy->getFltSemantics(); + DenormalMode Mode = F->getDenormalMode(FltSem); + if ((KnownRHS.isKnownNeverInfinity() || - KnownLHS.isKnownNeverLogicalZero(*F, Op->getType())) && + KnownLHS.isKnownNeverLogicalZero(Mode)) && (KnownLHS.isKnownNeverInfinity() || - KnownRHS.isKnownNeverLogicalZero(*F, Op->getType()))) + KnownRHS.isKnownNeverLogicalZero(Mode))) Known.knownNot(fcNan); break; @@ -5916,14 +5866,18 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, } const Function *F = cast(Op)->getFunction(); + const fltSemantics &FltSem = + Op->getType()->getScalarType()->getFltSemantics(); if (Op->getOpcode() == Instruction::FDiv) { // Only 0/0, Inf/Inf produce NaN. if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()) && - ((F && KnownLHS.isKnownNeverLogicalZero(*F, Op->getType())) || - (F && KnownRHS.isKnownNeverLogicalZero(*F, Op->getType())))) { + ((F && + KnownLHS.isKnownNeverLogicalZero(F->getDenormalMode(FltSem))) || + (F && + KnownRHS.isKnownNeverLogicalZero(F->getDenormalMode(FltSem))))) { Known.knownNot(fcNan); } @@ -5935,7 +5889,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, // Inf REM x and x REM 0 produce NaN. if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && KnownLHS.isKnownNeverInfinity() && F && - KnownRHS.isKnownNeverLogicalZero(*F, Op->getType())) { + KnownRHS.isKnownNeverLogicalZero(F->getDenormalMode(FltSem))) { Known.knownNot(fcNan); } @@ -6113,11 +6067,14 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, InterestedClasses, KnownSrc, Depth + 1, Q); const Function *F = cast(Op)->getFunction(); + const fltSemantics &FltSem = + Op->getType()->getScalarType()->getFltSemantics(); if (KnownSrc.isKnownNever(fcNegative)) Known.knownNot(fcNegative); else { - if (F && KnownSrc.isKnownNeverLogicalNegZero(*F, Op->getType())) + if (F && + KnownSrc.isKnownNeverLogicalNegZero(F->getDenormalMode(FltSem))) Known.knownNot(fcNegZero); if (KnownSrc.isKnownNever(fcNegInf)) Known.knownNot(fcNegInf); @@ -6126,7 +6083,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, if (KnownSrc.isKnownNever(fcPositive)) Known.knownNot(fcPositive); else { - if (F && KnownSrc.isKnownNeverLogicalPosZero(*F, Op->getType())) + if (F && + KnownSrc.isKnownNeverLogicalPosZero(F->getDenormalMode(FltSem))) Known.knownNot(fcPosZero); if (KnownSrc.isKnownNever(fcPosInf)) Known.knownNot(fcPosInf); @@ -6273,6 +6231,89 @@ KnownFPClass llvm::computeKnownFPClass(const Value *V, return Known; } +KnownFPClass llvm::computeKnownFPClass( + const Value *V, const DataLayout &DL, FPClassTest InterestedClasses, + unsigned Depth, const TargetLibraryInfo *TLI, AssumptionCache *AC, + const Instruction *CxtI, const DominatorTree *DT, bool UseInstrInfo) { + return computeKnownFPClass( + V, InterestedClasses, Depth, + SimplifyQuery(DL, TLI, DT, AC, CxtI, UseInstrInfo)); +} + +KnownFPClass +llvm::computeKnownFPClass(const Value *V, const APInt &DemandedElts, + FastMathFlags FMF, FPClassTest InterestedClasses, + unsigned Depth, const SimplifyQuery &SQ) { + if (FMF.noNaNs()) + InterestedClasses &= ~fcNan; + if (FMF.noInfs()) + InterestedClasses &= ~fcInf; + + KnownFPClass Result = + computeKnownFPClass(V, DemandedElts, InterestedClasses, Depth, SQ); + + if (FMF.noNaNs()) + Result.KnownFPClasses &= ~fcNan; + if (FMF.noInfs()) + Result.KnownFPClasses &= ~fcInf; + return Result; +} + +KnownFPClass llvm::computeKnownFPClass(const Value *V, FastMathFlags FMF, + FPClassTest InterestedClasses, + unsigned Depth, + const SimplifyQuery &SQ) { + auto *FVTy = dyn_cast(V->getType()); + APInt DemandedElts = + FVTy ? APInt::getAllOnes(FVTy->getNumElements()) : APInt(1, 1); + return computeKnownFPClass(V, DemandedElts, FMF, InterestedClasses, Depth, + SQ); +} + +bool llvm::cannotBeNegativeZero(const Value *V, unsigned Depth, + const SimplifyQuery &SQ) { + KnownFPClass Known = computeKnownFPClass(V, fcNegZero, Depth, SQ); + return Known.isKnownNeverNegZero(); +} + +bool llvm::cannotBeOrderedLessThanZero(const Value *V, unsigned Depth, + const SimplifyQuery &SQ) { + KnownFPClass Known = + computeKnownFPClass(V, KnownFPClass::OrderedLessThanZeroMask, Depth, SQ); + return Known.cannotBeOrderedLessThanZero(); +} + +bool llvm::isKnownNeverInfinity(const Value *V, unsigned Depth, + const SimplifyQuery &SQ) { + KnownFPClass Known = computeKnownFPClass(V, fcInf, Depth, SQ); + return Known.isKnownNeverInfinity(); +} + +/// Return true if the floating-point value can never contain a NaN or infinity. +bool llvm::isKnownNeverInfOrNaN(const Value *V, unsigned Depth, + const SimplifyQuery &SQ) { + KnownFPClass Known = computeKnownFPClass(V, fcInf | fcNan, Depth, SQ); + return Known.isKnownNeverNaN() && Known.isKnownNeverInfinity(); +} + +/// Return true if the floating-point scalar value is not a NaN or if the +/// floating-point vector value has no NaN elements. Return false if a value +/// could ever be NaN. +bool llvm::isKnownNeverNaN(const Value *V, unsigned Depth, + const SimplifyQuery &SQ) { + KnownFPClass Known = computeKnownFPClass(V, fcNan, Depth, SQ); + return Known.isKnownNeverNaN(); +} + +/// Return false if we can prove that the specified FP value's sign bit is 0. +/// Return true if we can prove that the specified FP value's sign bit is 1. +/// Otherwise return std::nullopt. +std::optional llvm::computeKnownFPSignBit(const Value *V, unsigned Depth, + const SimplifyQuery &SQ) { + KnownFPClass Known = computeKnownFPClass(V, fcAllFlags, Depth, SQ); + return Known.SignBit; +} + Value *llvm::isBytewiseValue(Value *V, const DataLayout &DL) { // All byte-wide stores are splatable, even of arbitrary variables. diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 2754c97fce6c1..98ffd829d80b8 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -207,6 +207,7 @@ add_llvm_component_library(LLVMSupport IntervalMap.cpp JSON.cpp KnownBits.cpp + KnownFPClass.cpp LEB128.cpp LineIterator.cpp Locale.cpp diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp new file mode 100644 index 0000000000000..43fb2e7108d2b --- /dev/null +++ b/llvm/lib/Support/KnownFPClass.cpp @@ -0,0 +1,94 @@ +//===- llvm/Support/KnownFPClass.h - Stores known fplcass -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains a class for representing known fpclasses used by +// computeKnownFPClass. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/KnownFPClass.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +/// Return true if it's possible to assume IEEE treatment of input denormals in +/// \p F for \p Val. +static bool inputDenormalIsIEEE(DenormalMode Mode) { + return Mode.Input == DenormalMode::IEEE; +} + +static bool inputDenormalIsIEEEOrPosZero(DenormalMode Mode) { + return Mode.Input == DenormalMode::IEEE || + Mode.Input == DenormalMode::PositiveZero; +} + +bool KnownFPClass::isKnownNeverLogicalZero(DenormalMode Mode) const { + return isKnownNeverZero() && + (isKnownNeverSubnormal() || inputDenormalIsIEEE(Mode)); +} + +bool KnownFPClass::isKnownNeverLogicalNegZero(DenormalMode Mode) const { + return isKnownNeverNegZero() && + (isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(Mode)); +} + +bool KnownFPClass::isKnownNeverLogicalPosZero(DenormalMode Mode) const { + if (!isKnownNeverPosZero()) + return false; + + // If we know there are no denormals, nothing can be flushed to zero. + if (isKnownNeverSubnormal()) + return true; + + switch (Mode.Input) { + case DenormalMode::IEEE: + return true; + case DenormalMode::PreserveSign: + // Negative subnormal won't flush to +0 + return isKnownNeverPosSubnormal(); + case DenormalMode::PositiveZero: + default: + // Both positive and negative subnormal could flush to +0 + return false; + } + + llvm_unreachable("covered switch over denormal mode"); +} + +void KnownFPClass::propagateDenormal(const KnownFPClass &Src, + DenormalMode Mode) { + KnownFPClasses = Src.KnownFPClasses; + // If we aren't assuming the source can't be a zero, we don't have to check if + // a denormal input could be flushed. + if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero()) + return; + + // If we know the input can't be a denormal, it can't be flushed to 0. + if (Src.isKnownNeverSubnormal()) + return; + + if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE()) + KnownFPClasses |= fcPosZero; + + if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) { + if (Mode != DenormalMode::getPositiveZero()) + KnownFPClasses |= fcNegZero; + + if (Mode.Input == DenormalMode::PositiveZero || + Mode.Output == DenormalMode::PositiveZero || + Mode.Input == DenormalMode::Dynamic || + Mode.Output == DenormalMode::Dynamic) + KnownFPClasses |= fcPosZero; + } +} + +void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src, + DenormalMode Mode) { + propagateDenormal(Src, Mode); + propagateNaN(Src, /*PreserveSign=*/true); +} diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp index fdba8835cbf0a..0b7c5236ce4f5 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp @@ -29,6 +29,7 @@ #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Transforms/Utils/IntegerDivision.h" #include "llvm/Transforms/Utils/Local.h" diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index cb794adaba79a..0b39c8061b594 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -63,6 +63,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TypeSize.h" #include "llvm/Support/raw_ostream.h" diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 12dd4cec85f59..38519d81fce8d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -62,6 +62,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/InstCombine/InstCombiner.h" diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 5b2af39e69f2c..9923719c3443d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -15,8 +15,8 @@ #ifndef LLVM_LIB_TRANSFORMS_INSTCOMBINE_INSTCOMBINEINTERNAL_H #define LLVM_LIB_TRANSFORMS_INSTCOMBINE_INSTCOMBINEINTERNAL_H -#include "llvm/ADT/Statistic.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/TargetFolder.h" #include "llvm/Analysis/ValueTracking.h" @@ -26,6 +26,7 @@ #include "llvm/IR/Value.h" #include "llvm/Support/Debug.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Transforms/InstCombine/InstCombiner.h" #include "llvm/Transforms/Utils/Local.h" #include diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index d998816a8c2e5..3a2fa154b0fdd 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -94,6 +94,7 @@ #include "llvm/Support/DebugCounter.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index ecb107602f854..2d0027d976019 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/SimplifyLibCalls.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -31,6 +32,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Support/MathExtras.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/BuildLibCalls.h" @@ -2575,8 +2577,10 @@ Value *LibCallSimplifier::optimizeLog(CallInst *Log, IRBuilderBase &B) { KnownFPClass::OrderedLessThanZeroMask | fcSubnormal, /*Depth=*/0, SQ); Function *F = Log->getParent()->getParent(); - IsKnownNoErrno = Known.cannotBeOrderedLessThanZero() && - Known.isKnownNeverLogicalZero(*F, Ty); + const fltSemantics &FltSem = Ty->getScalarType()->getFltSemantics(); + IsKnownNoErrno = + Known.cannotBeOrderedLessThanZero() && + Known.isKnownNeverLogicalZero(F->getDenormalMode(FltSem)); } if (IsKnownNoErrno) { auto *NewLog = B.CreateUnaryIntrinsic(LogID, Log->getArgOperand(0), Log); @@ -2806,7 +2810,9 @@ Value *LibCallSimplifier::optimizeFMod(CallInst *CI, IRBuilderBase &B) { computeKnownFPClass(CI->getOperand(1), fcZero | fcSubnormal, /*Depth=*/0, SQ); Function *F = CI->getParent()->getParent(); - IsNoNan = Known1.isKnownNeverLogicalZero(*F, CI->getType()); + const fltSemantics &FltSem = + CI->getType()->getScalarType()->getFltSemantics(); + IsNoNan = Known1.isKnownNeverLogicalZero(F->getDenormalMode(FltSem)); } } diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp index 50e5e0e6b2ff5..285f342092897 100644 --- a/llvm/unittests/Analysis/ValueTrackingTest.cpp +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -19,6 +19,7 @@ #include "llvm/IR/Module.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Support/KnownFPClass.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Transforms/Utils/Local.h" #include "gtest/gtest.h" diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn index fe7ff6ef68f99..3a9f43b1070a7 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn @@ -102,6 +102,7 @@ static_library("Support") { "IntervalMap.cpp", "JSON.cpp", "KnownBits.cpp", + "KnownFPClass.cpp", "LEB128.cpp", "LineIterator.cpp", "Locale.cpp",