From e12b73816b50bbe2cc54b8005d86c95413b4f465 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sun, 28 Feb 2010 02:51:25 +0000 Subject: [PATCH] Teach APFloat how to create both QNaNs and SNaNs and with arbitrary-width payloads. APFloat's internal folding routines always make QNaNs now, instead of sometimes making QNaNs and sometimes SNaNs depending on the type. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@97364 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/APFloat.h | 32 +++++++++++-- include/llvm/ADT/APInt.h | 3 ++ lib/Support/APFloat.cpp | 47 ++++++++++++++----- lib/Support/APInt.cpp | 10 +++- ...2009-01-19-fmod-constant-float-specials.ll | 3 +- unittests/ADT/APFloatTest.cpp | 29 ++++++++++++ 6 files changed, 107 insertions(+), 17 deletions(-) diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index f81109af417..861b7b99e9c 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -173,11 +173,16 @@ namespace llvm { fcZero }; + enum uninitializedTag { + uninitialized + }; + // Constructors. APFloat(const fltSemantics &); // Default construct to 0.0 APFloat(const fltSemantics &, const StringRef &); APFloat(const fltSemantics &, integerPart); - APFloat(const fltSemantics &, fltCategory, bool negative, unsigned type=0); + APFloat(const fltSemantics &, fltCategory, bool negative); + APFloat(const fltSemantics &, uninitializedTag); explicit APFloat(double d); explicit APFloat(float f); explicit APFloat(const APInt &, bool isIEEE = false); @@ -199,7 +204,26 @@ namespace llvm { /// default. The value is truncated as necessary. static APFloat getNaN(const fltSemantics &Sem, bool Negative = false, unsigned type = 0) { - return APFloat(Sem, fcNaN, Negative, type); + if (type) { + APInt fill(64, type); + return getQNaN(Sem, Negative, &fill); + } else { + return getQNaN(Sem, Negative, 0); + } + } + + /// getQNan - Factory for QNaN values. + static APFloat getQNaN(const fltSemantics &Sem, + bool Negative = false, + const APInt *payload = 0) { + return makeNaN(Sem, false, Negative, payload); + } + + /// getSNan - Factory for SNaN values. + static APFloat getSNaN(const fltSemantics &Sem, + bool Negative = false, + const APInt *payload = 0) { + return makeNaN(Sem, true, Negative, payload); } /// getLargest - Returns the largest finite number in the given @@ -350,7 +374,9 @@ namespace llvm { opStatus modSpecials(const APFloat &); /* Miscellany. */ - void makeNaN(unsigned = 0); + static APFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative, + const APInt *fill); + void makeNaN(bool SNaN = false, bool Neg = false, const APInt *fill = 0); opStatus normalize(roundingMode, lostFraction); opStatus addOrSubtract(const APFloat &, roundingMode, bool subtract); cmpResult compareAbsoluteValue(const APFloat &) const; diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 88aa9956d93..ea940ad1783 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -1308,6 +1308,9 @@ public: /// Set the given bit of a bignum. Zero-based. static void tcSetBit(integerPart *, unsigned int bit); + /// Clear the given bit of a bignum. Zero-based. + static void tcClearBit(integerPart *, unsigned int bit); + /// Returns the bit number of the least or most significant set bit /// of a number. If the input number has no bits set -1U is /// returned. diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index f90973feab8..4f1b85431cc 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -626,17 +626,37 @@ APFloat::copySignificand(const APFloat &rhs) /* Make this number a NaN, with an arbitrary but deterministic value for the significand. If double or longer, this is a signalling NaN, which may not be ideal. If float, this is QNaN(0). */ -void -APFloat::makeNaN(unsigned type) +void APFloat::makeNaN(bool SNaN, bool Negative, const APInt *fill) { category = fcNaN; - // FIXME: Add double and long double support for QNaN(0). - if (semantics->precision == 24 && semantics->maxExponent == 127) { - type |= 0x7fc00000U; - type &= ~0x80000000U; - } else - type = ~0U; - APInt::tcSet(significandParts(), type, partCount()); + sign = Negative; + + // Set the significand bits to the fill. + if (!fill || fill->getNumWords() < partCount()) + APInt::tcSet(significandParts(), 0, partCount()); + if (fill) + APInt::tcAssign(significandParts(), fill->getRawData(), partCount()); + + if (SNaN) { + // We always have to clear the QNaN bit to make it an SNaN. + APInt::tcClearBit(significandParts(), semantics->precision - 2); + + // If there are no bits set in the payload, we have to set + // *something* to make it a NaN instead of an infinity; + // conventionally, this is the next bit down from the QNaN bit. + if (APInt::tcIsZero(significandParts(), partCount())) + APInt::tcSetBit(significandParts(), semantics->precision - 3); + } else { + // We always have to set the QNaN bit to make it a QNaN. + APInt::tcSetBit(significandParts(), semantics->precision - 2); + } +} + +APFloat APFloat::makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative, + const APInt *fill) { + APFloat value(Sem, uninitialized); + value.makeNaN(SNaN, Negative, fill); + return value; } APFloat & @@ -701,9 +721,14 @@ APFloat::APFloat(const fltSemantics &ourSemantics) { sign = false; } +APFloat::APFloat(const fltSemantics &ourSemantics, uninitializedTag tag) { + assertArithmeticOK(ourSemantics); + // Allocates storage if necessary but does not initialize it. + initialize(&ourSemantics); +} APFloat::APFloat(const fltSemantics &ourSemantics, - fltCategory ourCategory, bool negative, unsigned type) + fltCategory ourCategory, bool negative) { assertArithmeticOK(ourSemantics); initialize(&ourSemantics); @@ -712,7 +737,7 @@ APFloat::APFloat(const fltSemantics &ourSemantics, if (category == fcNormal) category = fcZero; else if (ourCategory == fcNaN) - makeNaN(type); + makeNaN(); } APFloat::APFloat(const fltSemantics &ourSemantics, const StringRef& text) diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 3bce3f3ed3f..6a6384aa3f4 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -2344,13 +2344,21 @@ APInt::tcExtractBit(const integerPart *parts, unsigned int bit) & ((integerPart) 1 << bit % integerPartWidth)) != 0; } -/* Set the given bit of a bignum. */ +/* Set the given bit of a bignum. */ void APInt::tcSetBit(integerPart *parts, unsigned int bit) { parts[bit / integerPartWidth] |= (integerPart) 1 << (bit % integerPartWidth); } +/* Clears the given bit of a bignum. */ +void +APInt::tcClearBit(integerPart *parts, unsigned int bit) +{ + parts[bit / integerPartWidth] &= + ~((integerPart) 1 << (bit % integerPartWidth)); +} + /* Returns the bit number of the least significant set bit of a number. If the input number has no bits set -1U is returned. */ unsigned int diff --git a/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll b/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll index 79a2f1fd8eb..142134791ef 100644 --- a/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll +++ b/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll @@ -1,5 +1,4 @@ -; RUN: opt < %s -simplifycfg -instcombine -S | grep 0x7FF8000000000000 | count 7 -; RUN: opt < %s -simplifycfg -instcombine -S | grep 0x7FF00000FFFFFFFF | count 5 +; RUN: opt < %s -simplifycfg -instcombine -S | grep 0x7FF8000000000000 | count 12 ; RUN: opt < %s -simplifycfg -instcombine -S | grep {0\\.0} | count 3 ; RUN: opt < %s -simplifycfg -instcombine -S | grep {3\\.5} | count 1 ; diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 3277c836da2..571996013e3 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -344,6 +344,35 @@ TEST(APFloatTest, toString) { ASSERT_EQ("8.731834E+2", convertToString(873.1834, 0, 0)); } +static APInt nanbits(const fltSemantics &Sem, + bool SNaN, bool Negative, uint64_t fill) { + APInt apfill(64, fill); + if (SNaN) + return APFloat::getSNaN(Sem, Negative, &apfill).bitcastToAPInt(); + else + return APFloat::getQNaN(Sem, Negative, &apfill).bitcastToAPInt(); +} + +TEST(APFloatTest, makeNaN) { + ASSERT_EQ(0x7fc00000, nanbits(APFloat::IEEEsingle, false, false, 0)); + ASSERT_EQ(0xffc00000, nanbits(APFloat::IEEEsingle, false, true, 0)); + ASSERT_EQ(0x7fc0ae72, nanbits(APFloat::IEEEsingle, false, false, 0xae72)); + ASSERT_EQ(0x7fffae72, nanbits(APFloat::IEEEsingle, false, false, 0xffffae72)); + ASSERT_EQ(0x7fa00000, nanbits(APFloat::IEEEsingle, true, false, 0)); + ASSERT_EQ(0xffa00000, nanbits(APFloat::IEEEsingle, true, true, 0)); + ASSERT_EQ(0x7f80ae72, nanbits(APFloat::IEEEsingle, true, false, 0xae72)); + ASSERT_EQ(0x7fbfae72, nanbits(APFloat::IEEEsingle, true, false, 0xffffae72)); + + ASSERT_EQ(0x7ff8000000000000ULL, nanbits(APFloat::IEEEdouble, false, false, 0)); + ASSERT_EQ(0xfff8000000000000ULL, nanbits(APFloat::IEEEdouble, false, true, 0)); + ASSERT_EQ(0x7ff800000000ae72ULL, nanbits(APFloat::IEEEdouble, false, false, 0xae72)); + ASSERT_EQ(0x7fffffffffffae72ULL, nanbits(APFloat::IEEEdouble, false, false, 0xffffffffffffae72ULL)); + ASSERT_EQ(0x7ff4000000000000ULL, nanbits(APFloat::IEEEdouble, true, false, 0)); + ASSERT_EQ(0xfff4000000000000ULL, nanbits(APFloat::IEEEdouble, true, true, 0)); + ASSERT_EQ(0x7ff000000000ae72ULL, nanbits(APFloat::IEEEdouble, true, false, 0xae72)); + ASSERT_EQ(0x7ff7ffffffffae72ULL, nanbits(APFloat::IEEEdouble, true, false, 0xffffffffffffae72ULL)); +} + #ifdef GTEST_HAS_DEATH_TEST TEST(APFloatTest, SemanticsDeath) { EXPECT_DEATH(APFloat(APFloat::IEEEsingle, 0.0f).convertToDouble(), "Float semantics are not IEEEdouble"); -- 2.34.1