[llvm] [Analysis][NFC] Extract KnownFPClass (PR #133457)
Tim Gymnich via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 28 08:39:24 PDT 2025
https://github.com/tgymnich updated https://github.com/llvm/llvm-project/pull/133457
>From 22dbc421269e1e9897f1878f8bd005b3fd9273d5 Mon Sep 17 00:00:00 2001
From: Tim Gymnich <tim at gymni.ch>
Date: Sat, 22 Mar 2025 13:35:00 +0100
Subject: [PATCH 1/2] [Analysis] Extract KnownFPClass
---
llvm/include/llvm/Analysis/ValueTracking.h | 334 ++----------------
llvm/include/llvm/Support/KnownFPClass.h | 237 +++++++++++++
llvm/lib/Analysis/InstructionSimplify.cpp | 1 +
llvm/lib/Analysis/ValueTracking.cpp | 231 +++++++-----
llvm/lib/Support/CMakeLists.txt | 1 +
llvm/lib/Support/KnownFPClass.cpp | 94 +++++
.../Target/AMDGPU/AMDGPUCodeGenPrepare.cpp | 1 +
.../Transforms/IPO/AttributorAttributes.cpp | 1 +
.../InstCombine/InstCombineCalls.cpp | 1 +
.../InstCombine/InstCombineInternal.h | 3 +-
.../InstCombine/InstructionCombining.cpp | 1 +
.../lib/Transforms/Utils/SimplifyLibCalls.cpp | 12 +-
llvm/unittests/Analysis/ValueTrackingTest.cpp | 1 +
.../gn/secondary/llvm/lib/Support/BUILD.gn | 1 +
14 files changed, 513 insertions(+), 406 deletions(-)
create mode 100644 llvm/include/llvm/Support/KnownFPClass.h
create mode 100644 llvm/lib/Support/KnownFPClass.cpp
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<Value *, FPClassTest, FPClassTest>
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<bool> 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<FixedVectorType>(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<bool> computeKnownFPSignBit(const Value *V, unsigned Depth,
- const SimplifyQuery &SQ) {
- KnownFPClass Known = computeKnownFPClass(V, fcAllFlags, Depth, SQ);
- return Known.SignBit;
-}
+std::optional<bool> 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..9a0afa89c946b
--- /dev/null
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -0,0 +1,237 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_KNOWNFPCLASS_H
+#define LLVM_SUPPORT_KNOWNFPCLASS_H
+
+#include "llvm/ADT/FloatingPointMode.h"
+#include <optional>
+
+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<bool> 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
\ No newline at end of file
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 <algorithm>
#include <optional>
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 <algorithm>
@@ -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<Instruction>(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<Instruction>(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<FixedVectorType>(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<bool> 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 <cassert>
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",
>From ac0fc913c0f78ccc65d1ae6862823e195bc2761d Mon Sep 17 00:00:00 2001
From: Tim Gymnich <tim at gymni.ch>
Date: Fri, 28 Mar 2025 16:39:16 +0100
Subject: [PATCH 2/2] Update llvm/include/llvm/Support/KnownFPClass.h
Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
llvm/include/llvm/Support/KnownFPClass.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 9a0afa89c946b..c243819a01ff4 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -1,4 +1,4 @@
-//===- llvm/Support/KnownFPClass.h - Stores known fplcass -------*- C++ -*-===//
+//===- 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.
More information about the llvm-commits
mailing list