[llvm] [KnownFPClass] Refactor NaN sign encoding for KnownFPClass (PR #220606)
Eric Ross via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 4 16:29:28 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/220606
>From 25249336c06723d3f6284dc015d326d15e40af4d Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Mon, 24 Aug 2026 14:59:31 -0600
Subject: [PATCH 1/4] [KnownFPClass] Refactor NaN sign encoding for
KnownFPClass
---
llvm/include/llvm/Support/KnownFPClass.h | 343 +++++++++++++++++------
llvm/lib/Support/KnownFPClass.cpp | 10 +-
2 files changed, 267 insertions(+), 86 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 33a115b679ad0..5dc9c34e78d28 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -24,41 +24,219 @@ class APInt;
struct fltSemantics;
struct KnownBits;
+enum FPClassMask : unsigned {
+ kfcNone = 0,
+
+ kfcNegQNan = 0x0001,
+ kfcNegSNan = 0x0002,
+ kfcNegInf = 0x0004,
+ kfcNegNormal = 0x0008,
+ kfcNegSubnormal = 0x0010,
+ kfcNegZero = 0x0020,
+ kfcPosZero = 0x0040,
+ kfcPosSubnormal = 0x0080,
+ kfcPosNormal = 0x0100,
+ kfcPosInf = 0x0200,
+ kfcPosSNan = 0x0400,
+ kfcPosQNan = 0x0800,
+
+ kfcSNan = kfcPosSNan | kfcNegSNan,
+ kfcQNan = kfcPosQNan | kfcNegQNan,
+ kfcPosNan = kfcPosSNan | kfcPosQNan,
+ kfcNegNan = kfcNegSNan | kfcNegQNan,
+ kfcNan = kfcSNan | kfcQNan,
+ kfcInf = kfcPosInf | kfcNegInf,
+ kfcNormal = kfcPosNormal | kfcNegNormal,
+ kfcSubnormal = kfcPosSubnormal | kfcNegSubnormal,
+ kfcZero = kfcPosZero | kfcNegZero,
+ kfcPosFinite = kfcPosNormal | kfcPosSubnormal | kfcPosZero,
+ kfcNegFinite = kfcNegNormal | kfcNegSubnormal | kfcNegZero,
+ kfcFinite = kfcPosFinite | kfcNegFinite,
+ kfcPositive = kfcPosFinite | kfcPosInf,
+ kfcNegative = kfcNegFinite | kfcNegInf,
+ kfcPosSignBit = kfcPositive | kfcPosNan,
+ kfcNegSignBit = kfcNegative | kfcNegNan,
+
+ kfcAllFlags = kfcNan | kfcInf | kfcFinite,
+};
+
+LLVM_DECLARE_ENUM_AS_BITMASK(FPClassMask, /* LargestValue */ kfcPosQNan);
+
+constexpr FPClassMask toFPClassMask(FPClassTest Classes) {
+ FPClassMask Mask = kfcNone;
+
+ if (Classes & fcQNan)
+ Mask |= kfcQNan;
+ if (Classes & fcSNan)
+ Mask |= kfcSNan;
+ if (Classes & fcNegInf)
+ Mask |= kfcNegInf;
+ if (Classes & fcNegNormal)
+ Mask |= kfcNegNormal;
+ if (Classes & fcNegSubnormal)
+ Mask |= kfcNegSubnormal;
+ if (Classes & fcNegZero)
+ Mask |= kfcNegZero;
+ if (Classes & fcPosZero)
+ Mask |= kfcPosZero;
+ if (Classes & fcPosSubnormal)
+ Mask |= kfcPosSubnormal;
+ if (Classes & fcPosNormal)
+ Mask |= kfcPosNormal;
+ if (Classes & fcPosInf)
+ Mask |= kfcPosInf;
+
+ return Mask;
+}
+
+constexpr FPClassMask toFPClassMask(FPClassTest Classes,
+ std::optional<bool> SignBit) {
+ FPClassMask Mask = toFPClassMask(Classes);
+
+ // This is the only way to generate a NaN with a specific sign from
+ // FPClassTest. SignBit must agree with the input classes.
+ if (SignBit) {
+ if (!*SignBit) {
+ Mask &= ~kfcNegNan;
+ // If the SignBit is false, then we should not have any negative classes.
+ if (!(Mask & kfcNegSignBit))
+ return Mask;
+ } else {
+ Mask &= ~kfcPosNan;
+ // If the SignBit is true, then we should not have any positive classes.
+ if (!(Mask & kfcPosSignBit))
+ return Mask;
+ }
+ }
+
+ // SignBit is unknown or inconsistent with the input classes. Expand the
+ // possible set to its opposite sign pair.
+ if (Classes & fcQNan)
+ Mask |= kfcQNan;
+ if (Classes & fcSNan)
+ Mask |= kfcSNan;
+ if (Classes & fcInf)
+ Mask |= kfcInf;
+ if (Classes & fcNormal)
+ Mask |= kfcNormal;
+ if (Classes & fcSubnormal)
+ Mask |= kfcSubnormal;
+ if (Classes & fcZero)
+ Mask |= kfcZero;
+
+ return Mask;
+}
+
+constexpr FPClassTest toFPClassTest(FPClassMask Mask) {
+ FPClassTest Classes = fcNone;
+
+ // Sign of qNaN and sNaN are lost in the conversion.
+ if (Mask & kfcQNan)
+ Classes |= fcQNan;
+ if (Mask & kfcSNan)
+ Classes |= fcSNan;
+
+ if (Mask & kfcNegInf)
+ Classes |= fcNegInf;
+ if (Mask & kfcNegNormal)
+ Classes |= fcNegNormal;
+ if (Mask & kfcNegSubnormal)
+ Classes |= fcNegSubnormal;
+ if (Mask & kfcNegZero)
+ Classes |= fcNegZero;
+ if (Mask & kfcPosZero)
+ Classes |= fcPosZero;
+ if (Mask & kfcPosSubnormal)
+ Classes |= fcPosSubnormal;
+ if (Mask & kfcPosNormal)
+ Classes |= fcPosNormal;
+ if (Mask & kfcPosInf)
+ Classes |= fcPosInf;
+
+ return Classes;
+}
+
struct KnownFPClass {
- FPClassTest KnownFPClassesValue = fcAllFlags;
- std::optional<bool> SignBitValue;
+ FPClassMask KnownFPMask = kfcAllFlags;
/// Floating-point classes the value could be one of.
- FPClassTest getKnownFPClasses() const { return KnownFPClassesValue; }
+ FPClassTest getKnownFPClasses() const { return toFPClassTest(KnownFPMask); }
- void setKnownFPClasses(FPClassTest Classes) { KnownFPClassesValue = Classes; }
+ void setKnownFPClasses(FPClassTest Classes) {
+ KnownFPMask = toFPClassMask(Classes);
+ }
+
+ void setKnownFPClasses(FPClassTest Classes, std::optional<bool> Sign) {
+ KnownFPMask = toFPClassMask(Classes, Sign);
+ }
/// 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> getSignBit() const { return SignBitValue; }
+ /// By convention, returns false for kfcNone/poison.
+ std::optional<bool> getSignBit() const {
+ if (KnownFPMask == kfcNone)
+ return false;
- void setSignBit(std::optional<bool> Sign) { SignBitValue = Sign; }
+ if ((KnownFPMask & kfcPosSignBit) == KnownFPMask)
+ return false;
+ if ((KnownFPMask & kfcNegSignBit) == KnownFPMask)
+ return true;
- KnownFPClass(FPClassTest Known = fcAllFlags, std::optional<bool> Sign = {})
- : KnownFPClassesValue(Known), SignBitValue(Sign) {}
+ return std::nullopt;
+ }
+
+ void setSignBit(std::optional<bool> Sign) {
+ if (Sign && !*Sign) {
+ KnownFPMask &= kfcPosSignBit;
+ return;
+ }
+ if (Sign && *Sign) {
+ KnownFPMask &= kfcNegSignBit;
+ return;
+ }
+ // Set sign to unknown.
+ if (KnownFPMask & kfcQNan)
+ KnownFPMask |= kfcQNan;
+ if (KnownFPMask & kfcSNan)
+ KnownFPMask |= kfcSNan;
+ if (KnownFPMask & kfcInf)
+ KnownFPMask |= kfcInf;
+ if (KnownFPMask & kfcNormal)
+ KnownFPMask |= kfcNormal;
+ if (KnownFPMask & kfcSubnormal)
+ KnownFPMask |= kfcSubnormal;
+ if (KnownFPMask & kfcZero)
+ KnownFPMask |= kfcZero;
+ }
+
+ KnownFPClass(FPClassMask Known = kfcAllFlags) : KnownFPMask(Known) {}
+ KnownFPClass(FPClassTest Known) : KnownFPMask(toFPClassMask(Known)) {}
+ KnownFPClass(FPClassTest Known, std::optional<bool> Sign)
+ : KnownFPMask(toFPClassMask(Known, Sign)) {}
LLVM_ABI KnownFPClass(const APFloat &C);
bool operator==(KnownFPClass Other) const {
- return getKnownFPClasses() == Other.getKnownFPClasses() &&
- getSignBit() == Other.getSignBit();
+ return KnownFPMask == Other.KnownFPMask;
+ }
+
+ /// Return true if it's known this can never be one of the mask entries.
+ bool isKnownNever(FPClassMask Mask) const {
+ return (KnownFPMask & Mask) == kfcNone;
}
/// Return true if it's known this can never be one of the mask entries.
bool isKnownNever(FPClassTest Mask) const {
- return (getKnownFPClasses() & Mask) == fcNone;
+ return isKnownNever(toFPClassMask(Mask));
}
- bool isKnownAlways(FPClassTest Mask) const { return isKnownNever(~Mask); }
+ bool isKnownAlways(FPClassMask Mask) const { return isKnownNever(~Mask); }
- bool isUnknown() const {
- return getKnownFPClasses() == fcAllFlags && !getSignBit();
+ bool isKnownAlways(FPClassTest Mask) const {
+ return isKnownAlways(toFPClassMask(Mask));
}
+ bool isUnknown() const { return KnownFPMask == kfcAllFlags; }
+
/// Return true if it's known this can never be a nan.
bool isKnownNeverNaN() const { return isKnownNever(fcNan); }
@@ -171,44 +349,51 @@ struct KnownFPClass {
DenormalMode Mode);
KnownFPClass intersectWith(const KnownFPClass &RHS) const {
- return KnownFPClass(getKnownFPClasses() | RHS.getKnownFPClasses(),
- getSignBit() == RHS.getSignBit() ? getSignBit()
- : std::nullopt);
+ return KnownFPClass(KnownFPMask | RHS.KnownFPMask);
}
KnownFPClass unionWith(const KnownFPClass &RHS) const {
- std::optional<bool> MergedSignBit;
- if (getSignBit() && !RHS.getSignBit())
- MergedSignBit = getSignBit();
- else if (!getSignBit() && RHS.getSignBit())
- MergedSignBit = RHS.getSignBit();
-
- return KnownFPClass(getKnownFPClasses() & RHS.getKnownFPClasses(),
- MergedSignBit);
+ return KnownFPClass(KnownFPMask & RHS.KnownFPMask);
}
KnownFPClass &operator|=(const KnownFPClass &RHS) {
- setKnownFPClasses(getKnownFPClasses() | RHS.getKnownFPClasses());
-
- if (getSignBit() != RHS.getSignBit())
- setSignBit(std::nullopt);
+ KnownFPMask |= RHS.KnownFPMask;
return *this;
}
- void knownNot(FPClassTest RuleOut) {
- setKnownFPClasses(getKnownFPClasses() & ~RuleOut);
- if (isKnownNever(fcNan) && !getSignBit()) {
- if (isKnownNever(fcNegative))
- setSignBit(false);
- else if (isKnownNever(fcPositive))
- setSignBit(true);
- }
- }
+ void knownNot(FPClassMask RuleOut) { KnownFPMask &= ~RuleOut; }
+
+ void knownNot(FPClassTest RuleOut) { knownNot(toFPClassMask(RuleOut)); }
void fneg() {
- setKnownFPClasses(llvm::fneg(getKnownFPClasses()));
- if (std::optional<bool> Sign = getSignBit())
- setSignBit(!*Sign);
+ FPClassMask Known = kfcNone;
+
+ if (KnownFPMask & kfcNegQNan)
+ Known |= kfcPosQNan;
+ if (KnownFPMask & kfcNegSNan)
+ Known |= kfcPosSNan;
+ if (KnownFPMask & kfcNegInf)
+ Known |= kfcPosInf;
+ if (KnownFPMask & kfcNegNormal)
+ Known |= kfcPosNormal;
+ if (KnownFPMask & kfcNegSubnormal)
+ Known |= kfcPosSubnormal;
+ if (KnownFPMask & kfcNegZero)
+ Known |= kfcPosZero;
+ if (KnownFPMask & kfcPosZero)
+ Known |= kfcNegZero;
+ if (KnownFPMask & kfcPosSubnormal)
+ Known |= kfcNegSubnormal;
+ if (KnownFPMask & kfcPosNormal)
+ Known |= kfcNegNormal;
+ if (KnownFPMask & kfcPosInf)
+ Known |= kfcNegInf;
+ if (KnownFPMask & kfcPosSNan)
+ Known |= kfcNegSNan;
+ if (KnownFPMask & kfcPosQNan)
+ Known |= kfcNegQNan;
+
+ KnownFPMask = Known;
}
static KnownFPClass fneg(const KnownFPClass &Src) {
@@ -218,19 +403,22 @@ struct KnownFPClass {
}
void fabs() {
- if (getKnownFPClasses() & fcNegZero)
- setKnownFPClasses(getKnownFPClasses() | fcPosZero);
-
- if (getKnownFPClasses() & fcNegInf)
- setKnownFPClasses(getKnownFPClasses() | fcPosInf);
-
- if (getKnownFPClasses() & fcNegSubnormal)
- setKnownFPClasses(getKnownFPClasses() | fcPosSubnormal);
-
- if (getKnownFPClasses() & fcNegNormal)
- setKnownFPClasses(getKnownFPClasses() | fcPosNormal);
-
- signBitMustBeZero();
+ FPClassMask Known = kfcNone;
+
+ if (KnownFPMask & kfcQNan)
+ Known |= kfcPosQNan;
+ if (KnownFPMask & kfcSNan)
+ Known |= kfcPosSNan;
+ if (KnownFPMask & kfcInf)
+ Known |= kfcPosInf;
+ if (KnownFPMask & kfcNormal)
+ Known |= kfcPosNormal;
+ if (KnownFPMask & kfcSubnormal)
+ Known |= kfcPosSubnormal;
+ if (KnownFPMask & kfcZero)
+ Known |= kfcPosZero;
+
+ KnownFPMask = Known;
}
static KnownFPClass fabs(const KnownFPClass &Src) {
@@ -379,39 +567,32 @@ struct KnownFPClass {
bool signBitIsZeroOrNaN() const { return isKnownNever(fcNegative); }
/// Assume the sign bit is zero.
- void signBitMustBeZero() {
- setKnownFPClasses(getKnownFPClasses() & (fcPositive | fcNan));
- setSignBit(false);
- }
+ void signBitMustBeZero() { KnownFPMask &= kfcPosSignBit; }
/// Assume the sign bit is one.
- void signBitMustBeOne() {
- setKnownFPClasses(getKnownFPClasses() & (fcNegative | fcNan));
- setSignBit(true);
- }
+ void signBitMustBeOne() { KnownFPMask &= kfcNegSignBit; }
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 (getKnownFPClasses() & fcZero)
- setKnownFPClasses(getKnownFPClasses() | fcZero);
- if (getKnownFPClasses() & fcSubnormal)
- setKnownFPClasses(getKnownFPClasses() | fcSubnormal);
- if (getKnownFPClasses() & fcNormal)
- setKnownFPClasses(getKnownFPClasses() | fcNormal);
- if (getKnownFPClasses() & fcInf)
- setKnownFPClasses(getKnownFPClasses() | fcInf);
-
- // Sign bit is exactly preserved even for nans.
- setSignBit(Sign.getSignBit());
-
- // Clear sign bits based on the input sign mask.
- if (Sign.isKnownNever(fcPositive | fcNan) ||
- (getSignBit() && *getSignBit()))
- setKnownFPClasses(getKnownFPClasses() & (fcNegative | fcNan));
- if (Sign.isKnownNever(fcNegative | fcNan) ||
- (getSignBit() && !*getSignBit()))
- setKnownFPClasses(getKnownFPClasses() & (fcPositive | fcNan));
+
+ if (KnownFPMask & kfcQNan)
+ KnownFPMask |= kfcQNan;
+ if (KnownFPMask & kfcSNan)
+ KnownFPMask |= kfcSNan;
+ if (KnownFPMask & kfcInf)
+ KnownFPMask |= kfcInf;
+ if (KnownFPMask & kfcNormal)
+ KnownFPMask |= kfcNormal;
+ if (KnownFPMask & kfcSubnormal)
+ KnownFPMask |= kfcSubnormal;
+ if (KnownFPMask & kfcZero)
+ KnownFPMask |= kfcZero;
+
+ if (Sign.getSignBit() && !*Sign.getSignBit())
+ KnownFPMask &= kfcPosSignBit;
+ if (Sign.getSignBit() && *Sign.getSignBit())
+ KnownFPMask &= kfcNegSignBit;
}
static KnownFPClass copysign(const KnownFPClass &KnownMag,
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 96d6a9758b8f8..6b040b9015970 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -19,9 +19,7 @@
using namespace llvm;
KnownFPClass::KnownFPClass(const APFloat &C)
- : KnownFPClassesValue(C.classify()) {
- setSignBit(C.isNegative());
-}
+ : KnownFPClass(C.classify(), C.isNegative()) {}
KnownFPClass KnownFPClass::applyInputDenormalMode(const KnownFPClass &KnownSrc,
DenormalMode Mode) {
@@ -987,8 +985,10 @@ KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc,
}
// Sign bit of a nan isn't guaranteed.
- if (!Known.isKnownNeverNaN())
- Known.setSignBit(std::nullopt);
+ if (Known.KnownFPMask & kfcSNan)
+ Known.KnownFPMask |= kfcSNan;
+ if (Known.KnownFPMask & kfcQNan)
+ Known.KnownFPMask |= kfcQNan;
return Known;
}
>From 791d0853a4b2ec2eeaaec841bce380899ce0c366 Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Wed, 23 Sep 2026 15:02:00 -0600
Subject: [PATCH 2/4] make KnownFPClass a class, and convert some
std::optional<bool> parameters to bool
---
llvm/include/llvm/Analysis/ValueTracking.h | 2 +-
llvm/include/llvm/IR/ConstantFPRange.h | 2 +-
llvm/include/llvm/Support/KnownFPClass.h | 34 +++++++++-------------
3 files changed, 16 insertions(+), 22 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index b3c8a894ef056..46eb729c2eaff 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -36,7 +36,7 @@ class DominatorTree;
class GEPOperator;
class WithOverflowInst;
struct KnownBits;
-struct KnownFPClass;
+class KnownFPClass;
class Loop;
class LoopInfo;
class MDNode;
diff --git a/llvm/include/llvm/IR/ConstantFPRange.h b/llvm/include/llvm/IR/ConstantFPRange.h
index e772095a266cc..f13778c5eb95d 100644
--- a/llvm/include/llvm/IR/ConstantFPRange.h
+++ b/llvm/include/llvm/IR/ConstantFPRange.h
@@ -31,7 +31,7 @@
namespace llvm {
class raw_ostream;
-struct KnownFPClass;
+class KnownFPClass;
/// This class represents a range of floating-point values.
class [[nodiscard]] ConstantFPRange {
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 5dc9c34e78d28..255f92782676b 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -89,24 +89,21 @@ constexpr FPClassMask toFPClassMask(FPClassTest Classes) {
return Mask;
}
-constexpr FPClassMask toFPClassMask(FPClassTest Classes,
- std::optional<bool> SignBit) {
+constexpr FPClassMask toFPClassMask(FPClassTest Classes, bool SignBit) {
FPClassMask Mask = toFPClassMask(Classes);
// This is the only way to generate a NaN with a specific sign from
// FPClassTest. SignBit must agree with the input classes.
- if (SignBit) {
- if (!*SignBit) {
- Mask &= ~kfcNegNan;
- // If the SignBit is false, then we should not have any negative classes.
- if (!(Mask & kfcNegSignBit))
- return Mask;
- } else {
- Mask &= ~kfcPosNan;
- // If the SignBit is true, then we should not have any positive classes.
- if (!(Mask & kfcPosSignBit))
- return Mask;
- }
+ if (!SignBit) {
+ Mask &= ~kfcNegNan;
+ // If the SignBit is false, then we should not have any negative classes.
+ if (!(Mask & kfcNegSignBit))
+ return Mask;
+ } else {
+ Mask &= ~kfcPosNan;
+ // If the SignBit is true, then we should not have any positive classes.
+ if (!(Mask & kfcPosSignBit))
+ return Mask;
}
// SignBit is unknown or inconsistent with the input classes. Expand the
@@ -156,9 +153,10 @@ constexpr FPClassTest toFPClassTest(FPClassMask Mask) {
return Classes;
}
-struct KnownFPClass {
+class KnownFPClass {
FPClassMask KnownFPMask = kfcAllFlags;
+public:
/// Floating-point classes the value could be one of.
FPClassTest getKnownFPClasses() const { return toFPClassTest(KnownFPMask); }
@@ -166,10 +164,6 @@ struct KnownFPClass {
KnownFPMask = toFPClassMask(Classes);
}
- void setKnownFPClasses(FPClassTest Classes, std::optional<bool> Sign) {
- KnownFPMask = toFPClassMask(Classes, Sign);
- }
-
/// 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.
/// By convention, returns false for kfcNone/poison.
@@ -211,7 +205,7 @@ struct KnownFPClass {
KnownFPClass(FPClassMask Known = kfcAllFlags) : KnownFPMask(Known) {}
KnownFPClass(FPClassTest Known) : KnownFPMask(toFPClassMask(Known)) {}
- KnownFPClass(FPClassTest Known, std::optional<bool> Sign)
+ KnownFPClass(FPClassTest Known, bool Sign)
: KnownFPMask(toFPClassMask(Known, Sign)) {}
LLVM_ABI KnownFPClass(const APFloat &C);
>From 352be2af70e1fd6c5a28cc8946bcd55ad8aa349e Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Wed, 30 Sep 2026 00:00:56 -0600
Subject: [PATCH 3/4] Make FPClassMask an enum class
---
llvm/include/llvm/Support/KnownFPClass.h | 339 ++++++++++++-----------
llvm/lib/Support/KnownFPClass.cpp | 8 +-
2 files changed, 175 insertions(+), 172 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 255f92782676b..80cfcfd0608b5 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -14,6 +14,7 @@
#ifndef LLVM_SUPPORT_KNOWNFPCLASS_H
#define LLVM_SUPPORT_KNOWNFPCLASS_H
+#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/Support/Compiler.h"
#include <optional>
@@ -24,7 +25,7 @@ class APInt;
struct fltSemantics;
struct KnownBits;
-enum FPClassMask : unsigned {
+enum class FPClassMask : unsigned {
kfcNone = 0,
kfcNegQNan = 0x0001,
@@ -58,103 +59,104 @@ enum FPClassMask : unsigned {
kfcNegSignBit = kfcNegative | kfcNegNan,
kfcAllFlags = kfcNan | kfcInf | kfcFinite,
-};
-LLVM_DECLARE_ENUM_AS_BITMASK(FPClassMask, /* LargestValue */ kfcPosQNan);
-
-constexpr FPClassMask toFPClassMask(FPClassTest Classes) {
- FPClassMask Mask = kfcNone;
-
- if (Classes & fcQNan)
- Mask |= kfcQNan;
- if (Classes & fcSNan)
- Mask |= kfcSNan;
- if (Classes & fcNegInf)
- Mask |= kfcNegInf;
- if (Classes & fcNegNormal)
- Mask |= kfcNegNormal;
- if (Classes & fcNegSubnormal)
- Mask |= kfcNegSubnormal;
- if (Classes & fcNegZero)
- Mask |= kfcNegZero;
- if (Classes & fcPosZero)
- Mask |= kfcPosZero;
- if (Classes & fcPosSubnormal)
- Mask |= kfcPosSubnormal;
- if (Classes & fcPosNormal)
- Mask |= kfcPosNormal;
- if (Classes & fcPosInf)
- Mask |= kfcPosInf;
-
- return Mask;
-}
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ kfcPosQNan)
+};
-constexpr FPClassMask toFPClassMask(FPClassTest Classes, bool SignBit) {
- FPClassMask Mask = toFPClassMask(Classes);
-
- // This is the only way to generate a NaN with a specific sign from
- // FPClassTest. SignBit must agree with the input classes.
- if (!SignBit) {
- Mask &= ~kfcNegNan;
- // If the SignBit is false, then we should not have any negative classes.
- if (!(Mask & kfcNegSignBit))
- return Mask;
- } else {
- Mask &= ~kfcPosNan;
- // If the SignBit is true, then we should not have any positive classes.
- if (!(Mask & kfcPosSignBit))
- return Mask;
+class KnownFPClass {
+ FPClassMask KnownFPMask = FPClassMask::kfcAllFlags;
+
+ static constexpr FPClassMask toFPClassMask(FPClassTest Classes) {
+ FPClassMask Mask = FPClassMask::kfcNone;
+
+ if (Classes & fcQNan)
+ Mask |= FPClassMask::kfcQNan;
+ if (Classes & fcSNan)
+ Mask |= FPClassMask::kfcSNan;
+ if (Classes & fcNegInf)
+ Mask |= FPClassMask::kfcNegInf;
+ if (Classes & fcNegNormal)
+ Mask |= FPClassMask::kfcNegNormal;
+ if (Classes & fcNegSubnormal)
+ Mask |= FPClassMask::kfcNegSubnormal;
+ if (Classes & fcNegZero)
+ Mask |= FPClassMask::kfcNegZero;
+ if (Classes & fcPosZero)
+ Mask |= FPClassMask::kfcPosZero;
+ if (Classes & fcPosSubnormal)
+ Mask |= FPClassMask::kfcPosSubnormal;
+ if (Classes & fcPosNormal)
+ Mask |= FPClassMask::kfcPosNormal;
+ if (Classes & fcPosInf)
+ Mask |= FPClassMask::kfcPosInf;
+
+ return Mask;
}
- // SignBit is unknown or inconsistent with the input classes. Expand the
- // possible set to its opposite sign pair.
- if (Classes & fcQNan)
- Mask |= kfcQNan;
- if (Classes & fcSNan)
- Mask |= kfcSNan;
- if (Classes & fcInf)
- Mask |= kfcInf;
- if (Classes & fcNormal)
- Mask |= kfcNormal;
- if (Classes & fcSubnormal)
- Mask |= kfcSubnormal;
- if (Classes & fcZero)
- Mask |= kfcZero;
-
- return Mask;
-}
+ static constexpr FPClassMask toFPClassMask(FPClassTest Classes,
+ bool SignBit) {
+ FPClassMask Mask = toFPClassMask(Classes);
+
+ // This is the only way to generate a NaN with a specific sign from
+ // FPClassTest. SignBit must agree with the input classes.
+ if (!SignBit) {
+ Mask &= ~FPClassMask::kfcNegNan;
+ // If the SignBit is false, then we should not have any negative classes.
+ if ((Mask & FPClassMask::kfcNegSignBit) == FPClassMask::kfcNone)
+ return Mask;
+ } else {
+ Mask &= ~FPClassMask::kfcPosNan;
+ // If the SignBit is true, then we should not have any positive classes.
+ if ((Mask & FPClassMask::kfcPosSignBit) == FPClassMask::kfcNone)
+ return Mask;
+ }
-constexpr FPClassTest toFPClassTest(FPClassMask Mask) {
- FPClassTest Classes = fcNone;
-
- // Sign of qNaN and sNaN are lost in the conversion.
- if (Mask & kfcQNan)
- Classes |= fcQNan;
- if (Mask & kfcSNan)
- Classes |= fcSNan;
-
- if (Mask & kfcNegInf)
- Classes |= fcNegInf;
- if (Mask & kfcNegNormal)
- Classes |= fcNegNormal;
- if (Mask & kfcNegSubnormal)
- Classes |= fcNegSubnormal;
- if (Mask & kfcNegZero)
- Classes |= fcNegZero;
- if (Mask & kfcPosZero)
- Classes |= fcPosZero;
- if (Mask & kfcPosSubnormal)
- Classes |= fcPosSubnormal;
- if (Mask & kfcPosNormal)
- Classes |= fcPosNormal;
- if (Mask & kfcPosInf)
- Classes |= fcPosInf;
-
- return Classes;
-}
+ // SignBit is unknown or inconsistent with the input classes. Expand the
+ // possible set to its opposite sign pair.
+ if (Classes & fcQNan)
+ Mask |= FPClassMask::kfcQNan;
+ if (Classes & fcSNan)
+ Mask |= FPClassMask::kfcSNan;
+ if (Classes & fcInf)
+ Mask |= FPClassMask::kfcInf;
+ if (Classes & fcNormal)
+ Mask |= FPClassMask::kfcNormal;
+ if (Classes & fcSubnormal)
+ Mask |= FPClassMask::kfcSubnormal;
+ if (Classes & fcZero)
+ Mask |= FPClassMask::kfcZero;
+
+ return Mask;
+ }
-class KnownFPClass {
- FPClassMask KnownFPMask = kfcAllFlags;
+ static constexpr FPClassTest toFPClassTest(FPClassMask Mask) {
+ FPClassTest Classes = fcNone;
+
+ // Sign of qNaN and sNaN are lost in the conversion.
+ if ((Mask & FPClassMask::kfcQNan) != FPClassMask::kfcNone)
+ Classes |= fcQNan;
+ if ((Mask & FPClassMask::kfcSNan) != FPClassMask::kfcNone)
+ Classes |= fcSNan;
+
+ if ((Mask & FPClassMask::kfcNegInf) != FPClassMask::kfcNone)
+ Classes |= fcNegInf;
+ if ((Mask & FPClassMask::kfcNegNormal) != FPClassMask::kfcNone)
+ Classes |= fcNegNormal;
+ if ((Mask & FPClassMask::kfcNegSubnormal) != FPClassMask::kfcNone)
+ Classes |= fcNegSubnormal;
+ if ((Mask & FPClassMask::kfcNegZero) != FPClassMask::kfcNone)
+ Classes |= fcNegZero;
+ if ((Mask & FPClassMask::kfcPosZero) != FPClassMask::kfcNone)
+ Classes |= fcPosZero;
+ if ((Mask & FPClassMask::kfcPosSubnormal) != FPClassMask::kfcNone)
+ Classes |= fcPosSubnormal;
+ if ((Mask & FPClassMask::kfcPosNormal) != FPClassMask::kfcNone)
+ Classes |= fcPosNormal;
+ if ((Mask & FPClassMask::kfcPosInf) != FPClassMask::kfcNone)
+ Classes |= fcPosInf;
+
+ return Classes;
+ }
public:
/// Floating-point classes the value could be one of.
@@ -168,12 +170,12 @@ class KnownFPClass {
/// definitely set or false if the sign bit is definitely unset.
/// By convention, returns false for kfcNone/poison.
std::optional<bool> getSignBit() const {
- if (KnownFPMask == kfcNone)
+ if (KnownFPMask == FPClassMask::kfcNone)
return false;
- if ((KnownFPMask & kfcPosSignBit) == KnownFPMask)
+ if ((KnownFPMask & FPClassMask::kfcPosSignBit) == KnownFPMask)
return false;
- if ((KnownFPMask & kfcNegSignBit) == KnownFPMask)
+ if ((KnownFPMask & FPClassMask::kfcNegSignBit) == KnownFPMask)
return true;
return std::nullopt;
@@ -181,29 +183,30 @@ class KnownFPClass {
void setSignBit(std::optional<bool> Sign) {
if (Sign && !*Sign) {
- KnownFPMask &= kfcPosSignBit;
+ KnownFPMask &= FPClassMask::kfcPosSignBit;
return;
}
if (Sign && *Sign) {
- KnownFPMask &= kfcNegSignBit;
+ KnownFPMask &= FPClassMask::kfcNegSignBit;
return;
}
// Set sign to unknown.
- if (KnownFPMask & kfcQNan)
- KnownFPMask |= kfcQNan;
- if (KnownFPMask & kfcSNan)
- KnownFPMask |= kfcSNan;
- if (KnownFPMask & kfcInf)
- KnownFPMask |= kfcInf;
- if (KnownFPMask & kfcNormal)
- KnownFPMask |= kfcNormal;
- if (KnownFPMask & kfcSubnormal)
- KnownFPMask |= kfcSubnormal;
- if (KnownFPMask & kfcZero)
- KnownFPMask |= kfcZero;
+ if ((KnownFPMask & FPClassMask::kfcQNan) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcQNan;
+ if ((KnownFPMask & FPClassMask::kfcSNan) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcSNan;
+ if ((KnownFPMask & FPClassMask::kfcInf) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcInf;
+ if ((KnownFPMask & FPClassMask::kfcNormal) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcNormal;
+ if ((KnownFPMask & FPClassMask::kfcSubnormal) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcSubnormal;
+ if ((KnownFPMask & FPClassMask::kfcZero) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcZero;
}
- KnownFPClass(FPClassMask Known = kfcAllFlags) : KnownFPMask(Known) {}
+ KnownFPClass(FPClassMask Known = FPClassMask::kfcAllFlags)
+ : KnownFPMask(Known) {}
KnownFPClass(FPClassTest Known) : KnownFPMask(toFPClassMask(Known)) {}
KnownFPClass(FPClassTest Known, bool Sign)
: KnownFPMask(toFPClassMask(Known, Sign)) {}
@@ -215,7 +218,7 @@ class KnownFPClass {
/// Return true if it's known this can never be one of the mask entries.
bool isKnownNever(FPClassMask Mask) const {
- return (KnownFPMask & Mask) == kfcNone;
+ return (KnownFPMask & Mask) == FPClassMask::kfcNone;
}
/// Return true if it's known this can never be one of the mask entries.
@@ -229,7 +232,7 @@ class KnownFPClass {
return isKnownAlways(toFPClassMask(Mask));
}
- bool isUnknown() const { return KnownFPMask == kfcAllFlags; }
+ bool isUnknown() const { return KnownFPMask == FPClassMask::kfcAllFlags; }
/// Return true if it's known this can never be a nan.
bool isKnownNeverNaN() const { return isKnownNever(fcNan); }
@@ -360,32 +363,32 @@ class KnownFPClass {
void knownNot(FPClassTest RuleOut) { knownNot(toFPClassMask(RuleOut)); }
void fneg() {
- FPClassMask Known = kfcNone;
-
- if (KnownFPMask & kfcNegQNan)
- Known |= kfcPosQNan;
- if (KnownFPMask & kfcNegSNan)
- Known |= kfcPosSNan;
- if (KnownFPMask & kfcNegInf)
- Known |= kfcPosInf;
- if (KnownFPMask & kfcNegNormal)
- Known |= kfcPosNormal;
- if (KnownFPMask & kfcNegSubnormal)
- Known |= kfcPosSubnormal;
- if (KnownFPMask & kfcNegZero)
- Known |= kfcPosZero;
- if (KnownFPMask & kfcPosZero)
- Known |= kfcNegZero;
- if (KnownFPMask & kfcPosSubnormal)
- Known |= kfcNegSubnormal;
- if (KnownFPMask & kfcPosNormal)
- Known |= kfcNegNormal;
- if (KnownFPMask & kfcPosInf)
- Known |= kfcNegInf;
- if (KnownFPMask & kfcPosSNan)
- Known |= kfcNegSNan;
- if (KnownFPMask & kfcPosQNan)
- Known |= kfcNegQNan;
+ FPClassMask Known = FPClassMask::kfcNone;
+
+ if ((KnownFPMask & FPClassMask::kfcNegQNan) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosQNan;
+ if ((KnownFPMask & FPClassMask::kfcNegSNan) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosSNan;
+ if ((KnownFPMask & FPClassMask::kfcNegInf) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosInf;
+ if ((KnownFPMask & FPClassMask::kfcNegNormal) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosNormal;
+ if ((KnownFPMask & FPClassMask::kfcNegSubnormal) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosSubnormal;
+ if ((KnownFPMask & FPClassMask::kfcNegZero) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosZero;
+ if ((KnownFPMask & FPClassMask::kfcPosZero) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcNegZero;
+ if ((KnownFPMask & FPClassMask::kfcPosSubnormal) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcNegSubnormal;
+ if ((KnownFPMask & FPClassMask::kfcPosNormal) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcNegNormal;
+ if ((KnownFPMask & FPClassMask::kfcPosInf) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcNegInf;
+ if ((KnownFPMask & FPClassMask::kfcPosSNan) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcNegSNan;
+ if ((KnownFPMask & FPClassMask::kfcPosQNan) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcNegQNan;
KnownFPMask = Known;
}
@@ -397,20 +400,20 @@ class KnownFPClass {
}
void fabs() {
- FPClassMask Known = kfcNone;
-
- if (KnownFPMask & kfcQNan)
- Known |= kfcPosQNan;
- if (KnownFPMask & kfcSNan)
- Known |= kfcPosSNan;
- if (KnownFPMask & kfcInf)
- Known |= kfcPosInf;
- if (KnownFPMask & kfcNormal)
- Known |= kfcPosNormal;
- if (KnownFPMask & kfcSubnormal)
- Known |= kfcPosSubnormal;
- if (KnownFPMask & kfcZero)
- Known |= kfcPosZero;
+ FPClassMask Known = FPClassMask::kfcNone;
+
+ if ((KnownFPMask & FPClassMask::kfcQNan) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosQNan;
+ if ((KnownFPMask & FPClassMask::kfcSNan) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosSNan;
+ if ((KnownFPMask & FPClassMask::kfcInf) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosInf;
+ if ((KnownFPMask & FPClassMask::kfcNormal) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosNormal;
+ if ((KnownFPMask & FPClassMask::kfcSubnormal) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosSubnormal;
+ if ((KnownFPMask & FPClassMask::kfcZero) != FPClassMask::kfcNone)
+ Known |= FPClassMask::kfcPosZero;
KnownFPMask = Known;
}
@@ -561,32 +564,32 @@ class KnownFPClass {
bool signBitIsZeroOrNaN() const { return isKnownNever(fcNegative); }
/// Assume the sign bit is zero.
- void signBitMustBeZero() { KnownFPMask &= kfcPosSignBit; }
+ void signBitMustBeZero() { KnownFPMask &= FPClassMask::kfcPosSignBit; }
/// Assume the sign bit is one.
- void signBitMustBeOne() { KnownFPMask &= kfcNegSignBit; }
+ void signBitMustBeOne() { KnownFPMask &= FPClassMask::kfcNegSignBit; }
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 (KnownFPMask & kfcQNan)
- KnownFPMask |= kfcQNan;
- if (KnownFPMask & kfcSNan)
- KnownFPMask |= kfcSNan;
- if (KnownFPMask & kfcInf)
- KnownFPMask |= kfcInf;
- if (KnownFPMask & kfcNormal)
- KnownFPMask |= kfcNormal;
- if (KnownFPMask & kfcSubnormal)
- KnownFPMask |= kfcSubnormal;
- if (KnownFPMask & kfcZero)
- KnownFPMask |= kfcZero;
+ if ((KnownFPMask & FPClassMask::kfcQNan) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcQNan;
+ if ((KnownFPMask & FPClassMask::kfcSNan) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcSNan;
+ if ((KnownFPMask & FPClassMask::kfcInf) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcInf;
+ if ((KnownFPMask & FPClassMask::kfcNormal) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcNormal;
+ if ((KnownFPMask & FPClassMask::kfcSubnormal) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcSubnormal;
+ if ((KnownFPMask & FPClassMask::kfcZero) != FPClassMask::kfcNone)
+ KnownFPMask |= FPClassMask::kfcZero;
if (Sign.getSignBit() && !*Sign.getSignBit())
- KnownFPMask &= kfcPosSignBit;
+ KnownFPMask &= FPClassMask::kfcPosSignBit;
if (Sign.getSignBit() && *Sign.getSignBit())
- KnownFPMask &= kfcNegSignBit;
+ KnownFPMask &= FPClassMask::kfcNegSignBit;
}
static KnownFPClass copysign(const KnownFPClass &KnownMag,
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 6b040b9015970..947f7d6184062 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -985,10 +985,10 @@ KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc,
}
// Sign bit of a nan isn't guaranteed.
- if (Known.KnownFPMask & kfcSNan)
- Known.KnownFPMask |= kfcSNan;
- if (Known.KnownFPMask & kfcQNan)
- Known.KnownFPMask |= kfcQNan;
+ if (!Known.isKnownNever(fcSNan))
+ Known.setKnownFPClasses(Known.getKnownFPClasses() | fcSNan);
+ if (!Known.isKnownNever(fcQNan))
+ Known.setKnownFPClasses(Known.getKnownFPClasses() | fcQNan);
return Known;
}
>From 052ffb88c3bef9613fdc2a3e2982bf179abba44f Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Sun, 4 Oct 2026 17:27:58 -0600
Subject: [PATCH 4/4] Update applyDenormalMode helpers
---
llvm/lib/Support/KnownFPClass.cpp | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 947f7d6184062..c2799d54b3329 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -34,18 +34,12 @@ KnownFPClass KnownFPClass::applyInputDenormalMode(const KnownFPClass &KnownSrc,
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero);
return Known;
case DenormalMode::PositiveZero:
- if (KnownSrc.getKnownFPClasses() & fcSubnormal) {
+ if (KnownSrc.getKnownFPClasses() & fcSubnormal)
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero);
- if (KnownSrc.getKnownFPClasses() & fcNegSubnormal)
- Known.setSignBit(std::nullopt);
- }
return Known;
default:
- if (KnownSrc.getKnownFPClasses() & fcSubnormal) {
+ if (KnownSrc.getKnownFPClasses() & fcSubnormal)
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero);
- if (KnownSrc.getKnownFPClasses() & fcNegSubnormal)
- Known.setSignBit(std::nullopt);
- }
if (KnownSrc.getKnownFPClasses() & fcNegSubnormal)
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero);
return Known;
@@ -67,18 +61,12 @@ KnownFPClass KnownFPClass::applyOutputDenormalMode(const KnownFPClass &KnownSrc,
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero);
return Known;
case DenormalMode::PositiveZero:
- if (KnownSrc.getKnownFPClasses() & fcSubnormal) {
+ if (KnownSrc.getKnownFPClasses() & fcSubnormal)
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero);
- if (KnownSrc.getKnownFPClasses() & fcNegSubnormal)
- Known.setSignBit(std::nullopt);
- }
return Known;
default:
- if (KnownSrc.getKnownFPClasses() & fcSubnormal) {
+ if (KnownSrc.getKnownFPClasses() & fcSubnormal)
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero);
- if (KnownSrc.getKnownFPClasses() & fcNegSubnormal)
- Known.setSignBit(std::nullopt);
- }
if (KnownSrc.getKnownFPClasses() & fcNegSubnormal)
Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero);
return Known;
More information about the llvm-commits
mailing list