xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/KnownFPClass.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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