1 //===- llvm/Support/KnownFPClass.h - Stores known fpclass -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains a class for representing known fpclasses used by 10 // computeKnownFPClass. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_SUPPORT_KNOWNFPCLASS_H 15 #define LLVM_SUPPORT_KNOWNFPCLASS_H 16 17 #include "llvm/ADT/FloatingPointMode.h" 18 #include "llvm/Support/Compiler.h" 19 #include <optional> 20 21 namespace llvm { 22 23 struct KnownFPClass { 24 /// Floating-point classes the value could be one of. 25 FPClassTest KnownFPClasses = fcAllFlags; 26 27 /// std::nullopt if the sign bit is unknown, true if the sign bit is 28 /// definitely set or false if the sign bit is definitely unset. 29 std::optional<bool> SignBit; 30 31 bool operator==(KnownFPClass Other) const { 32 return KnownFPClasses == Other.KnownFPClasses && SignBit == Other.SignBit; 33 } 34 35 /// Return true if it's known this can never be one of the mask entries. isKnownNeverKnownFPClass36 bool isKnownNever(FPClassTest Mask) const { 37 return (KnownFPClasses & Mask) == fcNone; 38 } 39 isKnownAlwaysKnownFPClass40 bool isKnownAlways(FPClassTest Mask) const { return isKnownNever(~Mask); } 41 isUnknownKnownFPClass42 bool isUnknown() const { return KnownFPClasses == fcAllFlags && !SignBit; } 43 44 /// Return true if it's known this can never be a nan. isKnownNeverNaNKnownFPClass45 bool isKnownNeverNaN() const { return isKnownNever(fcNan); } 46 47 /// Return true if it's known this must always be a nan. isKnownAlwaysNaNKnownFPClass48 bool isKnownAlwaysNaN() const { return isKnownAlways(fcNan); } 49 50 /// Return true if it's known this can never be an infinity. isKnownNeverInfinityKnownFPClass51 bool isKnownNeverInfinity() const { return isKnownNever(fcInf); } 52 53 /// Return true if it's known this can never be +infinity. isKnownNeverPosInfinityKnownFPClass54 bool isKnownNeverPosInfinity() const { return isKnownNever(fcPosInf); } 55 56 /// Return true if it's known this can never be -infinity. isKnownNeverNegInfinityKnownFPClass57 bool isKnownNeverNegInfinity() const { return isKnownNever(fcNegInf); } 58 59 /// Return true if it's known this can never be a subnormal isKnownNeverSubnormalKnownFPClass60 bool isKnownNeverSubnormal() const { return isKnownNever(fcSubnormal); } 61 62 /// Return true if it's known this can never be a positive subnormal isKnownNeverPosSubnormalKnownFPClass63 bool isKnownNeverPosSubnormal() const { return isKnownNever(fcPosSubnormal); } 64 65 /// Return true if it's known this can never be a negative subnormal isKnownNeverNegSubnormalKnownFPClass66 bool isKnownNeverNegSubnormal() const { return isKnownNever(fcNegSubnormal); } 67 68 /// Return true if it's known this can never be a zero. This means a literal 69 /// [+-]0, and does not include denormal inputs implicitly treated as [+-]0. isKnownNeverZeroKnownFPClass70 bool isKnownNeverZero() const { return isKnownNever(fcZero); } 71 72 /// Return true if it's known this can never be a literal positive zero. isKnownNeverPosZeroKnownFPClass73 bool isKnownNeverPosZero() const { return isKnownNever(fcPosZero); } 74 75 /// Return true if it's known this can never be a negative zero. This means a 76 /// literal -0 and does not include denormal inputs implicitly treated as -0. isKnownNeverNegZeroKnownFPClass77 bool isKnownNeverNegZero() const { return isKnownNever(fcNegZero); } 78 79 /// Return true if it's know this can never be interpreted as a zero. This 80 /// extends isKnownNeverZero to cover the case where the assumed 81 /// floating-point mode for the function interprets denormals as zero. 82 LLVM_ABI bool isKnownNeverLogicalZero(DenormalMode Mode) const; 83 84 /// Return true if it's know this can never be interpreted as a negative zero. 85 LLVM_ABI bool isKnownNeverLogicalNegZero(DenormalMode Mode) const; 86 87 /// Return true if it's know this can never be interpreted as a positive zero. 88 LLVM_ABI bool isKnownNeverLogicalPosZero(DenormalMode Mode) const; 89 90 static constexpr FPClassTest OrderedLessThanZeroMask = 91 fcNegSubnormal | fcNegNormal | fcNegInf; 92 static constexpr FPClassTest OrderedGreaterThanZeroMask = 93 fcPosSubnormal | fcPosNormal | fcPosInf; 94 95 /// Return true if we can prove that the analyzed floating-point value is 96 /// either NaN or never less than -0.0. 97 /// 98 /// NaN --> true 99 /// +0 --> true 100 /// -0 --> true 101 /// x > +0 --> true 102 /// x < -0 --> false cannotBeOrderedLessThanZeroKnownFPClass103 bool cannotBeOrderedLessThanZero() const { 104 return isKnownNever(OrderedLessThanZeroMask); 105 } 106 107 /// Return true if we can prove that the analyzed floating-point value is 108 /// either NaN or never greater than -0.0. 109 /// NaN --> true 110 /// +0 --> true 111 /// -0 --> true 112 /// x > +0 --> false 113 /// x < -0 --> true cannotBeOrderedGreaterThanZeroKnownFPClass114 bool cannotBeOrderedGreaterThanZero() const { 115 return isKnownNever(OrderedGreaterThanZeroMask); 116 } 117 118 KnownFPClass &operator|=(const KnownFPClass &RHS) { 119 KnownFPClasses = KnownFPClasses | RHS.KnownFPClasses; 120 121 if (SignBit != RHS.SignBit) 122 SignBit = std::nullopt; 123 return *this; 124 } 125 knownNotKnownFPClass126 void knownNot(FPClassTest RuleOut) { 127 KnownFPClasses = KnownFPClasses & ~RuleOut; 128 if (isKnownNever(fcNan) && !SignBit) { 129 if (isKnownNever(fcNegative)) 130 SignBit = false; 131 else if (isKnownNever(fcPositive)) 132 SignBit = true; 133 } 134 } 135 fnegKnownFPClass136 void fneg() { 137 KnownFPClasses = llvm::fneg(KnownFPClasses); 138 if (SignBit) 139 SignBit = !*SignBit; 140 } 141 fabsKnownFPClass142 void fabs() { 143 if (KnownFPClasses & fcNegZero) 144 KnownFPClasses |= fcPosZero; 145 146 if (KnownFPClasses & fcNegInf) 147 KnownFPClasses |= fcPosInf; 148 149 if (KnownFPClasses & fcNegSubnormal) 150 KnownFPClasses |= fcPosSubnormal; 151 152 if (KnownFPClasses & fcNegNormal) 153 KnownFPClasses |= fcPosNormal; 154 155 signBitMustBeZero(); 156 } 157 158 /// Return true if the sign bit must be 0, ignoring the sign of nans. signBitIsZeroOrNaNKnownFPClass159 bool signBitIsZeroOrNaN() const { return isKnownNever(fcNegative); } 160 161 /// Assume the sign bit is zero. signBitMustBeZeroKnownFPClass162 void signBitMustBeZero() { 163 KnownFPClasses &= (fcPositive | fcNan); 164 SignBit = false; 165 } 166 167 /// Assume the sign bit is one. signBitMustBeOneKnownFPClass168 void signBitMustBeOne() { 169 KnownFPClasses &= (fcNegative | fcNan); 170 SignBit = true; 171 } 172 copysignKnownFPClass173 void copysign(const KnownFPClass &Sign) { 174 // Don't know anything about the sign of the source. Expand the possible set 175 // to its opposite sign pair. 176 if (KnownFPClasses & fcZero) 177 KnownFPClasses |= fcZero; 178 if (KnownFPClasses & fcSubnormal) 179 KnownFPClasses |= fcSubnormal; 180 if (KnownFPClasses & fcNormal) 181 KnownFPClasses |= fcNormal; 182 if (KnownFPClasses & fcInf) 183 KnownFPClasses |= fcInf; 184 185 // Sign bit is exactly preserved even for nans. 186 SignBit = Sign.SignBit; 187 188 // Clear sign bits based on the input sign mask. 189 if (Sign.isKnownNever(fcPositive | fcNan) || (SignBit && *SignBit)) 190 KnownFPClasses &= (fcNegative | fcNan); 191 if (Sign.isKnownNever(fcNegative | fcNan) || (SignBit && !*SignBit)) 192 KnownFPClasses &= (fcPositive | fcNan); 193 } 194 195 // Propagate knowledge that a non-NaN source implies the result can also not 196 // be a NaN. For unconstrained operations, signaling nans are not guaranteed 197 // to be quieted but cannot be introduced. 198 void propagateNaN(const KnownFPClass &Src, bool PreserveSign = false) { 199 if (Src.isKnownNever(fcNan)) { 200 knownNot(fcNan); 201 if (PreserveSign) 202 SignBit = Src.SignBit; 203 } else if (Src.isKnownNever(fcSNan)) 204 knownNot(fcSNan); 205 } 206 207 /// Propagate knowledge from a source value that could be a denormal or 208 /// zero. We have to be conservative since output flushing is not guaranteed, 209 /// so known-never-zero may not hold. 210 /// 211 /// This assumes a copy-like operation and will replace any currently known 212 /// information. 213 LLVM_ABI void propagateDenormal(const KnownFPClass &Src, DenormalMode Mode); 214 215 /// Report known classes if \p Src is evaluated through a potentially 216 /// canonicalizing operation. We can assume signaling nans will not be 217 /// introduced, but cannot assume a denormal will be flushed under FTZ/DAZ. 218 /// 219 /// This assumes a copy-like operation and will replace any currently known 220 /// information. 221 LLVM_ABI void propagateCanonicalizingSrc(const KnownFPClass &Src, 222 DenormalMode Mode); 223 resetAllKnownFPClass224 void resetAll() { *this = KnownFPClass(); } 225 }; 226 227 inline KnownFPClass operator|(KnownFPClass LHS, const KnownFPClass &RHS) { 228 LHS |= RHS; 229 return LHS; 230 } 231 232 inline KnownFPClass operator|(const KnownFPClass &LHS, KnownFPClass &&RHS) { 233 RHS |= LHS; 234 return std::move(RHS); 235 } 236 237 } // namespace llvm 238 239 #endif 240