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