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/Support/Debug.h" 12 #include "llvm/Support/raw_ostream.h" 13 #include <cassert> 14 15 using namespace llvm; 16 17 void ConstantFPRange::makeEmpty() { 18 auto &Sem = Lower.getSemantics(); 19 Lower = APFloat::getInf(Sem, /*Negative=*/false); 20 Upper = APFloat::getInf(Sem, /*Negative=*/true); 21 MayBeQNaN = false; 22 MayBeSNaN = false; 23 } 24 25 void ConstantFPRange::makeFull() { 26 auto &Sem = Lower.getSemantics(); 27 Lower = APFloat::getInf(Sem, /*Negative=*/true); 28 Upper = APFloat::getInf(Sem, /*Negative=*/false); 29 MayBeQNaN = true; 30 MayBeSNaN = true; 31 } 32 33 bool ConstantFPRange::isNaNOnly() const { 34 return Lower.isPosInfinity() && Upper.isNegInfinity(); 35 } 36 37 ConstantFPRange::ConstantFPRange(const fltSemantics &Sem, bool IsFullSet) 38 : Lower(Sem, APFloat::uninitialized), Upper(Sem, APFloat::uninitialized) { 39 Lower = APFloat::getInf(Sem, /*Negative=*/IsFullSet); 40 Upper = APFloat::getInf(Sem, /*Negative=*/!IsFullSet); 41 MayBeQNaN = IsFullSet; 42 MayBeSNaN = IsFullSet; 43 } 44 45 ConstantFPRange::ConstantFPRange(const APFloat &Value) 46 : Lower(Value.getSemantics(), APFloat::uninitialized), 47 Upper(Value.getSemantics(), APFloat::uninitialized) { 48 if (Value.isNaN()) { 49 makeEmpty(); 50 bool IsSNaN = Value.isSignaling(); 51 MayBeQNaN = !IsSNaN; 52 MayBeSNaN = IsSNaN; 53 } else { 54 Lower = Upper = Value; 55 MayBeQNaN = MayBeSNaN = false; 56 } 57 } 58 59 // We treat that -0 is less than 0 here. 60 static APFloat::cmpResult strictCompare(const APFloat &LHS, 61 const APFloat &RHS) { 62 assert(!LHS.isNaN() && !RHS.isNaN() && "Unordered compare"); 63 if (LHS.isZero() && RHS.isZero()) { 64 if (LHS.isNegative() == RHS.isNegative()) 65 return APFloat::cmpEqual; 66 return LHS.isNegative() ? APFloat::cmpLessThan : APFloat::cmpGreaterThan; 67 } 68 return LHS.compare(RHS); 69 } 70 71 static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) { 72 return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan && 73 !(Lower.isInfinity() && Upper.isInfinity()); 74 } 75 76 static void canonicalizeRange(APFloat &Lower, APFloat &Upper) { 77 if (isNonCanonicalEmptySet(Lower, Upper)) { 78 Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false); 79 Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true); 80 } 81 } 82 83 ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal, 84 bool MayBeQNaNVal, bool MayBeSNaNVal) 85 : Lower(std::move(LowerVal)), Upper(std::move(UpperVal)), 86 MayBeQNaN(MayBeQNaNVal), MayBeSNaN(MayBeSNaNVal) { 87 assert(&Lower.getSemantics() == &Upper.getSemantics() && 88 "Should only use the same semantics"); 89 assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form"); 90 } 91 92 ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) { 93 return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true), 94 APFloat::getLargest(Sem, /*Negative=*/false), 95 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false); 96 } 97 98 ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem, 99 bool MayBeQNaN, bool MayBeSNaN) { 100 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false), 101 APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN, 102 MayBeSNaN); 103 } 104 105 ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) { 106 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true), 107 APFloat::getInf(Sem, /*Negative=*/false), 108 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false); 109 } 110 111 /// Return true for ULT/UGT/OLT/OGT 112 static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred) { 113 return !(Pred & FCmpInst::FCMP_OEQ); 114 } 115 116 /// Return [-inf, V) or [-inf, V] 117 static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) { 118 const fltSemantics &Sem = V.getSemantics(); 119 if (fcmpPredExcludesEqual(Pred)) { 120 if (V.isNegInfinity()) 121 return ConstantFPRange::getEmpty(Sem); 122 V.next(/*nextDown=*/true); 123 } 124 return ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), 125 std::move(V)); 126 } 127 128 /// Return (V, +inf] or [V, +inf] 129 static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) { 130 const fltSemantics &Sem = V.getSemantics(); 131 if (fcmpPredExcludesEqual(Pred)) { 132 if (V.isPosInfinity()) 133 return ConstantFPRange::getEmpty(Sem); 134 V.next(/*nextDown=*/false); 135 } 136 return ConstantFPRange::getNonNaN(std::move(V), 137 APFloat::getInf(Sem, /*Negative=*/false)); 138 } 139 140 /// Make sure that +0/-0 are both included in the range. 141 static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR, 142 FCmpInst::Predicate Pred) { 143 if (fcmpPredExcludesEqual(Pred)) 144 return CR; 145 146 APFloat Lower = CR.getLower(); 147 APFloat Upper = CR.getUpper(); 148 if (Lower.isPosZero()) 149 Lower = APFloat::getZero(Lower.getSemantics(), /*Negative=*/true); 150 if (Upper.isNegZero()) 151 Upper = APFloat::getZero(Upper.getSemantics(), /*Negative=*/false); 152 return ConstantFPRange(std::move(Lower), std::move(Upper), CR.containsQNaN(), 153 CR.containsSNaN()); 154 } 155 156 static ConstantFPRange setNaNField(const ConstantFPRange &CR, 157 FCmpInst::Predicate Pred) { 158 bool ContainsNaN = FCmpInst::isUnordered(Pred); 159 return ConstantFPRange(CR.getLower(), CR.getUpper(), 160 /*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN); 161 } 162 163 ConstantFPRange 164 ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred, 165 const ConstantFPRange &Other) { 166 if (Other.isEmptySet()) 167 return Other; 168 if (Other.containsNaN() && FCmpInst::isUnordered(Pred)) 169 return getFull(Other.getSemantics()); 170 if (Other.isNaNOnly() && FCmpInst::isOrdered(Pred)) 171 return getEmpty(Other.getSemantics()); 172 173 switch (Pred) { 174 case FCmpInst::FCMP_TRUE: 175 return getFull(Other.getSemantics()); 176 case FCmpInst::FCMP_FALSE: 177 return getEmpty(Other.getSemantics()); 178 case FCmpInst::FCMP_ORD: 179 return getNonNaN(Other.getSemantics()); 180 case FCmpInst::FCMP_UNO: 181 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true, 182 /*MayBeSNaN=*/true); 183 case FCmpInst::FCMP_OEQ: 184 case FCmpInst::FCMP_UEQ: 185 return setNaNField(extendZeroIfEqual(Other, Pred), Pred); 186 case FCmpInst::FCMP_ONE: 187 case FCmpInst::FCMP_UNE: 188 if (const APFloat *SingleElement = 189 Other.getSingleElement(/*ExcludesNaN=*/true)) { 190 const fltSemantics &Sem = SingleElement->getSemantics(); 191 if (SingleElement->isPosInfinity()) 192 return setNaNField( 193 getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), 194 APFloat::getLargest(Sem, /*Negative=*/false)), 195 Pred); 196 if (SingleElement->isNegInfinity()) 197 return setNaNField( 198 getNonNaN(APFloat::getLargest(Sem, /*Negative=*/true), 199 APFloat::getInf(Sem, /*Negative=*/false)), 200 Pred); 201 } 202 return Pred == FCmpInst::FCMP_ONE ? getNonNaN(Other.getSemantics()) 203 : getFull(Other.getSemantics()); 204 case FCmpInst::FCMP_OLT: 205 case FCmpInst::FCMP_OLE: 206 case FCmpInst::FCMP_ULT: 207 case FCmpInst::FCMP_ULE: 208 return setNaNField( 209 extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred); 210 case FCmpInst::FCMP_OGT: 211 case FCmpInst::FCMP_OGE: 212 case FCmpInst::FCMP_UGT: 213 case FCmpInst::FCMP_UGE: 214 return setNaNField( 215 extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred); 216 default: 217 llvm_unreachable("Unexpected predicate"); 218 } 219 } 220 221 ConstantFPRange 222 ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred, 223 const ConstantFPRange &Other) { 224 if (Other.isEmptySet()) 225 return getFull(Other.getSemantics()); 226 if (Other.containsNaN() && FCmpInst::isOrdered(Pred)) 227 return getEmpty(Other.getSemantics()); 228 if (Other.isNaNOnly() && FCmpInst::isUnordered(Pred)) 229 return getFull(Other.getSemantics()); 230 231 switch (Pred) { 232 case FCmpInst::FCMP_TRUE: 233 return getFull(Other.getSemantics()); 234 case FCmpInst::FCMP_FALSE: 235 return getEmpty(Other.getSemantics()); 236 case FCmpInst::FCMP_ORD: 237 return getNonNaN(Other.getSemantics()); 238 case FCmpInst::FCMP_UNO: 239 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true, 240 /*MayBeSNaN=*/true); 241 case FCmpInst::FCMP_OEQ: 242 case FCmpInst::FCMP_UEQ: 243 return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) || 244 ((Other.classify() & ~fcNan) == fcZero) 245 ? extendZeroIfEqual(Other, Pred) 246 : getEmpty(Other.getSemantics()), 247 Pred); 248 case FCmpInst::FCMP_ONE: 249 case FCmpInst::FCMP_UNE: 250 return getEmpty(Other.getSemantics()); 251 case FCmpInst::FCMP_OLT: 252 case FCmpInst::FCMP_OLE: 253 case FCmpInst::FCMP_ULT: 254 case FCmpInst::FCMP_ULE: 255 return setNaNField( 256 extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred); 257 case FCmpInst::FCMP_OGT: 258 case FCmpInst::FCMP_OGE: 259 case FCmpInst::FCMP_UGT: 260 case FCmpInst::FCMP_UGE: 261 return setNaNField( 262 extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred); 263 default: 264 llvm_unreachable("Unexpected predicate"); 265 } 266 } 267 268 std::optional<ConstantFPRange> 269 ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred, 270 const APFloat &Other) { 271 if ((Pred == FCmpInst::FCMP_UNE || Pred == FCmpInst::FCMP_ONE) && 272 !Other.isNaN()) 273 return std::nullopt; 274 return makeSatisfyingFCmpRegion(Pred, ConstantFPRange(Other)); 275 } 276 277 bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred, 278 const ConstantFPRange &Other) const { 279 return makeSatisfyingFCmpRegion(Pred, Other).contains(*this); 280 } 281 282 bool ConstantFPRange::isFullSet() const { 283 return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN && 284 MayBeSNaN; 285 } 286 287 bool ConstantFPRange::isEmptySet() const { 288 return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN && 289 !MayBeSNaN; 290 } 291 292 bool ConstantFPRange::contains(const APFloat &Val) const { 293 assert(&getSemantics() == &Val.getSemantics() && 294 "Should only use the same semantics"); 295 296 if (Val.isNaN()) 297 return Val.isSignaling() ? MayBeSNaN : MayBeQNaN; 298 return strictCompare(Lower, Val) != APFloat::cmpGreaterThan && 299 strictCompare(Val, Upper) != APFloat::cmpGreaterThan; 300 } 301 302 bool ConstantFPRange::contains(const ConstantFPRange &CR) const { 303 assert(&getSemantics() == &CR.getSemantics() && 304 "Should only use the same semantics"); 305 306 if (CR.MayBeQNaN && !MayBeQNaN) 307 return false; 308 309 if (CR.MayBeSNaN && !MayBeSNaN) 310 return false; 311 312 return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan && 313 strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan; 314 } 315 316 const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const { 317 if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN)) 318 return nullptr; 319 return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr; 320 } 321 322 std::optional<bool> ConstantFPRange::getSignBit() const { 323 if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative()) 324 return Lower.isNegative(); 325 return std::nullopt; 326 } 327 328 bool ConstantFPRange::operator==(const ConstantFPRange &CR) const { 329 if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN) 330 return false; 331 return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper); 332 } 333 334 FPClassTest ConstantFPRange::classify() const { 335 uint32_t Mask = fcNone; 336 if (MayBeSNaN) 337 Mask |= fcSNan; 338 if (MayBeQNaN) 339 Mask |= fcQNan; 340 if (!isNaNOnly()) { 341 FPClassTest LowerMask = Lower.classify(); 342 FPClassTest UpperMask = Upper.classify(); 343 assert(LowerMask <= UpperMask && "Range is nan-only."); 344 // Set all bits from log2(LowerMask) to log2(UpperMask). 345 Mask |= (UpperMask << 1) - LowerMask; 346 } 347 return static_cast<FPClassTest>(Mask); 348 } 349 350 void ConstantFPRange::print(raw_ostream &OS) const { 351 if (isFullSet()) 352 OS << "full-set"; 353 else if (isEmptySet()) 354 OS << "empty-set"; 355 else { 356 bool NaNOnly = isNaNOnly(); 357 if (!NaNOnly) 358 OS << '[' << Lower << ", " << Upper << ']'; 359 360 if (MayBeSNaN || MayBeQNaN) { 361 if (!NaNOnly) 362 OS << " with "; 363 if (MayBeSNaN && MayBeQNaN) 364 OS << "NaN"; 365 else if (MayBeSNaN) 366 OS << "SNaN"; 367 else if (MayBeQNaN) 368 OS << "QNaN"; 369 } 370 } 371 } 372 373 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 374 LLVM_DUMP_METHOD void ConstantFPRange::dump() const { print(dbgs()); } 375 #endif 376 377 ConstantFPRange 378 ConstantFPRange::intersectWith(const ConstantFPRange &CR) const { 379 assert(&getSemantics() == &CR.getSemantics() && 380 "Should only use the same semantics"); 381 APFloat NewLower = maxnum(Lower, CR.Lower); 382 APFloat NewUpper = minnum(Upper, CR.Upper); 383 canonicalizeRange(NewLower, NewUpper); 384 return ConstantFPRange(std::move(NewLower), std::move(NewUpper), 385 MayBeQNaN & CR.MayBeQNaN, MayBeSNaN & CR.MayBeSNaN); 386 } 387 388 ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const { 389 assert(&getSemantics() == &CR.getSemantics() && 390 "Should only use the same semantics"); 391 return ConstantFPRange(minnum(Lower, CR.Lower), maxnum(Upper, CR.Upper), 392 MayBeQNaN | CR.MayBeQNaN, MayBeSNaN | CR.MayBeSNaN); 393 } 394