| //===- llvm/Support/KnownFPClass.h - Stores known fplcass -------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains a class for representing known fpclasses used by | |
| // computeKnownFPClass. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Support/KnownFPClass.h" | |
| #include "llvm/ADT/APFloat.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/KnownBits.h" | |
| using namespace llvm; | |
| KnownFPClass::KnownFPClass(const APFloat &C) | |
| : KnownFPClassesValue(C.classify()) { | |
| setSignBit(C.isNegative()); | |
| } | |
| KnownFPClass KnownFPClass::applyInputDenormalMode(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| KnownFPClass Known = KnownSrc; | |
| switch (Mode.Input) { | |
| case DenormalMode::IEEE: | |
| return Known; | |
| case DenormalMode::PreserveSign: | |
| if (KnownSrc.getKnownFPClasses() & fcPosSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero); | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero); | |
| return Known; | |
| case DenormalMode::PositiveZero: | |
| if (KnownSrc.getKnownFPClasses() & fcSubnormal) { | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero); | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setSignBit(std::nullopt); | |
| } | |
| return Known; | |
| default: | |
| if (KnownSrc.getKnownFPClasses() & fcSubnormal) { | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero); | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setSignBit(std::nullopt); | |
| } | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero); | |
| return Known; | |
| } | |
| llvm_unreachable("covered switch over denormal mode"); | |
| } | |
| KnownFPClass KnownFPClass::applyOutputDenormalMode(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| KnownFPClass Known = KnownSrc; | |
| switch (Mode.Output) { | |
| case DenormalMode::IEEE: | |
| return Known; | |
| case DenormalMode::PreserveSign: | |
| if (KnownSrc.getKnownFPClasses() & fcPosSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero); | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero); | |
| return Known; | |
| case DenormalMode::PositiveZero: | |
| if (KnownSrc.getKnownFPClasses() & fcSubnormal) { | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero); | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setSignBit(std::nullopt); | |
| } | |
| return Known; | |
| default: | |
| if (KnownSrc.getKnownFPClasses() & fcSubnormal) { | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosZero); | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setSignBit(std::nullopt); | |
| } | |
| if (KnownSrc.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegZero); | |
| return Known; | |
| } | |
| llvm_unreachable("covered switch over denormal mode"); | |
| } | |
| bool KnownFPClass::isKnownNeverLogicalZero(DenormalMode Mode) const { | |
| return applyInputDenormalMode(*this, Mode).isKnownNeverZero(); | |
| } | |
| bool KnownFPClass::isKnownNeverLogicalNegZero(DenormalMode Mode) const { | |
| return applyInputDenormalMode(*this, Mode).isKnownNeverNegZero(); | |
| } | |
| bool KnownFPClass::isKnownNeverLogicalPosZero(DenormalMode Mode) const { | |
| return applyInputDenormalMode(*this, Mode).isKnownNeverPosZero(); | |
| } | |
| void KnownFPClass::propagateDenormal(const KnownFPClass &Src, | |
| DenormalMode Mode) { | |
| setKnownFPClasses(Src.getKnownFPClasses()); | |
| // If we aren't assuming the source can't be a zero, we don't have to check if | |
| // a denormal input could be flushed. | |
| if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero()) | |
| return; | |
| // If we know the input can't be a denormal, it can't be flushed to 0. | |
| if (Src.isKnownNeverSubnormal()) | |
| return; | |
| if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE()) | |
| setKnownFPClasses(getKnownFPClasses() | fcPosZero); | |
| if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) { | |
| if (Mode != DenormalMode::getPositiveZero()) | |
| setKnownFPClasses(getKnownFPClasses() | fcNegZero); | |
| if (Mode.Input == DenormalMode::PositiveZero || | |
| Mode.Output == DenormalMode::PositiveZero || | |
| Mode.Input == DenormalMode::Dynamic || | |
| Mode.Output == DenormalMode::Dynamic) | |
| setKnownFPClasses(getKnownFPClasses() | fcPosZero); | |
| } | |
| } | |
| KnownFPClass KnownFPClass::minMaxLike(const KnownFPClass &LHS_, | |
| const KnownFPClass &RHS_, MinMaxKind Kind, | |
| DenormalMode Mode) { | |
| KnownFPClass KnownLHS = LHS_; | |
| KnownFPClass KnownRHS = RHS_; | |
| bool NeverNaN = KnownLHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNaN(); | |
| KnownFPClass Known = KnownLHS | KnownRHS; | |
| // If either operand is not NaN, the result is not NaN. | |
| if (NeverNaN && | |
| (Kind == MinMaxKind::minnum || Kind == MinMaxKind::maxnum || | |
| Kind == MinMaxKind::minimumnum || Kind == MinMaxKind::maximumnum)) | |
| Known.knownNot(fcNan); | |
| if (Kind == MinMaxKind::maxnum || Kind == MinMaxKind::maximumnum) { | |
| if (KnownLHS.isKnownNeverNaN()) | |
| Known.knownNot(orderedStrictlyLess(KnownLHS.getKnownFPClasses())); | |
| if (KnownRHS.isKnownNeverNaN()) | |
| Known.knownNot(orderedStrictlyLess(KnownRHS.getKnownFPClasses())); | |
| } else if (Kind == MinMaxKind::maximum) { | |
| Known.knownNot(orderedStrictlyLess(KnownLHS.getKnownFPClasses()) | | |
| orderedStrictlyLess(KnownRHS.getKnownFPClasses())); | |
| } else if (Kind == MinMaxKind::minnum || Kind == MinMaxKind::minimumnum) { | |
| if (KnownLHS.isKnownNeverNaN()) | |
| Known.knownNot(orderedStrictlyGreater(KnownLHS.getKnownFPClasses())); | |
| if (KnownRHS.isKnownNeverNaN()) | |
| Known.knownNot(orderedStrictlyGreater(KnownRHS.getKnownFPClasses())); | |
| } else if (Kind == MinMaxKind::minimum) { | |
| Known.knownNot(orderedStrictlyGreater(KnownLHS.getKnownFPClasses()) | | |
| orderedStrictlyGreater(KnownRHS.getKnownFPClasses())); | |
| } else | |
| llvm_unreachable("unhandled intrinsic"); | |
| // Fixup zero handling if denormals could be returned as a zero. | |
| // | |
| // As there's no spec for denormal flushing, be conservative with the | |
| // treatment of denormals that could be flushed to zero. For older | |
| // subtargets on AMDGPU the min/max instructions would not flush the | |
| // output and return the original value. | |
| // | |
| if ((Known.getKnownFPClasses() & fcZero) != fcNone && | |
| !Known.isKnownNeverSubnormal()) { | |
| if (Mode != DenormalMode::getIEEE()) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcZero); | |
| } | |
| if (Known.isKnownNeverNaN()) { | |
| if (KnownLHS.getSignBit() && KnownRHS.getSignBit() && | |
| *KnownLHS.getSignBit() == *KnownRHS.getSignBit()) { | |
| if (*KnownLHS.getSignBit()) | |
| Known.signBitMustBeOne(); | |
| else | |
| Known.signBitMustBeZero(); | |
| } else if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::minimum || | |
| Kind == MinMaxKind::maximumnum || | |
| Kind == MinMaxKind::minimumnum) || | |
| // FIXME: Should be using logical zero versions | |
| ((KnownLHS.isKnownNeverNegZero() || | |
| KnownRHS.isKnownNeverPosZero()) && | |
| (KnownLHS.isKnownNeverPosZero() || | |
| KnownRHS.isKnownNeverNegZero()))) { | |
| // Don't take sign bit from NaN operands. | |
| if (!KnownLHS.isKnownNeverNaN()) | |
| KnownLHS.setSignBit(std::nullopt); | |
| if (!KnownRHS.isKnownNeverNaN()) | |
| KnownRHS.setSignBit(std::nullopt); | |
| if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::maximumnum || | |
| Kind == MinMaxKind::maxnum) && | |
| (KnownLHS.getSignBit() == false || KnownRHS.getSignBit() == false)) | |
| Known.signBitMustBeZero(); | |
| else if ((Kind == MinMaxKind::minimum || Kind == MinMaxKind::minimumnum || | |
| Kind == MinMaxKind::minnum) && | |
| (KnownLHS.getSignBit() == true || KnownRHS.getSignBit() == true)) | |
| Known.signBitMustBeOne(); | |
| } | |
| } | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::canonicalize(const KnownFPClass &KnownSrc, | |
| DenormalMode DenormMode) { | |
| KnownFPClass Known; | |
| // This is essentially a stronger form of | |
| // propagateCanonicalizingSrc. Other "canonicalizing" operations don't | |
| // actually have an IR canonicalization guarantee. | |
| // Canonicalize may flush denormals to zero, so we have to consider the | |
| // denormal mode to preserve known-not-0 knowledge. | |
| Known.setKnownFPClasses(KnownSrc.getKnownFPClasses() | fcZero | fcQNan); | |
| // Stronger version of propagateNaN | |
| // Canonicalize is guaranteed to quiet signaling nans. | |
| if (KnownSrc.isKnownNeverNaN()) | |
| Known.knownNot(fcNan); | |
| else | |
| Known.knownNot(fcSNan); | |
| // FIXME: Missing check of IEEE like types. | |
| // If the parent function flushes denormals, the canonical output cannot be a | |
| // denormal. | |
| if (DenormMode == DenormalMode::getIEEE()) { | |
| if (KnownSrc.isKnownNever(fcPosZero)) | |
| Known.knownNot(fcPosZero); | |
| if (KnownSrc.isKnownNever(fcNegZero)) | |
| Known.knownNot(fcNegZero); | |
| return Known; | |
| } | |
| if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero()) | |
| Known.knownNot(fcSubnormal); | |
| if (DenormMode == DenormalMode::getPreserveSign()) { | |
| if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal)) | |
| Known.knownNot(fcPosZero); | |
| if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal)) | |
| Known.knownNot(fcNegZero); | |
| return Known; | |
| } | |
| if (DenormMode.Input == DenormalMode::PositiveZero || | |
| (DenormMode.Output == DenormalMode::PositiveZero && | |
| DenormMode.Input == DenormalMode::IEEE)) { | |
| // -0.0 is not a subnormal and should not be flushed. | |
| if (KnownSrc.isKnownNever(fcNegZero)) | |
| Known.knownNot(fcNegZero); | |
| if (KnownSrc.isKnownNever(fcPosZero | fcSubnormal)) | |
| Known.knownNot(fcPosZero); | |
| } | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics, | |
| const KnownBits &Bits) { | |
| assert(FltSemantics.sizeInBits == Bits.getBitWidth() && | |
| "Bitcast operand has incorrect bit width"); | |
| KnownFPClass Known; | |
| // Conflicting known bits do not describe a concrete value. Return unknown. | |
| if (Bits.hasConflict()) | |
| return Known; | |
| // Return unknown for types we have not validated. | |
| auto IsSupported = [](const fltSemantics &Semantics) { | |
| switch (APFloat::SemanticsToEnum(Semantics)) { | |
| case APFloatBase::S_IEEEhalf: | |
| case APFloatBase::S_BFloat: | |
| case APFloatBase::S_IEEEsingle: | |
| case APFloatBase::S_IEEEdouble: | |
| case APFloatBase::S_IEEEquad: | |
| case APFloatBase::S_x87DoubleExtended: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| }; | |
| if (!IsSupported(FltSemantics)) | |
| return Known; | |
| // Transfer information from the sign bit. | |
| if (Bits.isNonNegative()) | |
| Known.signBitMustBeZero(); | |
| else if (Bits.isNegative()) | |
| Known.signBitMustBeOne(); | |
| if (APFloat::isIEEELikeFP(FltSemantics)) { | |
| const unsigned MantissaBits = FltSemantics.precision - 1; | |
| const APInt ExponentMask = APInt::getBitsSet( | |
| FltSemantics.sizeInBits, MantissaBits, FltSemantics.sizeInBits - 1); | |
| const APInt MantissaMask = | |
| APInt::getLowBitsSet(FltSemantics.sizeInBits, MantissaBits); | |
| const bool ExponentKnownAllZeros = | |
| (Bits.Zero & ExponentMask) == ExponentMask; | |
| const bool ExponentKnownAllOnes = (Bits.One & ExponentMask) == ExponentMask; | |
| const bool ExponentKnownNotAllZeros = !(Bits.One & ExponentMask).isZero(); | |
| const bool ExponentKnownNotAllOnes = !(Bits.Zero & ExponentMask).isZero(); | |
| const bool MantissaKnownAllZeros = | |
| (Bits.Zero & MantissaMask) == MantissaMask; | |
| const bool MantissaKnownNotAllZeros = !(Bits.One & MantissaMask).isZero(); | |
| // Zero and subnormal require an exponent with all zero bits. | |
| if (ExponentKnownNotAllZeros) | |
| Known.knownNot(fcZero | fcSubnormal); | |
| // Infinity and NaN require an exponent with all one bits. | |
| if (ExponentKnownNotAllOnes) | |
| Known.knownNot(fcInf | fcNan); | |
| // Normal values have an exponent that is not all zeros or all ones. | |
| if (ExponentKnownAllZeros || ExponentKnownAllOnes) | |
| Known.knownNot(fcNormal); | |
| // Zero and infinity require a mantissa with all zero bits. | |
| if (MantissaKnownNotAllZeros) | |
| Known.knownNot(fcZero | fcInf); | |
| // Subnormal and NaN require a non-zero mantissa. | |
| if (MantissaKnownAllZeros) | |
| Known.knownNot(fcSubnormal | fcNan); | |
| const bool QuietBitKnownSet = Bits.One[MantissaBits - 1]; | |
| const bool QuietBitKnownClear = Bits.Zero[MantissaBits - 1]; | |
| if (QuietBitKnownSet) | |
| Known.knownNot(fcSNan); | |
| else if (QuietBitKnownClear) | |
| Known.knownNot(fcQNan); | |
| } | |
| return Known; | |
| } | |
| KnownBits KnownFPClass::toKnownBits(const fltSemantics &FltSemantics) const { | |
| KnownBits Known(FltSemantics.sizeInBits); | |
| const FPClassTest FPClasses = getKnownFPClasses(); | |
| // Return unknown if poison. | |
| if (FPClasses == fcNone) | |
| return Known; | |
| // Return unknown for types we have not validated. | |
| auto IsSupported = [](const fltSemantics &Semantics) { | |
| switch (APFloat::SemanticsToEnum(Semantics)) { | |
| case APFloatBase::S_IEEEhalf: | |
| case APFloatBase::S_BFloat: | |
| case APFloatBase::S_IEEEsingle: | |
| case APFloatBase::S_IEEEdouble: | |
| case APFloatBase::S_IEEEquad: | |
| case APFloatBase::S_x87DoubleExtended: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| }; | |
| if (!IsSupported(FltSemantics)) | |
| return Known; | |
| switch (APFloat::SemanticsToEnum(FltSemantics)) { | |
| case APFloatBase::S_IEEEhalf: | |
| case APFloatBase::S_BFloat: | |
| case APFloatBase::S_IEEEsingle: | |
| case APFloatBase::S_IEEEdouble: | |
| case APFloatBase::S_IEEEquad: { | |
| // For ieee types, we cannot deduce anything if the source could be normal. | |
| if (FPClasses & fcNormal) | |
| break; | |
| Known.setAllConflict(); | |
| const unsigned BitWidth = FltSemantics.sizeInBits; | |
| const unsigned MantissaBits = FltSemantics.precision - 1; | |
| const unsigned ExponentBits = BitWidth - MantissaBits - 1; | |
| APInt MantissaMask = APInt::getLowBitsSet(BitWidth, MantissaBits); | |
| APInt ExponentMask = | |
| APInt::getBitsSet(BitWidth, MantissaBits, MantissaBits + ExponentBits); | |
| const unsigned QuietBitIndex = MantissaBits - 1; | |
| APInt PayloadMask = MantissaMask; | |
| PayloadMask.clearBit(QuietBitIndex); | |
| if (FPClasses & fcNan) { | |
| // Exponent bits cannot be zeros. | |
| Known.Zero &= ~ExponentMask; | |
| // No individual payload bit is known. | |
| Known.Zero &= ~PayloadMask; | |
| Known.One &= ~PayloadMask; | |
| if (FPClasses & fcQNan) | |
| Known.Zero.clearBit(QuietBitIndex); | |
| if (FPClasses & fcSNan) | |
| Known.One.clearBit(QuietBitIndex); | |
| } | |
| if (FPClasses & fcInf) { | |
| // Exponent bits cannot be zeros. | |
| Known.Zero &= ~ExponentMask; | |
| // Mantissa bits cannot be ones. | |
| Known.One &= ~MantissaMask; | |
| } | |
| if (FPClasses & fcSubnormal) { | |
| // Exponent bits cannot be ones. | |
| Known.One &= ~ExponentMask; | |
| // Unknown mantissa. | |
| Known.One &= ~MantissaMask; | |
| Known.Zero &= ~MantissaMask; | |
| } | |
| if (FPClasses & fcZero) { | |
| // Exponent bits cannot be ones. | |
| Known.One &= ~ExponentMask; | |
| // Mantissa cannot be ones. | |
| Known.One &= ~MantissaMask; | |
| } | |
| break; | |
| } | |
| case APFloatBase::S_x87DoubleExtended: { | |
| if (!isKnownNever(fcNormal | fcSubnormal | fcNan)) | |
| break; | |
| Known.setAllConflict(); | |
| if (FPClasses & fcInf) | |
| Known = Known.intersectWith(KnownBits::makeConstant( | |
| APFloat::getInf(FltSemantics).bitcastToAPInt())); | |
| if (FPClasses & fcZero) | |
| Known = Known.intersectWith( | |
| KnownBits::makeConstant(APInt::getZero(FltSemantics.sizeInBits))); | |
| break; | |
| } | |
| default: | |
| llvm_unreachable("unhandled supported semantics"); | |
| } | |
| Known.Zero.clearSignBit(); | |
| Known.One.clearSignBit(); | |
| if (std::optional<bool> Sign = getSignBit()) { | |
| if (*Sign) | |
| Known.makeNegative(); | |
| else | |
| Known.makeNonNegative(); | |
| } | |
| return Known; | |
| } | |
| // Handle known sign bit and nan cases for fadd. | |
| static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, DenormalMode Mode) { | |
| KnownFPClass Known; | |
| // Adding positive and negative infinity produces NaN, but only if both | |
| // opposite-sign infinity combinations are possible. | |
| if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && | |
| (KnownLHS.isKnownNever(fcPosInf) || KnownRHS.isKnownNever(fcNegInf)) && | |
| (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcPosInf))) | |
| Known.knownNot(fcNan); | |
| if (KnownLHS.cannotBeOrderedLessThanZero() && | |
| KnownRHS.cannotBeOrderedLessThanZero()) { | |
| Known.knownNot(KnownFPClass::OrderedLessThanZeroMask); | |
| // This can't underflow if one of the operands is known normal. | |
| if (KnownLHS.isKnownNever(fcZero | fcPosSubnormal) || | |
| KnownRHS.isKnownNever(fcZero | fcPosSubnormal)) | |
| Known.knownNot(fcZero | fcPosSubnormal); | |
| } | |
| if (KnownLHS.cannotBeOrderedGreaterThanZero() && | |
| KnownRHS.cannotBeOrderedGreaterThanZero()) { | |
| Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask); | |
| // This can't underflow if one of the operands is known normal. | |
| if (KnownLHS.isKnownNever(fcZero | fcNegSubnormal) || | |
| KnownRHS.isKnownNever(fcZero | fcNegSubnormal)) | |
| Known.knownNot(fcZero | fcNegSubnormal); | |
| } | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fadd(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, | |
| DenormalMode Mode) { | |
| KnownFPClass Known = fadd_impl(KnownLHS, KnownRHS, Mode); | |
| // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0. | |
| if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) || | |
| KnownRHS.isKnownNeverLogicalNegZero(Mode)) && | |
| // Make sure output negative denormal can't flush to -0 | |
| (Mode.Output == DenormalMode::IEEE || | |
| Mode.Output == DenormalMode::PositiveZero)) | |
| Known.knownNot(fcNegZero); | |
| Known.propagateNonSNaN(KnownLHS, KnownRHS); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fadd_self(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| KnownFPClass Known = fadd(KnownSrc, KnownSrc, Mode); | |
| // Doubling 0 will give the same 0. | |
| if (KnownSrc.isKnownNeverLogicalPosZero(Mode) && | |
| (Mode.Output == DenormalMode::IEEE || | |
| (Mode.Output == DenormalMode::PreserveSign && | |
| KnownSrc.isKnownNeverPosSubnormal()) || | |
| (Mode.Output == DenormalMode::PositiveZero && | |
| KnownSrc.isKnownNeverSubnormal()))) | |
| Known.knownNot(fcPosZero); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fsub(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, | |
| DenormalMode Mode) { | |
| return fadd(KnownLHS, fneg(KnownRHS), Mode); | |
| } | |
| KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, | |
| DenormalMode Mode) { | |
| KnownFPClass Known; | |
| Known.propagateNonSNaN(KnownLHS, KnownRHS); | |
| // +X * +Y or -X * -Y => +Q | |
| // +X * -Y or -X * +Y => -Q | |
| Known.propagateXorSign(KnownLHS, KnownRHS, Mode); | |
| // Inf * Y => Inf or NaN | |
| if (KnownLHS.isKnownAlways(fcInf | fcNan) || | |
| KnownRHS.isKnownAlways(fcInf | fcNan)) | |
| Known.knownNot(fcNormal | fcSubnormal | fcZero); | |
| // 0 * Y => 0 or NaN | |
| if (KnownRHS.isKnownAlways(fcZero | fcNan) || | |
| KnownLHS.isKnownAlways(fcZero | fcNan)) | |
| Known.knownNot(fcNormal | fcSubnormal | fcInf); | |
| if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN()) | |
| return Known; | |
| // 0 * +/-inf => NaN | |
| if ((KnownRHS.isKnownNeverInfinity() || | |
| KnownLHS.isKnownNeverLogicalZero(Mode)) && | |
| (KnownLHS.isKnownNeverInfinity() || | |
| KnownRHS.isKnownNeverLogicalZero(Mode))) | |
| Known.knownNot(fcNan); | |
| return Known; | |
| } | |
| // TODO: This generalizes to known ranges | |
| KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS, | |
| const APFloat &CRHS, DenormalMode Mode) { | |
| // Match denormal scaling pattern, similar to the case in ldexp. If the | |
| // constant's exponent is sufficiently large, the result cannot be subnormal. | |
| const fltSemantics &Flt = CRHS.getSemantics(); | |
| unsigned Precision = APFloat::semanticsPrecision(Flt); | |
| const int MantissaBits = Precision - 1; | |
| int MinKnownExponent = ilogb(CRHS); | |
| bool CannotBeSubnormal = (MinKnownExponent >= MantissaBits); | |
| KnownFPClass Known = KnownFPClass::fmul(KnownLHS, KnownFPClass(CRHS), Mode); | |
| if (CannotBeSubnormal) | |
| Known.knownNot(fcSubnormal); | |
| // Multiply of values <= 1 cannot introduce overflow. | |
| if (KnownLHS.isKnownNever(fcInf)) { | |
| if (MinKnownExponent < 0) | |
| Known.knownNot(fcInf); | |
| else if (MinKnownExponent == 0 && CRHS.compareAbsoluteValue(APFloat::getOne( | |
| Flt)) == APFloat::cmpEqual) | |
| Known.knownNot(fcInf); | |
| } | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fdiv(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, | |
| DenormalMode Mode) { | |
| KnownFPClass Known; | |
| Known.propagateNonSNaN(KnownLHS, KnownRHS); | |
| // Only 0/0, Inf/Inf produce NaN. | |
| if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && | |
| (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()) && | |
| (KnownLHS.isKnownNeverLogicalZero(Mode) || | |
| KnownRHS.isKnownNeverLogicalZero(Mode))) { | |
| Known.knownNot(fcNan); | |
| } | |
| // X / -0.0 => -Inf (or NaN) | |
| // +X / +Y or -X / -Y => +Q | |
| // +X / -Y or -X / +Y => -Q | |
| Known.propagateXorSign(KnownLHS, KnownRHS, Mode); | |
| // Normal and subnormal results require two non-zero finite operands. | |
| if ((KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal) && | |
| KnownRHS.isKnownNever(fcNegNormal | fcNegSubnormal)) || | |
| (KnownLHS.isKnownNever(fcPosNormal | fcPosSubnormal) && | |
| KnownRHS.isKnownNever(fcPosNormal | fcPosSubnormal))) | |
| Known.knownNot(fcNegNormal | fcNegSubnormal); | |
| if ((KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal) && | |
| KnownRHS.isKnownNever(fcPosNormal | fcPosSubnormal)) || | |
| (KnownLHS.isKnownNever(fcPosNormal | fcPosSubnormal) && | |
| KnownRHS.isKnownNever(fcNegNormal | fcNegSubnormal))) | |
| Known.knownNot(fcPosNormal | fcPosSubnormal); | |
| // 0 / X => 0 or NaN | |
| if (KnownLHS.isKnownAlways(fcZero)) | |
| Known.knownNot(fcSubnormal | fcNormal | fcInf); | |
| // X / 0 => NaN or Inf | |
| if (KnownRHS.isKnownAlways(fcZero)) | |
| Known.knownNot(fcFinite); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fdiv_self(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| // X / X is always exactly 1.0 or a NaN. | |
| KnownFPClass Known(fcNan | fcPosNormal); | |
| Known.propagateNonSNaN(KnownSrc); | |
| if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode)) | |
| Known.knownNot(fcNan); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::frem(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, | |
| DenormalMode Mode) { | |
| KnownFPClass Known; | |
| // We are assuming that frem(x, Inf) is already handled elsewhere. | |
| Known.knownNot(fcInf); | |
| Known.propagateNonSNaN(KnownLHS, KnownRHS); | |
| // frem(Inf, x) and frem(x, 0) produce NaN. | |
| if (KnownLHS.isKnownNeverInfOrNaN() && KnownRHS.isKnownNeverNaN() && | |
| KnownRHS.isKnownNeverLogicalZero(Mode)) { | |
| Known.knownNot(fcNan); | |
| } | |
| // The sign for frem is the same as the first operand. | |
| if (KnownLHS.isKnownNever(fcPosNormal | fcPosSubnormal)) | |
| Known.knownNot(fcPosNormal | fcPosSubnormal); | |
| if (KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal)) | |
| Known.knownNot(fcNegNormal | fcNegSubnormal); | |
| // A negative zero result requires a negative finite first operand. | |
| if (KnownLHS.isKnownNever(fcNegFinite)) | |
| Known.knownNot(fcNegZero); | |
| // A positive zero result can additionally come from a negative finite | |
| // result being flushed to positive zero. | |
| if (KnownLHS.isKnownNever(fcPosFinite) && | |
| KnownLHS.isKnownNeverLogicalPosZero(Mode) && | |
| (!Mode.outputsMayBePositiveZero() || | |
| KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal))) | |
| Known.knownNot(fcPosZero); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::frem_self(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| // X % X is always exactly [+-]0.0 or a NaN. | |
| KnownFPClass Known(fcNan | fcZero); | |
| Known.propagateNonSNaN(KnownSrc); | |
| if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode)) | |
| Known.knownNot(fcNan); | |
| // The sign of a zero result is the sign of the finite non-zero input. | |
| // We do not have to worry about subnormal values flushing to zero, since | |
| // frem(+-0.0, +-0.0) = NaN. | |
| if (KnownSrc.isKnownNever(fcPosNormal | fcPosSubnormal)) | |
| Known.knownNot(fcPosZero); | |
| if (KnownSrc.isKnownNever(fcNegNormal | fcNegSubnormal)) | |
| Known.knownNot(fcNegZero); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fma(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS, | |
| const KnownFPClass &KnownAddend, | |
| DenormalMode Mode) { | |
| KnownFPClass Mul = fmul(KnownLHS, KnownRHS, Mode); | |
| // FMA differs from the base fmul + fadd handling only in the treatment of -0 | |
| // results. | |
| // | |
| // If the multiply is a -0 due to rounding, the final -0 + 0 will be -0, | |
| // unlike for a separate fadd. | |
| KnownFPClass Known = fadd_impl(Mul, KnownAddend, Mode); | |
| // propagateNonSNaN for 3 arguments. | |
| if (KnownLHS.isKnownNever(fcSNan) && KnownRHS.isKnownNever(fcSNan) && | |
| KnownAddend.isKnownNever(fcSNan)) | |
| Known.knownNot(fcSNan); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fma_square(const KnownFPClass &KnownSquared, | |
| const KnownFPClass &KnownAddend, | |
| DenormalMode Mode) { | |
| KnownFPClass Squared = square(KnownSquared, Mode); | |
| KnownFPClass Known = fadd_impl(Squared, KnownAddend, Mode); | |
| // Since we know the squared input must be positive, the add of opposite sign | |
| // infinities nan hazard only applies for negative inf. | |
| // | |
| // TODO: Alternatively to proving addend is not -inf, we could know Squared is | |
| // not pinf. Other than the degenerate always-subnormal input case, we can't | |
| // prove that without a known range. | |
| if (KnownAddend.isKnownNever(fcNegInf | fcNan) && Squared.isKnownNever(fcNan)) | |
| Known.knownNot(fcNan); | |
| Known.propagateNonSNaN(KnownSquared, KnownAddend); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| Known.knownNot(fcNegative); | |
| Known.propagateNonNaN(KnownSrc); | |
| // The following deductions assume that exp10(-1.0) = +0.1 and | |
| // exp10(+1.0) = +10.0 are both finite normal values. | |
| // Zero can only be produced if x < -1.0. | |
| if (KnownSrc.isKnownNever(fcNegNormal | fcNegInf)) | |
| Known.knownNot(fcPosZero); | |
| // Subnormals can only be produced if x < -1.0 and x is finite. | |
| if (KnownSrc.isKnownNever(fcNegNormal)) | |
| Known.knownNot(fcPosSubnormal); | |
| // Infinity can only be produced if x > +1.0. | |
| if (KnownSrc.isKnownNever(fcPosNormal | fcPosInf)) | |
| Known.knownNot(fcPosInf); | |
| return Known; | |
| } | |
| void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src, | |
| DenormalMode Mode) { | |
| propagateDenormal(Src, Mode); | |
| propagateNonNaN(Src); | |
| } | |
| KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| KnownFPClass Known; | |
| Known.knownNot(fcNegZero | fcSubnormal); | |
| Known.propagateNonSNaN(KnownSrc); | |
| if (KnownSrc.isKnownNeverPosInfinity()) | |
| Known.knownNot(fcPosInf); | |
| if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero()) | |
| Known.knownNot(fcNan); | |
| if (KnownSrc.isKnownNeverLogicalZero(Mode)) | |
| Known.knownNot(fcNegInf); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::sqrt(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| KnownFPClass Known; | |
| Known.knownNot(fcPosSubnormal); | |
| if (KnownSrc.isKnownNeverPosInfinity()) | |
| Known.knownNot(fcPosInf); | |
| Known.propagateNonSNaN(KnownSrc); | |
| // Any negative value besides -0.0 returns a nan. | |
| if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero()) | |
| Known.knownNot(fcNan); | |
| // The only negative value that can be returned is -0.0 for -0.0 inputs. | |
| Known.knownNot(fcNegInf | fcNegSubnormal | fcNegNormal); | |
| // Only sqrt(+0.0) == +0.0. However, subnormals may also be treated as +0.0 | |
| // depending on the input denormal mode. | |
| if (KnownSrc.isKnownNeverLogicalPosZero(Mode)) | |
| Known.knownNot(fcPosZero); | |
| // Only sqrt(-0.0) == -0.0. However, negative subnormals may also be treated | |
| // as -0.0 depending on the input denormal mode. | |
| if (KnownSrc.isKnownNeverLogicalNegZero(Mode)) | |
| Known.knownNot(fcNegZero); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::sin(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| Known.propagateNonSNaN(KnownSrc); | |
| // Return NaN on infinite inputs. | |
| Known.knownNot(fcInf); | |
| if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity()) | |
| Known.knownNot(fcNan); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::cos(const KnownFPClass &KnownSrc) { | |
| return sin(KnownSrc); | |
| } | |
| KnownFPClass KnownFPClass::tan(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // tan never returns Inf (tan(+-Inf) = NaN; tan(finite) = finite). | |
| Known.knownNot(fcInf); | |
| Known.propagateNonSNaN(KnownSrc); | |
| // NaN propagates. tan(+-Inf) is NaN. | |
| if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity()) | |
| Known.knownNot(fcNan); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::sinh(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // sinh is sign-preserving: sinh(x) < 0 iff x < 0. | |
| if (KnownSrc.isKnownNever(fcNegative)) | |
| Known.knownNot(fcNegative); | |
| Known.propagateNonNaN(KnownSrc); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::cosh(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // cosh(x) >= 1 for all real x; cosh(+-Inf) = +Inf. Never negative, | |
| // zero, or subnormal. | |
| Known.knownNot(fcNegative | fcZero | fcSubnormal); | |
| Known.propagateNonNaN(KnownSrc); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::tanh(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // tanh is bounded to (-1, 1), never Inf. | |
| Known.knownNot(fcInf); | |
| // tanh is sign-preserving: tanh(x) < 0 iff x < 0. | |
| if (KnownSrc.isKnownNever(fcNegative)) | |
| Known.knownNot(fcNegative); | |
| Known.propagateNonNaN(KnownSrc); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::asin(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // asin is bounded to [-pi/2, pi/2], never Inf. | |
| Known.knownNot(fcInf); | |
| Known.propagateNonSNaN(KnownSrc); | |
| // asin is sign-preserving for finite arguments. | |
| if (KnownSrc.isKnownNever(fcNegFinite)) | |
| Known.knownNot(fcNegFinite); | |
| // NaN propagates. asin(x) is also NaN for |x| > 1, so we cannot rule | |
| // out NaN without knowing the source is in [-1, 1]. | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::acos(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // acos(x) is bounded to [0, pi] for -1 <= x <= 1, and is never negative, | |
| // infinite, or subnormal. The smallest non-zero value occurs when x is | |
| // close to 1.0, where acos(x) can be approximated by sqrt(2 * (1 - x)). | |
| // Since sqrt cannot produce a subnormal result, we can conclude that | |
| // acos(x) will also never produce a subnormal result. | |
| Known.knownNot(fcNegative | fcInf | fcSubnormal); | |
| // acos(x) == +0.0 iff x == +1.0 | |
| if (KnownSrc.isKnownNever(fcPosNormal)) | |
| Known.knownNot(fcZero); | |
| Known.propagateNonSNaN(KnownSrc); | |
| // NaN propagates. acos(x) is also NaN for |x| > 1, so we cannot rule | |
| // out NaN without knowing the source is in [-1, 1]. | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::atan(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // atan is bounded to (-pi/2, pi/2), never Inf. atan(+-Inf) = +-pi/2 (finite). | |
| Known.knownNot(fcInf); | |
| // atan is sign-preserving: atan(x) < 0 iff x < 0. | |
| if (KnownSrc.isKnownNever(fcNegative)) | |
| Known.knownNot(fcNegative); | |
| Known.propagateNonNaN(KnownSrc); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::atan2(const KnownFPClass &KnownY_, | |
| const KnownFPClass &KnownX_, | |
| DenormalMode Mode) { | |
| KnownFPClass KnownY = applyInputDenormalMode(KnownY_, Mode); | |
| KnownFPClass KnownX = applyInputDenormalMode(KnownX_, Mode); | |
| KnownFPClass Known; | |
| // Even though these deductions are correct, we are ignoring the following | |
| // potentially erroneous cases: | |
| // * atan2(y, inf) is not subnormal | |
| // * atan2(inf, x) is not zero or subnormal | |
| // atan2 result is in (-pi, pi], never Inf. | |
| Known.knownNot(fcInf); | |
| Known.propagateNonNaN(KnownY, KnownX); | |
| // If x <= -0.0, then |atan2(y, x)| >= pi/2 | |
| if (KnownX.isKnownNever(fcPositive)) | |
| Known.knownNot(fcZero | fcSubnormal); | |
| // If y >= +0.0, then atan2(y, x) >= +0.0 | |
| if (KnownY.isKnownNever(fcNegative)) | |
| Known.knownNot(fcNegative); | |
| // If y <= -0.0, then atan2(y, x) <= -0.0 | |
| if (KnownY.isKnownNever(fcPositive)) | |
| Known.knownNot(fcPositive); | |
| return applyOutputDenormalMode(Known, Mode); | |
| } | |
| KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc, | |
| const fltSemantics &DstTy, | |
| const fltSemantics &SrcTy) { | |
| // Infinity, nan and zero propagate from source. | |
| KnownFPClass Known = KnownSrc; | |
| // All subnormal inputs should be in the normal range in the result type. | |
| if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) { | |
| if (Known.getKnownFPClasses() & fcPosSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcPosNormal); | |
| if (Known.getKnownFPClasses() & fcNegSubnormal) | |
| Known.setKnownFPClasses(Known.getKnownFPClasses() | fcNegNormal); | |
| Known.knownNot(fcSubnormal); | |
| } | |
| // Sign bit of a nan isn't guaranteed. | |
| if (!Known.isKnownNeverNaN()) | |
| Known.setSignBit(std::nullopt); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::fptrunc(const KnownFPClass &KnownSrc) { | |
| KnownFPClass Known; | |
| // Sign should be preserved | |
| // TODO: Handle cannot be ordered greater than zero | |
| if (KnownSrc.cannotBeOrderedLessThanZero()) | |
| Known.knownNot(KnownFPClass::OrderedLessThanZeroMask); | |
| Known.propagateNonNaN(KnownSrc); | |
| // Infinity needs a range check. | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::roundToIntegral(const KnownFPClass &KnownSrc, | |
| bool IsTrunc, | |
| bool IsMultiUnitFPType) { | |
| KnownFPClass Known; | |
| // Integer results cannot be subnormal. | |
| Known.knownNot(fcSubnormal); | |
| Known.propagateNonNaN(KnownSrc); | |
| // Pass through infinities, except PPC_FP128 is a special case for | |
| // intrinsics other than trunc. | |
| if (IsTrunc || !IsMultiUnitFPType) { | |
| if (KnownSrc.isKnownNeverPosInfinity()) | |
| Known.knownNot(fcPosInf); | |
| if (KnownSrc.isKnownNeverNegInfinity()) | |
| Known.knownNot(fcNegInf); | |
| } | |
| // Negative round ups to 0 produce -0 | |
| if (KnownSrc.isKnownNever(fcPosFinite)) | |
| Known.knownNot(fcPosFinite); | |
| if (KnownSrc.isKnownNever(fcNegFinite)) | |
| Known.knownNot(fcNegFinite); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::frexp_mant(const KnownFPClass &KnownSrc, | |
| DenormalMode Mode) { | |
| KnownFPClass Known; | |
| Known.knownNot(fcSubnormal); | |
| Known.propagateNonNaN(KnownSrc); | |
| if (KnownSrc.isKnownNeverPosInfinity()) | |
| Known.knownNot(fcPosInf); | |
| if (KnownSrc.isKnownNeverNegInfinity()) | |
| Known.knownNot(fcNegInf); | |
| if (KnownSrc.isKnownNeverLogicalPosZero(Mode)) | |
| Known.knownNot(fcPosZero); | |
| if (KnownSrc.isKnownNeverLogicalNegZero(Mode)) | |
| Known.knownNot(fcNegZero); | |
| // TODO: These deductions can be improved if subnormal inputs are guaranteed | |
| // to be flushed to zero. | |
| if (KnownSrc.isKnownNever(fcPosNormal | fcPosSubnormal)) | |
| Known.knownNot(fcPosNormal); | |
| if (KnownSrc.isKnownNever(fcNegNormal | fcNegSubnormal)) | |
| Known.knownNot(fcNegNormal); | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc_, | |
| const APInt &ConstantRangeExpMin, | |
| const APInt &ConstantRangeExpMax, | |
| const fltSemantics &Flt, DenormalMode Mode) { | |
| KnownFPClass Known; | |
| KnownFPClass KnownSrc = applyInputDenormalMode(KnownSrc_, Mode); | |
| if (ConstantRangeExpMin.isZero() && ConstantRangeExpMax.isZero()) { | |
| // ldexp(x, 0) -> x | |
| // Here we make sure to properly propagate sNaN and denormals. | |
| Known.setKnownFPClasses(KnownSrc.getKnownFPClasses() | fcNan); | |
| Known.propagateNonNaN(KnownSrc); | |
| return applyOutputDenormalMode(Known, Mode); | |
| } | |
| Known.propagateNonNaN(KnownSrc); | |
| // Sign is preserved, but underflows may produce zeroes. | |
| if (KnownSrc.isKnownNever(fcNegative)) | |
| Known.knownNot(fcNegative); | |
| else if (KnownSrc.cannotBeOrderedLessThanZero()) | |
| Known.knownNot(OrderedLessThanZeroMask); | |
| if (KnownSrc.isKnownNever(fcPositive)) | |
| Known.knownNot(fcPositive); | |
| else if (KnownSrc.cannotBeOrderedGreaterThanZero()) | |
| Known.knownNot(OrderedGreaterThanZeroMask); | |
| // TODO: determine when it is safe to rule out subnormal for ppcf128. | |
| if (&Flt != &APFloat::PPCDoubleDouble()) { | |
| unsigned Precision = APFloat::semanticsPrecision(Flt); | |
| const int MantissaBits = Precision - 1; | |
| if (ConstantRangeExpMin.sge(MantissaBits)) | |
| Known.knownNot(fcSubnormal); | |
| } | |
| if (ConstantRangeExpMax.isNonPositive()) { | |
| // If we know the power is <= 0, can't introduce inf | |
| if (KnownSrc.isKnownNeverPosInfinity()) | |
| Known.knownNot(fcPosInf); | |
| if (KnownSrc.isKnownNeverNegInfinity()) | |
| Known.knownNot(fcNegInf); | |
| } else if (ConstantRangeExpMin.isNonNegative()) { | |
| // If we know the power is >= 0, can't introduce subnormal or zero | |
| if (KnownSrc.isKnownNeverPosSubnormal()) | |
| Known.knownNot(fcPosSubnormal); | |
| if (KnownSrc.isKnownNeverNegSubnormal()) | |
| Known.knownNot(fcNegSubnormal); | |
| if (KnownSrc.isKnownNeverPosZero()) | |
| Known.knownNot(fcPosZero); | |
| if (KnownSrc.isKnownNeverNegZero()) | |
| Known.knownNot(fcNegZero); | |
| } | |
| return applyOutputDenormalMode(Known, Mode); | |
| } | |
| KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc, | |
| const KnownBits &ExpBits, | |
| const fltSemantics &Flt, DenormalMode Mode) { | |
| return ldexp(KnownSrc, ExpBits.getSignedMinValue(), | |
| ExpBits.getSignedMaxValue(), Flt, Mode); | |
| } | |
| KnownFPClass KnownFPClass::pow(const KnownFPClass &KnownLHS, | |
| const KnownFPClass &KnownRHS) { | |
| KnownFPClass Known; | |
| Known.propagateNonSNaN(KnownLHS, KnownRHS); | |
| // pow may return NaN if one of the arguments is NaN. NaN may be produced from | |
| // a non-zero-finite-negative base and a non-integer exponent. | |
| if (KnownLHS.isKnownNever(fcNan | fcNegNormal | fcNegSubnormal) && | |
| KnownRHS.isKnownNeverNaN()) | |
| Known.knownNot(fcNan); | |
| // We could rule out negative and subnormal results when exponent is known to | |
| // never be a normal value, but having either argument being known to never be | |
| // normal is unlikely and not worth considering. | |
| // Only a negative base raised to an odd power returns a negative value. | |
| if (KnownLHS.isKnownNever(fcNegative)) { | |
| Known.knownNot(fcNegative); | |
| } else if (KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal)) { | |
| Known.knownNot(fcNegNormal | fcNegSubnormal); | |
| // See if we can also rule out -0.0 or -inf. | |
| // Here at least one of -0.0 or -inf is a possible base. | |
| // pow(-0.0, odd-positive) = -0.0 | |
| // pow(-inf, odd-negative) = -0.0 | |
| if ((KnownLHS.isKnownNever(fcNegZero) || | |
| KnownRHS.isKnownNever(fcPosNormal)) && | |
| (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcNegNormal))) | |
| Known.knownNot(fcNegZero); | |
| // pow(-0.0, odd-negative) = -inf | |
| // pow(-inf, odd-positive) = -inf | |
| if ((KnownLHS.isKnownNever(fcNegZero) || | |
| KnownRHS.isKnownNever(fcNegNormal)) && | |
| (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcPosNormal))) | |
| Known.knownNot(fcNegInf); | |
| } | |
| return Known; | |
| } | |
| KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc, | |
| const KnownBits &ExponentKnownBits) { | |
| KnownFPClass Known; | |
| Known.propagateNonNaN(KnownSrc); | |
| if (ExponentKnownBits.isZero()) { | |
| // powi(QNaN, 0) returns 1.0, and powi(SNaN, 0) may non-deterministically | |
| // return 1.0 or a NaN. | |
| if (KnownSrc.isKnownNever(fcSNan)) { | |
| Known.knownNot(~fcPosNormal); | |
| return Known; | |
| } | |
| Known.knownNot(~(fcPosNormal | fcNan)); | |
| return Known; | |
| } | |
| // Given that exp is an integer, here are the | |
| // ways that powi can return a negative value: | |
| // | |
| // powi(x, exp) --> negative if exp is odd and x is negative. | |
| // powi(-0, exp) --> -inf if exp is negative odd. | |
| // powi(-0, exp) --> -0 if exp is positive odd. | |
| // powi(-inf, exp) --> -0 if exp is negative odd. | |
| // powi(-inf, exp) --> -inf if exp is positive odd. | |
| if (KnownSrc.isKnownNever(fcNegative) || ExponentKnownBits.isEven()) { | |
| Known.knownNot(fcNegative); | |
| } else if (KnownSrc.isKnownNever(fcNegNormal | fcNegSubnormal)) { | |
| Known.knownNot(fcNegNormal | fcNegSubnormal); | |
| // See if we can also rule out -0.0 or -inf. | |
| // Here at least one of -0.0 or -inf is a possible base. | |
| // We already know that ExponentKnownBits.isEven() is false here. | |
| const bool IsKnownNeverOddPositive = ExponentKnownBits.isNegative(); | |
| const bool IsKnownNeverOddNegative = ExponentKnownBits.isNonNegative(); | |
| // powi(-0.0, odd-positive) = -0.0 | |
| // powi(-inf, odd-negative) = -0.0 | |
| if ((KnownSrc.isKnownNever(fcNegZero) || IsKnownNeverOddPositive) && | |
| (KnownSrc.isKnownNever(fcNegInf) || IsKnownNeverOddNegative)) | |
| Known.knownNot(fcNegZero); | |
| // powi(-0.0, odd-negative) = -inf | |
| // powi(-inf, odd-positive) = -inf | |
| if ((KnownSrc.isKnownNever(fcNegZero) || IsKnownNeverOddNegative) && | |
| (KnownSrc.isKnownNever(fcNegInf) || IsKnownNeverOddPositive)) | |
| Known.knownNot(fcNegInf); | |
| } | |
| // powi(x, exp) --> inf | |
| // when: | |
| // * powi(inf, exp), exp > 0 | |
| // * powi(+/-0, exp), exp < 0 | |
| // * powi(finite, exp), |exp| > 1 | |
| // * powi(subnormal, -1) | |
| // TODO: | |
| // 1. This simple all or nothing approach. We can do better | |
| // and cover sign/parity and exp > 1 vs exp < -1 separately. | |
| // 2. powi(0/nan, exp), exp > 0 can be refinable | |
| // to fcNan | fcZero | fcPosNormal. | |
| { | |
| APInt MinExp = ExponentKnownBits.getSignedMinValue(); | |
| APInt MaxExp = ExponentKnownBits.getSignedMaxValue(); | |
| // powi(inf, exp), exp > 0 | |
| bool MayInfSrc = | |
| !KnownSrc.isKnownNever(fcInf) && MaxExp.isStrictlyPositive(); | |
| // powi(+/-0, exp), exp < 0 | |
| bool MayDivByZero = !KnownSrc.isKnownNever(fcZero) && MinExp.isNegative(); | |
| // powi(finite, exp), |exp| > 1 | |
| bool MayFinite = !KnownSrc.isKnownNever(fcNormal | fcSubnormal); | |
| bool MayAbsExpGT1 = MinExp.slt(-1) || MaxExp.sgt(1); | |
| bool MayFiniteOverflow = MayFinite && MayAbsExpGT1; | |
| // powi(subnormal, -1) | |
| bool MayBeNegOne = ExponentKnownBits.Zero.isZero(); | |
| bool MaySubnormInv = !KnownSrc.isKnownNever(fcSubnormal) && MayBeNegOne; | |
| if (!MayInfSrc && !MayDivByZero && !MayFiniteOverflow && !MaySubnormInv) | |
| Known.knownNot(fcInf); | |
| } | |
| return Known; | |
| } |