1 //===- ConstantFPRange.cpp - ConstantFPRange implementation ---------------===// 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 #include "llvm/IR/ConstantFPRange.h" 10 #include "llvm/ADT/APFloat.h" 11 #include "llvm/Analysis/ValueTracking.h" 12 #include "llvm/Support/Debug.h" 13 #include "llvm/Support/raw_ostream.h" 14 #include <cassert> 15 16 using namespace llvm; 17 18 void ConstantFPRange::makeEmpty() { 19 auto &Sem = Lower.getSemantics(); 20 Lower = APFloat::getInf(Sem, /*Negative=*/false); 21 Upper = APFloat::getInf(Sem, /*Negative=*/true); 22 MayBeQNaN = false; 23 MayBeSNaN = false; 24 } 25 26 void ConstantFPRange::makeFull() { 27 auto &Sem = Lower.getSemantics(); 28 Lower = APFloat::getInf(Sem, /*Negative=*/true); 29 Upper = APFloat::getInf(Sem, /*Negative=*/false); 30 MayBeQNaN = true; 31 MayBeSNaN = true; 32 } 33 34 bool ConstantFPRange::isNaNOnly() const { 35 return Lower.isPosInfinity() && Upper.isNegInfinity(); 36 } 37 38 ConstantFPRange::ConstantFPRange(const fltSemantics &Sem, bool IsFullSet) 39 : Lower(Sem, APFloat::uninitialized), Upper(Sem, APFloat::uninitialized) { 40 Lower = APFloat::getInf(Sem, /*Negative=*/IsFullSet); 41 Upper = APFloat::getInf(Sem, /*Negative=*/!IsFullSet); 42 MayBeQNaN = IsFullSet; 43 MayBeSNaN = IsFullSet; 44 } 45 46 ConstantFPRange::ConstantFPRange(const APFloat &Value) 47 : Lower(Value.getSemantics(), APFloat::uninitialized), 48 Upper(Value.getSemantics(), APFloat::uninitialized) { 49 if (Value.isNaN()) { 50 makeEmpty(); 51 bool IsSNaN = Value.isSignaling(); 52 MayBeQNaN = !IsSNaN; 53 MayBeSNaN = IsSNaN; 54 } else { 55 Lower = Upper = Value; 56 MayBeQNaN = MayBeSNaN = false; 57 } 58 } 59 60 // We treat that -0 is less than 0 here. 61 static APFloat::cmpResult strictCompare(const APFloat &LHS, 62 const APFloat &RHS) { 63 assert(!LHS.isNaN() && !RHS.isNaN() && "Unordered compare"); 64 if (LHS.isZero() && RHS.isZero()) { 65 if (LHS.isNegative() == RHS.isNegative()) 66 return APFloat::cmpEqual; 67 return LHS.isNegative() ? APFloat::cmpLessThan : APFloat::cmpGreaterThan; 68 } 69 return LHS.compare(RHS); 70 } 71 72 static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) { 73 return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan && 74 !(Lower.isInfinity() && Upper.isInfinity()); 75 } 76 77 static void canonicalizeRange(APFloat &Lower, APFloat &Upper) { 78 if (isNonCanonicalEmptySet(Lower, Upper)) { 79 Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false); 80 Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true); 81 } 82 } 83 84 ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal, 85 bool MayBeQNaN, bool MayBeSNaN) 86 : Lower(std::move(LowerVal)), Upper(std::move(UpperVal)) { 87 assert(&Lower.getSemantics() == &Upper.getSemantics() && 88 "Should only use the same semantics"); 89 assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form"); 90 this->MayBeQNaN = MayBeQNaN; 91 this->MayBeSNaN = MayBeSNaN; 92 } 93 94 ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) { 95 return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true), 96 APFloat::getLargest(Sem, /*Negative=*/false), 97 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false); 98 } 99 100 ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem, 101 bool MayBeQNaN, bool MayBeSNaN) { 102 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false), 103 APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN, 104 MayBeSNaN); 105 } 106 107 ConstantFPRange 108 ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred, 109 const ConstantFPRange &Other) { 110 // TODO 111 return getFull(Other.getSemantics()); 112 } 113 114 ConstantFPRange 115 ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred, 116 const ConstantFPRange &Other) { 117 // TODO 118 return getEmpty(Other.getSemantics()); 119 } 120 121 ConstantFPRange ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred, 122 const APFloat &Other) { 123 return makeAllowedFCmpRegion(Pred, ConstantFPRange(Other)); 124 } 125 126 bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred, 127 const ConstantFPRange &Other) const { 128 return makeSatisfyingFCmpRegion(Pred, Other).contains(*this); 129 } 130 131 bool ConstantFPRange::isFullSet() const { 132 return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN && 133 MayBeSNaN; 134 } 135 136 bool ConstantFPRange::isEmptySet() const { 137 return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN && 138 !MayBeSNaN; 139 } 140 141 bool ConstantFPRange::contains(const APFloat &Val) const { 142 assert(&getSemantics() == &Val.getSemantics() && 143 "Should only use the same semantics"); 144 145 if (Val.isNaN()) 146 return Val.isSignaling() ? MayBeSNaN : MayBeQNaN; 147 return strictCompare(Lower, Val) != APFloat::cmpGreaterThan && 148 strictCompare(Val, Upper) != APFloat::cmpGreaterThan; 149 } 150 151 bool ConstantFPRange::contains(const ConstantFPRange &CR) const { 152 assert(&getSemantics() == &CR.getSemantics() && 153 "Should only use the same semantics"); 154 155 if (CR.MayBeQNaN && !MayBeQNaN) 156 return false; 157 158 if (CR.MayBeSNaN && !MayBeSNaN) 159 return false; 160 161 return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan && 162 strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan; 163 } 164 165 const APFloat *ConstantFPRange::getSingleElement() const { 166 if (MayBeSNaN || MayBeQNaN) 167 return nullptr; 168 return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr; 169 } 170 171 std::optional<bool> ConstantFPRange::getSignBit() const { 172 if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative()) 173 return Lower.isNegative(); 174 return std::nullopt; 175 } 176 177 bool ConstantFPRange::operator==(const ConstantFPRange &CR) const { 178 if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN) 179 return false; 180 return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper); 181 } 182 183 FPClassTest ConstantFPRange::classify() const { 184 uint32_t Mask = fcNone; 185 if (MayBeSNaN) 186 Mask |= fcSNan; 187 if (MayBeQNaN) 188 Mask |= fcQNan; 189 if (!isNaNOnly()) { 190 FPClassTest LowerMask = Lower.classify(); 191 FPClassTest UpperMask = Upper.classify(); 192 assert(LowerMask <= UpperMask && "Range is nan-only."); 193 for (uint32_t I = LowerMask; I <= UpperMask; I <<= 1) 194 Mask |= I; 195 } 196 return static_cast<FPClassTest>(Mask); 197 } 198 199 KnownFPClass ConstantFPRange::toKnownFPClass() const { 200 KnownFPClass Result; 201 Result.KnownFPClasses = classify(); 202 Result.SignBit = getSignBit(); 203 return Result; 204 } 205 206 void ConstantFPRange::print(raw_ostream &OS) const { 207 if (isFullSet()) 208 OS << "full-set"; 209 else if (isEmptySet()) 210 OS << "empty-set"; 211 else { 212 bool NaNOnly = isNaNOnly(); 213 if (!NaNOnly) 214 OS << '[' << Lower << ", " << Upper << ']'; 215 216 if (MayBeSNaN || MayBeQNaN) { 217 if (!NaNOnly) 218 OS << " with "; 219 if (MayBeSNaN && MayBeQNaN) 220 OS << "NaN"; 221 else if (MayBeSNaN) 222 OS << "SNaN"; 223 else if (MayBeQNaN) 224 OS << "QNaN"; 225 } 226 } 227 } 228 229 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 230 LLVM_DUMP_METHOD void ConstantFPRange::dump() const { print(dbgs()); } 231 #endif 232 233 ConstantFPRange 234 ConstantFPRange::intersectWith(const ConstantFPRange &CR) const { 235 assert(&getSemantics() == &CR.getSemantics() && 236 "Should only use the same semantics"); 237 APFloat NewLower = maxnum(Lower, CR.Lower); 238 APFloat NewUpper = minnum(Upper, CR.Upper); 239 canonicalizeRange(NewLower, NewUpper); 240 return ConstantFPRange(std::move(NewLower), std::move(NewUpper), 241 MayBeQNaN & CR.MayBeQNaN, MayBeSNaN & CR.MayBeSNaN); 242 } 243 244 ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const { 245 assert(&getSemantics() == &CR.getSemantics() && 246 "Should only use the same semantics"); 247 return ConstantFPRange(minnum(Lower, CR.Lower), maxnum(Upper, CR.Upper), 248 MayBeQNaN | CR.MayBeQNaN, MayBeSNaN | CR.MayBeSNaN); 249 } 250