Index: llvm/include/llvm/ADT/APFloat.h =================================================================== --- llvm/include/llvm/ADT/APFloat.h +++ llvm/include/llvm/ADT/APFloat.h @@ -393,6 +393,10 @@ /// magnitude in the current semantics. bool isSmallest() const; + /// Returns true if this is the smallest (by magnitude) normalized finite + /// number in the given semantics. + bool isSmallestNormalized() const; + /// Returns true if and only if the number has the largest possible finite /// magnitude in the current semantics. bool isLargest() const; @@ -517,6 +521,7 @@ bool isSignificandAllOnesExceptLSB() const; /// Return true if the significand excluding the integral bit is all zeros. bool isSignificandAllZeros() const; + bool isSignificandAllZerosExceptMSB() const; /// @} @@ -694,6 +699,7 @@ bool isDenormal() const; bool isSmallest() const; + bool isSmallestNormalized() const; bool isLargest() const; bool isInteger() const; @@ -1247,6 +1253,10 @@ bool isInteger() const { APFLOAT_DISPATCH_ON_SEMANTICS(isInteger()); } bool isIEEE() const { return usesLayout(getSemantics()); } + bool isSmallestNormalized() const { + APFLOAT_DISPATCH_ON_SEMANTICS(isSmallestNormalized()); + } + APFloat &operator=(const APFloat &RHS) = default; APFloat &operator=(APFloat &&RHS) = default; Index: llvm/lib/Support/APFloat.cpp =================================================================== --- llvm/lib/Support/APFloat.cpp +++ llvm/lib/Support/APFloat.cpp @@ -883,6 +883,11 @@ significandMSB() == 0; } +bool IEEEFloat::isSmallestNormalized() const { + return getCategory() == fcNormal && exponent == semantics->minExponent && + isSignificandAllZerosExceptMSB(); +} + bool IEEEFloat::isSignificandAllOnes() const { // Test if the significand excluding the integral bit is all ones. This allows // us to test for binade boundaries. @@ -955,6 +960,21 @@ return true; } +bool IEEEFloat::isSignificandAllZerosExceptMSB() const { + const integerPart *Parts = significandParts(); + const unsigned PartCount = partCountForBits(semantics->precision); + + for (unsigned i = 0; i < PartCount - 1; i++) { + if (Parts[i]) + return false; + } + + const unsigned NumHighBits = + PartCount * integerPartWidth - semantics->precision + 1; + return Parts[PartCount - 1] == integerPart(1) + << (integerPartWidth - NumHighBits); +} + bool IEEEFloat::isLargest() const { if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly) { // The largest number by magnitude in our format will be the floating point @@ -4998,6 +5018,15 @@ return Tmp.compare(*this) == cmpEqual; } +bool DoubleAPFloat::isSmallestNormalized() const { + if (getCategory() != fcNormal) + return false; + + DoubleAPFloat Tmp(*this); + Tmp.makeSmallestNormalized(this->isNegative()); + return Tmp.compare(*this) == cmpEqual; +} + bool DoubleAPFloat::isLargest() const { if (getCategory() != fcNormal) return false; Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -6781,7 +6781,7 @@ return nullptr; if (!C->isPosZero()) { - if (*C != APFloat::getSmallestNormalized(C->getSemantics())) + if (!C->isSmallestNormalized()) return nullptr; const Function *F = I.getFunction(); Index: llvm/unittests/ADT/APFloatTest.cpp =================================================================== --- llvm/unittests/ADT/APFloatTest.cpp +++ llvm/unittests/ADT/APFloatTest.cpp @@ -664,6 +664,57 @@ } } +TEST(APFloatTest, IsSmallestNormalized) { + for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) { + const fltSemantics &Semantics = + APFloat::EnumToSemantics(static_cast(I)); + + EXPECT_FALSE(APFloat::getZero(Semantics, false).isSmallestNormalized()); + EXPECT_FALSE(APFloat::getZero(Semantics, true).isSmallestNormalized()); + + EXPECT_FALSE(APFloat::getInf(Semantics, false).isSmallestNormalized()); + EXPECT_FALSE(APFloat::getInf(Semantics, true).isSmallestNormalized()); + + EXPECT_FALSE(APFloat::getQNaN(Semantics).isSmallestNormalized()); + EXPECT_FALSE(APFloat::getSNaN(Semantics).isSmallestNormalized()); + + EXPECT_FALSE(APFloat::getLargest(Semantics).isSmallestNormalized()); + EXPECT_FALSE(APFloat::getLargest(Semantics, true).isSmallestNormalized()); + + EXPECT_FALSE(APFloat::getSmallest(Semantics).isSmallestNormalized()); + EXPECT_FALSE(APFloat::getSmallest(Semantics, true).isSmallestNormalized()); + + EXPECT_FALSE(APFloat::getAllOnesValue(Semantics).isSmallestNormalized()); + + APFloat PosSmallestNormalized = + APFloat::getSmallestNormalized(Semantics, false); + APFloat NegSmallestNormalized = + APFloat::getSmallestNormalized(Semantics, true); + EXPECT_TRUE(PosSmallestNormalized.isSmallestNormalized()); + EXPECT_TRUE(NegSmallestNormalized.isSmallestNormalized()); + + for (APFloat *Val : {&PosSmallestNormalized, &NegSmallestNormalized}) { + bool OldSign = Val->isNegative(); + + // Step down, make sure it's still not smallest normalized. + EXPECT_EQ(APFloat::opOK, Val->next(false)); + EXPECT_EQ(OldSign, Val->isNegative()); + EXPECT_FALSE(Val->isSmallestNormalized()); + EXPECT_EQ(OldSign, Val->isNegative()); + + // Step back up should restore it to being smallest normalized. + EXPECT_EQ(APFloat::opOK, Val->next(true)); + EXPECT_TRUE(Val->isSmallestNormalized()); + EXPECT_EQ(OldSign, Val->isNegative()); + + // Step beyond should no longer smallest normalized. + EXPECT_EQ(APFloat::opOK, Val->next(true)); + EXPECT_FALSE(Val->isSmallestNormalized()); + EXPECT_EQ(OldSign, Val->isNegative()); + } + } +} + TEST(APFloatTest, Zero) { EXPECT_EQ(0.0f, APFloat(0.0f).convertToFloat()); EXPECT_EQ(-0.0f, APFloat(-0.0f).convertToFloat()); @@ -1723,6 +1774,7 @@ EXPECT_TRUE(test.isFiniteNonZero()); EXPECT_FALSE(test.isDenormal()); EXPECT_TRUE(test.bitwiseIsEqual(expected)); + EXPECT_TRUE(test.isSmallestNormalized()); test = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true); expected = APFloat(APFloat::IEEEsingle(), "-0x1p-126"); @@ -1730,6 +1782,23 @@ EXPECT_TRUE(test.isFiniteNonZero()); EXPECT_FALSE(test.isDenormal()); EXPECT_TRUE(test.bitwiseIsEqual(expected)); + EXPECT_TRUE(test.isSmallestNormalized()); + + test = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), false); + expected = APFloat(APFloat::IEEEdouble(), "0x1p-1022"); + EXPECT_FALSE(test.isNegative()); + EXPECT_TRUE(test.isFiniteNonZero()); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + EXPECT_TRUE(test.isSmallestNormalized()); + + test = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), true); + expected = APFloat(APFloat::IEEEdouble(), "-0x1p-1022"); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.isFiniteNonZero()); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + EXPECT_TRUE(test.isSmallestNormalized()); test = APFloat::getSmallestNormalized(APFloat::IEEEquad(), false); expected = APFloat(APFloat::IEEEquad(), "0x1p-16382"); @@ -1737,6 +1806,7 @@ EXPECT_TRUE(test.isFiniteNonZero()); EXPECT_FALSE(test.isDenormal()); EXPECT_TRUE(test.bitwiseIsEqual(expected)); + EXPECT_TRUE(test.isSmallestNormalized()); test = APFloat::getSmallestNormalized(APFloat::IEEEquad(), true); expected = APFloat(APFloat::IEEEquad(), "-0x1p-16382"); @@ -1744,6 +1814,7 @@ EXPECT_TRUE(test.isFiniteNonZero()); EXPECT_FALSE(test.isDenormal()); EXPECT_TRUE(test.bitwiseIsEqual(expected)); + EXPECT_TRUE(test.isSmallestNormalized()); } TEST(APFloatTest, getZero) {