summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ADT/APFloat.h2
-rw-r--r--lib/Support/APFloat.cpp18
-rw-r--r--unittests/ADT/APFloatTest.cpp49
3 files changed, 69 insertions, 0 deletions
diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h
index 21b8c86d1d..d2566a44ba 100644
--- a/include/llvm/ADT/APFloat.h
+++ b/include/llvm/ADT/APFloat.h
@@ -109,6 +109,7 @@ namespace llvm {
typedef signed short exponent_t;
struct fltSemantics;
+ class APSInt;
class StringRef;
/* When bits of a floating point number are truncated, this enum is
@@ -283,6 +284,7 @@ namespace llvm {
opStatus convert(const fltSemantics &, roundingMode, bool *);
opStatus convertToInteger(integerPart *, unsigned int, bool,
roundingMode, bool *) const;
+ opStatus convertToInteger(APSInt&, roundingMode, bool *) const;
opStatus convertFromAPInt(const APInt &,
bool, roundingMode);
opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp
index c3169acabb..a46cc8dfa4 100644
--- a/lib/Support/APFloat.cpp
+++ b/lib/Support/APFloat.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/ErrorHandling.h"
@@ -2084,6 +2085,23 @@ APFloat::convertToInteger(integerPart *parts, unsigned int width,
return fs;
}
+/* Same as convertToInteger(integerPart*, ...), except the result is returned in
+ an APSInt, whose initial bit-width and signed-ness are used to determine the
+ precision of the conversion.
+ */
+APFloat::opStatus
+APFloat::convertToInteger(APSInt &result,
+ roundingMode rounding_mode, bool *isExact) const
+{
+ unsigned bitWidth = result.getBitWidth();
+ SmallVector<uint64_t, 4> parts(result.getNumWords());
+ opStatus status = convertToInteger(
+ parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact);
+ // Keeps the original signed-ness.
+ result = APInt(bitWidth, parts.size(), parts.data());
+ return status;
+}
+
/* Convert an unsigned integer SRC to a floating point number,
rounding according to ROUNDING_MODE. The sign of the floating
point number is not modified. */
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp
index 5f05b86169..08ac2a0525 100644
--- a/unittests/ADT/APFloatTest.cpp
+++ b/unittests/ADT/APFloatTest.cpp
@@ -12,6 +12,7 @@
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -344,6 +345,54 @@ TEST(APFloatTest, toString) {
ASSERT_EQ("8.731834E+2", convertToString(873.1834, 0, 0));
}
+TEST(APFloatTest, toInteger) {
+ bool isExact = false;
+ APSInt result(5, /*isUnsigned=*/true);
+
+ EXPECT_EQ(APFloat::opOK,
+ APFloat(APFloat::IEEEdouble, "10")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_TRUE(isExact);
+ EXPECT_EQ(APSInt(APInt(5, 10), true), result);
+
+ EXPECT_EQ(APFloat::opInvalidOp,
+ APFloat(APFloat::IEEEdouble, "-10")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_FALSE(isExact);
+ EXPECT_EQ(APSInt::getMinValue(5, true), result);
+
+ EXPECT_EQ(APFloat::opInvalidOp,
+ APFloat(APFloat::IEEEdouble, "32")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_FALSE(isExact);
+ EXPECT_EQ(APSInt::getMaxValue(5, true), result);
+
+ EXPECT_EQ(APFloat::opInexact,
+ APFloat(APFloat::IEEEdouble, "7.9")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_FALSE(isExact);
+ EXPECT_EQ(APSInt(APInt(5, 7), true), result);
+
+ result.setIsUnsigned(false);
+ EXPECT_EQ(APFloat::opOK,
+ APFloat(APFloat::IEEEdouble, "-10")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_TRUE(isExact);
+ EXPECT_EQ(APSInt(APInt(5, -10, true), false), result);
+
+ EXPECT_EQ(APFloat::opInvalidOp,
+ APFloat(APFloat::IEEEdouble, "-17")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_FALSE(isExact);
+ EXPECT_EQ(APSInt::getMinValue(5, false), result);
+
+ EXPECT_EQ(APFloat::opInvalidOp,
+ APFloat(APFloat::IEEEdouble, "16")
+ .convertToInteger(result, APFloat::rmTowardZero, &isExact));
+ EXPECT_FALSE(isExact);
+ EXPECT_EQ(APSInt::getMaxValue(5, false), result);
+}
+
static APInt nanbits(const fltSemantics &Sem,
bool SNaN, bool Negative, uint64_t fill) {
APInt apfill(64, fill);