1 //===- ConstantFPRange.h - Represent a range for floating-point -*- 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 // Represent a range of possible values that may occur when the program is run 10 // for a floating-point value. This keeps track of a lower and upper bound for 11 // the constant. 12 // 13 // Range = [Lower, Upper] U (MayBeQNaN ? QNaN : {}) U (MayBeSNaN ? SNaN : {}) 14 // Specifically, [inf, -inf] represents an empty set. 15 // Note: 16 // 1. Bounds are inclusive. 17 // 2. -0 is considered to be less than 0. That is, range [0, 0] doesn't contain 18 // -0. 19 // 3. Currently wrapping ranges are not supported. 20 // 21 //===----------------------------------------------------------------------===// 22 23 #ifndef LLVM_IR_CONSTANTFPRANGE_H 24 #define LLVM_IR_CONSTANTFPRANGE_H 25 26 #include "llvm/ADT/APFloat.h" 27 #include "llvm/IR/Instructions.h" 28 #include "llvm/Support/Compiler.h" 29 #include <optional> 30 31 namespace llvm { 32 33 class raw_ostream; 34 struct KnownFPClass; 35 36 /// This class represents a range of floating-point values. 37 class [[nodiscard]] ConstantFPRange { 38 APFloat Lower, Upper; 39 bool MayBeQNaN : 1; 40 bool MayBeSNaN : 1; 41 42 /// Create empty constant range with same semantics. getEmpty()43 ConstantFPRange getEmpty() const { 44 return ConstantFPRange(getSemantics(), /*IsFullSet=*/false); 45 } 46 47 /// Create full constant range with same semantics. getFull()48 ConstantFPRange getFull() const { 49 return ConstantFPRange(getSemantics(), /*IsFullSet=*/true); 50 } 51 52 void makeEmpty(); 53 void makeFull(); 54 55 /// Initialize a full or empty set for the specified semantics. 56 LLVM_ABI explicit ConstantFPRange(const fltSemantics &Sem, bool IsFullSet); 57 58 public: 59 /// Initialize a range to hold the single specified value. 60 LLVM_ABI explicit ConstantFPRange(const APFloat &Value); 61 62 /// Initialize a range of values explicitly. 63 /// Note: If \p LowerVal is greater than \p UpperVal, please use the canonical 64 /// form [Inf, -Inf]. 65 LLVM_ABI ConstantFPRange(APFloat LowerVal, APFloat UpperVal, bool MayBeQNaN, 66 bool MayBeSNaN); 67 68 /// Create empty constant range with the given semantics. getEmpty(const fltSemantics & Sem)69 static ConstantFPRange getEmpty(const fltSemantics &Sem) { 70 return ConstantFPRange(Sem, /*IsFullSet=*/false); 71 } 72 73 /// Create full constant range with the given semantics. getFull(const fltSemantics & Sem)74 static ConstantFPRange getFull(const fltSemantics &Sem) { 75 return ConstantFPRange(Sem, /*IsFullSet=*/true); 76 } 77 78 /// Helper for (-inf, inf) to represent all finite values. 79 LLVM_ABI static ConstantFPRange getFinite(const fltSemantics &Sem); 80 81 /// Helper for [-inf, inf] to represent all non-NaN values. 82 LLVM_ABI static ConstantFPRange getNonNaN(const fltSemantics &Sem); 83 84 /// Create a range which doesn't contain NaNs. getNonNaN(APFloat LowerVal,APFloat UpperVal)85 static ConstantFPRange getNonNaN(APFloat LowerVal, APFloat UpperVal) { 86 return ConstantFPRange(std::move(LowerVal), std::move(UpperVal), 87 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false); 88 } 89 90 /// Create a range which may contain NaNs. getMayBeNaN(APFloat LowerVal,APFloat UpperVal)91 static ConstantFPRange getMayBeNaN(APFloat LowerVal, APFloat UpperVal) { 92 return ConstantFPRange(std::move(LowerVal), std::move(UpperVal), 93 /*MayBeQNaN=*/true, /*MayBeSNaN=*/true); 94 } 95 96 /// Create a range which only contains NaNs. 97 LLVM_ABI static ConstantFPRange getNaNOnly(const fltSemantics &Sem, 98 bool MayBeQNaN, bool MayBeSNaN); 99 100 /// Produce the smallest range such that all values that may satisfy the given 101 /// predicate with any value contained within Other is contained in the 102 /// returned range. Formally, this returns a superset of 103 /// 'union over all y in Other . { x : fcmp op x y is true }'. If the exact 104 /// answer is not representable as a ConstantFPRange, the return value will be 105 /// a proper superset of the above. 106 /// 107 /// Example: Pred = ole and Other = float [2, 5] returns Result = [-inf, 5] 108 LLVM_ABI static ConstantFPRange 109 makeAllowedFCmpRegion(FCmpInst::Predicate Pred, const ConstantFPRange &Other); 110 111 /// Produce the largest range such that all values in the returned range 112 /// satisfy the given predicate with all values contained within Other. 113 /// Formally, this returns a subset of 114 /// 'intersection over all y in Other . { x : fcmp op x y is true }'. If the 115 /// exact answer is not representable as a ConstantFPRange, the return value 116 /// will be a proper subset of the above. 117 /// 118 /// Example: Pred = ole and Other = float [2, 5] returns [-inf, 2] 119 LLVM_ABI static ConstantFPRange 120 makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred, 121 const ConstantFPRange &Other); 122 123 /// Produce the exact range such that all values in the returned range satisfy 124 /// the given predicate with any value contained within Other. Formally, this 125 /// returns { x : fcmp op x Other is true }. 126 /// 127 /// Example: Pred = olt and Other = float 3 returns [-inf, 3) 128 /// If the exact answer is not representable as a ConstantFPRange, returns 129 /// std::nullopt. 130 LLVM_ABI static std::optional<ConstantFPRange> 131 makeExactFCmpRegion(FCmpInst::Predicate Pred, const APFloat &Other); 132 133 /// Does the predicate \p Pred hold between ranges this and \p Other? 134 /// NOTE: false does not mean that inverse predicate holds! 135 LLVM_ABI bool fcmp(FCmpInst::Predicate Pred, 136 const ConstantFPRange &Other) const; 137 138 /// Return the lower value for this range. getLower()139 const APFloat &getLower() const { return Lower; } 140 141 /// Return the upper value for this range. getUpper()142 const APFloat &getUpper() const { return Upper; } 143 containsNaN()144 bool containsNaN() const { return MayBeQNaN || MayBeSNaN; } containsQNaN()145 bool containsQNaN() const { return MayBeQNaN; } containsSNaN()146 bool containsSNaN() const { return MayBeSNaN; } 147 LLVM_ABI bool isNaNOnly() const; 148 149 /// Get the semantics of this ConstantFPRange. getSemantics()150 const fltSemantics &getSemantics() const { return Lower.getSemantics(); } 151 152 /// Return true if this set contains all of the elements possible 153 /// for this data-type. 154 LLVM_ABI bool isFullSet() const; 155 156 /// Return true if this set contains no members. 157 LLVM_ABI bool isEmptySet() const; 158 159 /// Return true if the specified value is in the set. 160 LLVM_ABI bool contains(const APFloat &Val) const; 161 162 /// Return true if the other range is a subset of this one. 163 LLVM_ABI bool contains(const ConstantFPRange &CR) const; 164 165 /// If this set contains a single element, return it, otherwise return null. 166 /// If \p ExcludesNaN is true, return the non-NaN single element. 167 LLVM_ABI const APFloat *getSingleElement(bool ExcludesNaN = false) const; 168 169 /// Return true if this set contains exactly one member. 170 /// If \p ExcludesNaN is true, return true if this set contains exactly one 171 /// non-NaN member. 172 bool isSingleElement(bool ExcludesNaN = false) const { 173 return getSingleElement(ExcludesNaN) != nullptr; 174 } 175 176 /// Return true if the sign bit of all values in this range is 1. 177 /// Return false if the sign bit of all values in this range is 0. 178 /// Otherwise, return std::nullopt. 179 LLVM_ABI std::optional<bool> getSignBit() const; 180 181 /// Return true if this range is equal to another range. 182 LLVM_ABI bool operator==(const ConstantFPRange &CR) const; 183 /// Return true if this range is not equal to another range. 184 bool operator!=(const ConstantFPRange &CR) const { return !operator==(CR); } 185 186 /// Return the FPClassTest which will return true for the value. 187 LLVM_ABI FPClassTest classify() const; 188 189 /// Print out the bounds to a stream. 190 LLVM_ABI void print(raw_ostream &OS) const; 191 192 /// Allow printing from a debugger easily. 193 LLVM_ABI void dump() const; 194 195 /// Return the range that results from the intersection of this range with 196 /// another range. 197 LLVM_ABI ConstantFPRange intersectWith(const ConstantFPRange &CR) const; 198 199 /// Return the smallest range that results from the union of this range 200 /// with another range. The resultant range is guaranteed to include the 201 /// elements of both sets, but may contain more. 202 LLVM_ABI ConstantFPRange unionWith(const ConstantFPRange &CR) const; 203 }; 204 205 inline raw_ostream &operator<<(raw_ostream &OS, const ConstantFPRange &CR) { 206 CR.print(OS); 207 return OS; 208 } 209 210 } // end namespace llvm 211 212 #endif // LLVM_IR_CONSTANTFPRANGE_H 213