Path: blob/main/contrib/llvm-project/llvm/lib/IR/ConstantFPRange.cpp
213766 views
//===- ConstantFPRange.cpp - ConstantFPRange implementation ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/IR/ConstantFPRange.h"9#include "llvm/ADT/APFloat.h"10#include "llvm/Support/Debug.h"11#include "llvm/Support/raw_ostream.h"12#include <cassert>1314using namespace llvm;1516void ConstantFPRange::makeEmpty() {17auto &Sem = Lower.getSemantics();18Lower = APFloat::getInf(Sem, /*Negative=*/false);19Upper = APFloat::getInf(Sem, /*Negative=*/true);20MayBeQNaN = false;21MayBeSNaN = false;22}2324void ConstantFPRange::makeFull() {25auto &Sem = Lower.getSemantics();26Lower = APFloat::getInf(Sem, /*Negative=*/true);27Upper = APFloat::getInf(Sem, /*Negative=*/false);28MayBeQNaN = true;29MayBeSNaN = true;30}3132bool ConstantFPRange::isNaNOnly() const {33return Lower.isPosInfinity() && Upper.isNegInfinity();34}3536ConstantFPRange::ConstantFPRange(const fltSemantics &Sem, bool IsFullSet)37: Lower(Sem, APFloat::uninitialized), Upper(Sem, APFloat::uninitialized) {38Lower = APFloat::getInf(Sem, /*Negative=*/IsFullSet);39Upper = APFloat::getInf(Sem, /*Negative=*/!IsFullSet);40MayBeQNaN = IsFullSet;41MayBeSNaN = IsFullSet;42}4344ConstantFPRange::ConstantFPRange(const APFloat &Value)45: Lower(Value.getSemantics(), APFloat::uninitialized),46Upper(Value.getSemantics(), APFloat::uninitialized) {47if (Value.isNaN()) {48makeEmpty();49bool IsSNaN = Value.isSignaling();50MayBeQNaN = !IsSNaN;51MayBeSNaN = IsSNaN;52} else {53Lower = Upper = Value;54MayBeQNaN = MayBeSNaN = false;55}56}5758// We treat that -0 is less than 0 here.59static APFloat::cmpResult strictCompare(const APFloat &LHS,60const APFloat &RHS) {61assert(!LHS.isNaN() && !RHS.isNaN() && "Unordered compare");62if (LHS.isZero() && RHS.isZero()) {63if (LHS.isNegative() == RHS.isNegative())64return APFloat::cmpEqual;65return LHS.isNegative() ? APFloat::cmpLessThan : APFloat::cmpGreaterThan;66}67return LHS.compare(RHS);68}6970static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) {71return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan &&72!(Lower.isInfinity() && Upper.isInfinity());73}7475static void canonicalizeRange(APFloat &Lower, APFloat &Upper) {76if (isNonCanonicalEmptySet(Lower, Upper)) {77Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false);78Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true);79}80}8182ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,83bool MayBeQNaNVal, bool MayBeSNaNVal)84: Lower(std::move(LowerVal)), Upper(std::move(UpperVal)),85MayBeQNaN(MayBeQNaNVal), MayBeSNaN(MayBeSNaNVal) {86assert(&Lower.getSemantics() == &Upper.getSemantics() &&87"Should only use the same semantics");88assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form");89}9091ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) {92return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true),93APFloat::getLargest(Sem, /*Negative=*/false),94/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);95}9697ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem,98bool MayBeQNaN, bool MayBeSNaN) {99return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false),100APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN,101MayBeSNaN);102}103104ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {105return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true),106APFloat::getInf(Sem, /*Negative=*/false),107/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);108}109110/// Return true for ULT/UGT/OLT/OGT111static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred) {112return !(Pred & FCmpInst::FCMP_OEQ);113}114115/// Return [-inf, V) or [-inf, V]116static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {117const fltSemantics &Sem = V.getSemantics();118if (fcmpPredExcludesEqual(Pred)) {119if (V.isNegInfinity())120return ConstantFPRange::getEmpty(Sem);121V.next(/*nextDown=*/true);122}123return ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),124std::move(V));125}126127/// Return (V, +inf] or [V, +inf]128static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {129const fltSemantics &Sem = V.getSemantics();130if (fcmpPredExcludesEqual(Pred)) {131if (V.isPosInfinity())132return ConstantFPRange::getEmpty(Sem);133V.next(/*nextDown=*/false);134}135return ConstantFPRange::getNonNaN(std::move(V),136APFloat::getInf(Sem, /*Negative=*/false));137}138139/// Make sure that +0/-0 are both included in the range.140static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,141FCmpInst::Predicate Pred) {142if (fcmpPredExcludesEqual(Pred))143return CR;144145APFloat Lower = CR.getLower();146APFloat Upper = CR.getUpper();147if (Lower.isPosZero())148Lower = APFloat::getZero(Lower.getSemantics(), /*Negative=*/true);149if (Upper.isNegZero())150Upper = APFloat::getZero(Upper.getSemantics(), /*Negative=*/false);151return ConstantFPRange(std::move(Lower), std::move(Upper), CR.containsQNaN(),152CR.containsSNaN());153}154155static ConstantFPRange setNaNField(const ConstantFPRange &CR,156FCmpInst::Predicate Pred) {157bool ContainsNaN = FCmpInst::isUnordered(Pred);158return ConstantFPRange(CR.getLower(), CR.getUpper(),159/*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);160}161162ConstantFPRange163ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,164const ConstantFPRange &Other) {165if (Other.isEmptySet())166return Other;167if (Other.containsNaN() && FCmpInst::isUnordered(Pred))168return getFull(Other.getSemantics());169if (Other.isNaNOnly() && FCmpInst::isOrdered(Pred))170return getEmpty(Other.getSemantics());171172switch (Pred) {173case FCmpInst::FCMP_TRUE:174return getFull(Other.getSemantics());175case FCmpInst::FCMP_FALSE:176return getEmpty(Other.getSemantics());177case FCmpInst::FCMP_ORD:178return getNonNaN(Other.getSemantics());179case FCmpInst::FCMP_UNO:180return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,181/*MayBeSNaN=*/true);182case FCmpInst::FCMP_OEQ:183case FCmpInst::FCMP_UEQ:184return setNaNField(extendZeroIfEqual(Other, Pred), Pred);185case FCmpInst::FCMP_ONE:186case FCmpInst::FCMP_UNE:187if (const APFloat *SingleElement =188Other.getSingleElement(/*ExcludesNaN=*/true)) {189const fltSemantics &Sem = SingleElement->getSemantics();190if (SingleElement->isPosInfinity())191return setNaNField(192getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),193APFloat::getLargest(Sem, /*Negative=*/false)),194Pred);195if (SingleElement->isNegInfinity())196return setNaNField(197getNonNaN(APFloat::getLargest(Sem, /*Negative=*/true),198APFloat::getInf(Sem, /*Negative=*/false)),199Pred);200}201return Pred == FCmpInst::FCMP_ONE ? getNonNaN(Other.getSemantics())202: getFull(Other.getSemantics());203case FCmpInst::FCMP_OLT:204case FCmpInst::FCMP_OLE:205case FCmpInst::FCMP_ULT:206case FCmpInst::FCMP_ULE:207return setNaNField(208extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);209case FCmpInst::FCMP_OGT:210case FCmpInst::FCMP_OGE:211case FCmpInst::FCMP_UGT:212case FCmpInst::FCMP_UGE:213return setNaNField(214extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);215default:216llvm_unreachable("Unexpected predicate");217}218}219220ConstantFPRange221ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,222const ConstantFPRange &Other) {223if (Other.isEmptySet())224return getFull(Other.getSemantics());225if (Other.containsNaN() && FCmpInst::isOrdered(Pred))226return getEmpty(Other.getSemantics());227if (Other.isNaNOnly() && FCmpInst::isUnordered(Pred))228return getFull(Other.getSemantics());229230switch (Pred) {231case FCmpInst::FCMP_TRUE:232return getFull(Other.getSemantics());233case FCmpInst::FCMP_FALSE:234return getEmpty(Other.getSemantics());235case FCmpInst::FCMP_ORD:236return getNonNaN(Other.getSemantics());237case FCmpInst::FCMP_UNO:238return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,239/*MayBeSNaN=*/true);240case FCmpInst::FCMP_OEQ:241case FCmpInst::FCMP_UEQ:242return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||243((Other.classify() & ~fcNan) == fcZero)244? extendZeroIfEqual(Other, Pred)245: getEmpty(Other.getSemantics()),246Pred);247case FCmpInst::FCMP_ONE:248case FCmpInst::FCMP_UNE:249return getEmpty(Other.getSemantics());250case FCmpInst::FCMP_OLT:251case FCmpInst::FCMP_OLE:252case FCmpInst::FCMP_ULT:253case FCmpInst::FCMP_ULE:254return setNaNField(255extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);256case FCmpInst::FCMP_OGT:257case FCmpInst::FCMP_OGE:258case FCmpInst::FCMP_UGT:259case FCmpInst::FCMP_UGE:260return setNaNField(261extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);262default:263llvm_unreachable("Unexpected predicate");264}265}266267std::optional<ConstantFPRange>268ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,269const APFloat &Other) {270if ((Pred == FCmpInst::FCMP_UNE || Pred == FCmpInst::FCMP_ONE) &&271!Other.isNaN())272return std::nullopt;273return makeSatisfyingFCmpRegion(Pred, ConstantFPRange(Other));274}275276bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred,277const ConstantFPRange &Other) const {278return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);279}280281bool ConstantFPRange::isFullSet() const {282return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&283MayBeSNaN;284}285286bool ConstantFPRange::isEmptySet() const {287return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN &&288!MayBeSNaN;289}290291bool ConstantFPRange::contains(const APFloat &Val) const {292assert(&getSemantics() == &Val.getSemantics() &&293"Should only use the same semantics");294295if (Val.isNaN())296return Val.isSignaling() ? MayBeSNaN : MayBeQNaN;297return strictCompare(Lower, Val) != APFloat::cmpGreaterThan &&298strictCompare(Val, Upper) != APFloat::cmpGreaterThan;299}300301bool ConstantFPRange::contains(const ConstantFPRange &CR) const {302assert(&getSemantics() == &CR.getSemantics() &&303"Should only use the same semantics");304305if (CR.MayBeQNaN && !MayBeQNaN)306return false;307308if (CR.MayBeSNaN && !MayBeSNaN)309return false;310311return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan &&312strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan;313}314315const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const {316if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN))317return nullptr;318return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;319}320321std::optional<bool> ConstantFPRange::getSignBit() const {322if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative())323return Lower.isNegative();324return std::nullopt;325}326327bool ConstantFPRange::operator==(const ConstantFPRange &CR) const {328if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN)329return false;330return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper);331}332333FPClassTest ConstantFPRange::classify() const {334uint32_t Mask = fcNone;335if (MayBeSNaN)336Mask |= fcSNan;337if (MayBeQNaN)338Mask |= fcQNan;339if (!isNaNOnly()) {340FPClassTest LowerMask = Lower.classify();341FPClassTest UpperMask = Upper.classify();342assert(LowerMask <= UpperMask && "Range is nan-only.");343// Set all bits from log2(LowerMask) to log2(UpperMask).344Mask |= (UpperMask << 1) - LowerMask;345}346return static_cast<FPClassTest>(Mask);347}348349void ConstantFPRange::print(raw_ostream &OS) const {350if (isFullSet())351OS << "full-set";352else if (isEmptySet())353OS << "empty-set";354else {355bool NaNOnly = isNaNOnly();356if (!NaNOnly)357OS << '[' << Lower << ", " << Upper << ']';358359if (MayBeSNaN || MayBeQNaN) {360if (!NaNOnly)361OS << " with ";362if (MayBeSNaN && MayBeQNaN)363OS << "NaN";364else if (MayBeSNaN)365OS << "SNaN";366else if (MayBeQNaN)367OS << "QNaN";368}369}370}371372#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)373LLVM_DUMP_METHOD void ConstantFPRange::dump() const { print(dbgs()); }374#endif375376ConstantFPRange377ConstantFPRange::intersectWith(const ConstantFPRange &CR) const {378assert(&getSemantics() == &CR.getSemantics() &&379"Should only use the same semantics");380APFloat NewLower = maxnum(Lower, CR.Lower);381APFloat NewUpper = minnum(Upper, CR.Upper);382canonicalizeRange(NewLower, NewUpper);383return ConstantFPRange(std::move(NewLower), std::move(NewUpper),384MayBeQNaN & CR.MayBeQNaN, MayBeSNaN & CR.MayBeSNaN);385}386387ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const {388assert(&getSemantics() == &CR.getSemantics() &&389"Should only use the same semantics");390return ConstantFPRange(minnum(Lower, CR.Lower), maxnum(Upper, CR.Upper),391MayBeQNaN | CR.MayBeQNaN, MayBeSNaN | CR.MayBeSNaN);392}393394395