[llvm] dd3014f - [Fixed Point] Add floating point methods to APFixedPoint.

Bevin Hansson via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 9 01:31:26 PDT 2020


Author: Bevin Hansson
Date: 2020-10-09T10:27:42+02:00
New Revision: dd3014f3dc7c1a42614be0488b0ab79bdcce995c

URL: https://github.com/llvm/llvm-project/commit/dd3014f3dc7c1a42614be0488b0ab79bdcce995c
DIFF: https://github.com/llvm/llvm-project/commit/dd3014f3dc7c1a42614be0488b0ab79bdcce995c.diff

LOG: [Fixed Point] Add floating point methods to APFixedPoint.

This adds methods to APFixedPoint for converting to and from
floating point values.

Differential Revision: https://reviews.llvm.org/D85961

Added: 
    

Modified: 
    llvm/include/llvm/ADT/APFixedPoint.h
    llvm/lib/Support/APFixedPoint.cpp
    llvm/unittests/ADT/APFixedPointTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/APFixedPoint.h b/llvm/include/llvm/ADT/APFixedPoint.h
index f63ff15cdf7d..d6349e6b2a88 100644
--- a/llvm/include/llvm/ADT/APFixedPoint.h
+++ b/llvm/include/llvm/ADT/APFixedPoint.h
@@ -22,6 +22,9 @@
 
 namespace llvm {
 
+class APFloat;
+struct fltSemantics;
+
 /// The fixed point semantics work similarly to fltSemantics. The width
 /// specifies the whole bit width of the underlying scaled integer (with padding
 /// if any). The scale represents the number of fractional bits in this type.
@@ -63,6 +66,15 @@ class FixedPointSemantics {
   FixedPointSemantics
   getCommonSemantics(const FixedPointSemantics &Other) const;
 
+  /// Returns true if this fixed-point semantic with its value bits interpreted
+  /// as an integer can fit in the given floating point semantic without
+  /// overflowing to infinity.
+  /// For example, a signed 8-bit fixed-point semantic has a maximum and
+  /// minimum integer representation of 127 and -128, respectively. If both of
+  /// these values can be represented (possibly inexactly) in the floating
+  /// point semantic without overflowing, this returns true.
+  bool fitsInFloatSemantics(const fltSemantics &FloatSema) const;
+
   /// Return the FixedPointSemantics for an integer type.
   static FixedPointSemantics GetIntegerSemantics(unsigned Width,
                                                  bool IsSigned) {
@@ -153,12 +165,13 @@ class APFixedPoint {
   /// If the overflow parameter is provided, and the integral value is not able
   /// to be fully stored in the provided width and sign, the overflow parameter
   /// is set to true.
-  ///
-  /// If the overflow parameter is provided, set this value to true or false to
-  /// indicate if this operation results in an overflow.
   APSInt convertToInt(unsigned DstWidth, bool DstSign,
                       bool *Overflow = nullptr) const;
 
+  /// Convert this fixed point number to a floating point value with the
+  /// provided semantics.
+  APFloat convertToFloat(const fltSemantics &FloatSema) const;
+
   void toString(SmallVectorImpl<char> &Str) const;
   std::string toString() const {
     SmallString<40> S;
@@ -186,6 +199,10 @@ class APFixedPoint {
   static APFixedPoint getMax(const FixedPointSemantics &Sema);
   static APFixedPoint getMin(const FixedPointSemantics &Sema);
 
+  /// Given a floating point semantic, return the next floating point semantic
+  /// with a larger exponent and larger or equal mantissa.
+  static const fltSemantics *promoteFloatSemantics(const fltSemantics *S);
+
   /// Create an APFixedPoint with a value equal to that of the provided integer,
   /// and in the same semantics as the provided target semantics. If the value
   /// is not able to fit in the specified fixed point semantics, and the
@@ -194,6 +211,17 @@ class APFixedPoint {
                                       const FixedPointSemantics &DstFXSema,
                                       bool *Overflow = nullptr);
 
+  /// Create an APFixedPoint with a value equal to that of the provided
+  /// floating point value, in the provided target semantics. If the value is
+  /// not able to fit in the specified fixed point semantics and the overflow
+  /// parameter is specified, it is set to true.
+  /// For NaN, the Overflow flag is always set. For +inf and -inf, if the
+  /// semantic is saturating, the value saturates. Otherwise, the Overflow flag
+  /// is set.
+  static APFixedPoint getFromFloatValue(const APFloat &Value,
+                                        const FixedPointSemantics &DstFXSema,
+                                        bool *Overflow = nullptr);
+
 private:
   APSInt Val;
   FixedPointSemantics Sema;
@@ -204,6 +232,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) {
   return OS;
 }
 
-}  // namespace llvm
+} // namespace llvm
 
 #endif

diff  --git a/llvm/lib/Support/APFixedPoint.cpp b/llvm/lib/Support/APFixedPoint.cpp
index ebb434276634..9764dd51f572 100644
--- a/llvm/lib/Support/APFixedPoint.cpp
+++ b/llvm/lib/Support/APFixedPoint.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ADT/APFixedPoint.h"
+#include "llvm/ADT/APFloat.h"
 
 namespace llvm {
 
@@ -124,6 +125,29 @@ APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
   return APFixedPoint(Val, Sema);
 }
 
+bool FixedPointSemantics::fitsInFloatSemantics(
+    const fltSemantics &FloatSema) const {
+  // A fixed point semantic fits in a floating point semantic if the maximum
+  // and minimum values as integers of the fixed point semantic can fit in the
+  // floating point semantic.
+
+  // If these values do not fit, then a floating point rescaling of the true
+  // maximum/minimum value will not fit either, so the floating point semantic
+  // cannot be used to perform such a rescaling.
+
+  APSInt MaxInt = APFixedPoint::getMax(*this).getValue();
+  APFloat F(FloatSema);
+  APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(),
+                                                APFloat::rmNearestTiesToAway);
+  if ((Status & APFloat::opOverflow) || !isSigned())
+    return !(Status & APFloat::opOverflow);
+
+  APSInt MinInt = APFixedPoint::getMin(*this).getValue();
+  Status = F.convertFromAPInt(MinInt, MinInt.isSigned(),
+                              APFloat::rmNearestTiesToAway);
+  return !(Status & APFloat::opOverflow);
+}
+
 FixedPointSemantics FixedPointSemantics::getCommonSemantics(
     const FixedPointSemantics &Other) const {
   unsigned CommonScale = std::max(getScale(), Other.getScale());
@@ -417,6 +441,54 @@ APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
   return Result.extOrTrunc(DstWidth);
 }
 
+const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) {
+  if (S == &APFloat::BFloat())
+    return &APFloat::IEEEdouble();
+  else if (S == &APFloat::IEEEhalf())
+    return &APFloat::IEEEsingle();
+  else if (S == &APFloat::IEEEsingle())
+    return &APFloat::IEEEdouble();
+  else if (S == &APFloat::IEEEdouble())
+    return &APFloat::IEEEquad();
+  llvm_unreachable("Could not promote float type!");
+}
+
+APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {
+  // For some operations, rounding mode has an effect on the result, while
+  // other operations are lossless and should never result in rounding.
+  // To signify which these operations are, we define two rounding modes here.
+  APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
+  APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
+
+  // Make sure that we are operating in a type that works with this fixed-point
+  // semantic.
+  const fltSemantics *OpSema = &FloatSema;
+  while (!Sema.fitsInFloatSemantics(*OpSema))
+    OpSema = promoteFloatSemantics(OpSema);
+
+  // Convert the fixed point value bits as an integer. If the floating point
+  // value does not have the required precision, we will round according to the
+  // given mode.
+  APFloat Flt(*OpSema);
+  APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM);
+
+  // If we cared about checking for precision loss, we could look at this
+  // status.
+  (void)S;
+
+  // Scale down the integer value in the float to match the correct scaling
+  // factor.
+  APFloat ScaleFactor(std::pow(2, -(int)Sema.getScale()));
+  bool Ignored;
+  ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
+  Flt.multiply(ScaleFactor, LosslessRM);
+
+  if (OpSema != &FloatSema)
+    Flt.convert(FloatSema, RM, &Ignored);
+
+  return Flt;
+}
+
 APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
                                            const FixedPointSemantics &DstFXSema,
                                            bool *Overflow) {
@@ -425,4 +497,78 @@ APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
   return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
 }
 
-}  // namespace clang
+APFixedPoint
+APFixedPoint::getFromFloatValue(const APFloat &Value,
+                                const FixedPointSemantics &DstFXSema,
+                                bool *Overflow) {
+  // For some operations, rounding mode has an effect on the result, while
+  // other operations are lossless and should never result in rounding.
+  // To signify which these operations are, we define two rounding modes here,
+  // even though they are the same mode.
+  APFloat::roundingMode RM = APFloat::rmTowardZero;
+  APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
+
+  const fltSemantics &FloatSema = Value.getSemantics();
+
+  if (Value.isNaN()) {
+    // Handle NaN immediately.
+    if (Overflow)
+      *Overflow = true;
+    return APFixedPoint(DstFXSema);
+  }
+
+  // Make sure that we are operating in a type that works with this fixed-point
+  // semantic.
+  const fltSemantics *OpSema = &FloatSema;
+  while (!DstFXSema.fitsInFloatSemantics(*OpSema))
+    OpSema = promoteFloatSemantics(OpSema);
+
+  APFloat Val = Value;
+
+  bool Ignored;
+  if (&FloatSema != OpSema)
+    Val.convert(*OpSema, LosslessRM, &Ignored);
+
+  // Scale up the float so that the 'fractional' part of the mantissa ends up in
+  // the integer range instead. Rounding mode is irrelevant here.
+  // It is fine if this overflows to infinity even for saturating types,
+  // since we will use floating point comparisons to check for saturation.
+  APFloat ScaleFactor(std::pow(2, DstFXSema.getScale()));
+  ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
+  Val.multiply(ScaleFactor, LosslessRM);
+
+  // Convert to the integral representation of the value. This rounding mode
+  // is significant.
+  APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned());
+  Val.convertToInteger(Res, RM, &Ignored);
+
+  // Round the integral value and scale back. This makes the
+  // overflow calculations below work properly. If we do not round here,
+  // we risk checking for overflow with a value that is outside the
+  // representable range of the fixed-point semantic even though no overflow
+  // would occur had we rounded first.
+  ScaleFactor = APFloat(std::pow(2, -(int)DstFXSema.getScale()));
+  ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
+  Val.roundToIntegral(RM);
+  Val.multiply(ScaleFactor, LosslessRM);
+
+  // Check for overflow/saturation by checking if the floating point value
+  // is outside the range representable by the fixed-point value.
+  APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema);
+  APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema);
+  bool Overflowed = false;
+  if (DstFXSema.isSaturated()) {
+    if (Val > FloatMax)
+      Res = getMax(DstFXSema).getValue();
+    else if (Val < FloatMin)
+      Res = getMin(DstFXSema).getValue();
+  } else
+    Overflowed = Val > FloatMax || Val < FloatMin;
+
+  if (Overflow)
+    *Overflow = Overflowed;
+
+  return APFixedPoint(Res, DstFXSema);
+}
+
+} // namespace llvm

diff  --git a/llvm/unittests/ADT/APFixedPointTest.cpp b/llvm/unittests/ADT/APFixedPointTest.cpp
index 02e80ca7380d..53fa1cd8b503 100644
--- a/llvm/unittests/ADT/APFixedPointTest.cpp
+++ b/llvm/unittests/ADT/APFixedPointTest.cpp
@@ -7,13 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ADT/APFixedPoint.h"
+#include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APSInt.h"
 #include "gtest/gtest.h"
 
 using llvm::APFixedPoint;
-using llvm::FixedPointSemantics;
+using llvm::APFloat;
 using llvm::APInt;
 using llvm::APSInt;
+using llvm::FixedPointSemantics;
 
 namespace {
 
@@ -641,4 +643,282 @@ TEST(FixedPoint, ModularWrapAround) {
             4294967295ULL << 32);
 }
 
+enum OvfKind { MinSat, MaxSat };
+
+void CheckFloatToFixedConversion(APFloat &Val, const FixedPointSemantics &Sema,
+                                 int64_t ExpectedNonSat) {
+  bool Ovf;
+  ASSERT_EQ(APFixedPoint::getFromFloatValue(Val, Sema, &Ovf).getValue(),
+            ExpectedNonSat);
+  ASSERT_EQ(Ovf, false);
+  ASSERT_EQ(
+      APFixedPoint::getFromFloatValue(Val, Saturated(Sema), &Ovf).getValue(),
+      ExpectedNonSat);
+  ASSERT_EQ(Ovf, false);
+}
+
+void CheckFloatToFixedConversion(APFloat &Val, const FixedPointSemantics &Sema,
+                                 OvfKind ExpectedOvf) {
+  bool Ovf;
+  (void)APFixedPoint::getFromFloatValue(Val, Sema, &Ovf);
+  ASSERT_EQ(Ovf, true);
+  ASSERT_EQ(
+      APFixedPoint::getFromFloatValue(Val, Saturated(Sema), &Ovf).getValue(),
+      (ExpectedOvf == MinSat ? APFixedPoint::getMin(Sema)
+                             : APFixedPoint::getMax(Sema))
+          .getValue());
+  ASSERT_EQ(Ovf, false);
+}
+
+TEST(FixedPoint, FloatToFixed) {
+  APFloat Val(0.0f);
+
+  // Simple exact fraction
+  Val = APFloat(0.75f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), 3ULL << 5);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  3ULL << 13);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), 3ULL << 29);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), 3ULL << 6);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  3ULL << 14);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), 3ULL << 30);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), 3ULL << 5);
+  CheckFloatToFixedConversion(Val, getFractSema(),  3ULL << 13);
+  CheckFloatToFixedConversion(Val, getLFractSema(), 3ULL << 29);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), 3ULL << 6);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  3ULL << 14);
+  CheckFloatToFixedConversion(Val, getULFractSema(), 3ULL << 30);
+
+  // Simple negative exact fraction
+  Val = APFloat(-0.75f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), -3ULL << 5);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  -3ULL << 13);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), -3ULL << 29);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), MinSat);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  MinSat);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), MinSat);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), -3ULL << 5);
+  CheckFloatToFixedConversion(Val, getFractSema(),  -3ULL << 13);
+  CheckFloatToFixedConversion(Val, getLFractSema(), -3ULL << 29);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), MinSat);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  MinSat);
+  CheckFloatToFixedConversion(Val, getULFractSema(), MinSat);
+
+  // Highly precise fraction
+  Val = APFloat(0.999999940395355224609375f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), 0x7FULL);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  0x7FFFULL);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), 0xFFFFFFULL << 7);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), 0xFFULL);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  0xFFFFULL);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), 0xFFFFFFULL << 8);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), 0x7FULL);
+  CheckFloatToFixedConversion(Val, getFractSema(),  0x7FFFULL);
+  CheckFloatToFixedConversion(Val, getLFractSema(), 0xFFFFFFULL << 7);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), 0xFFULL);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  0xFFFFULL);
+  CheckFloatToFixedConversion(Val, getULFractSema(), 0xFFFFFFULL << 8);
+
+  // Integral and fraction
+  Val = APFloat(17.99609375f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), 0x11FFULL >> 1);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  0x11FFULL << 7);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), 0x11FFULL << 23);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), 0x11FFULL);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  0x11FFULL << 8);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), 0x11FFULL << 24);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), MaxSat);
+  CheckFloatToFixedConversion(Val, getFractSema(),  MaxSat);
+  CheckFloatToFixedConversion(Val, getLFractSema(), MaxSat);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), MaxSat);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  MaxSat);
+  CheckFloatToFixedConversion(Val, getULFractSema(), MaxSat);
+
+  // Negative integral and fraction
+  Val = APFloat(-17.99609375f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), -0x11FELL >> 1);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  -0x11FFULL << 7);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), -0x11FFULL << 23);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), MinSat);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  MinSat);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), MinSat);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), MinSat);
+  CheckFloatToFixedConversion(Val, getFractSema(),  MinSat);
+  CheckFloatToFixedConversion(Val, getLFractSema(), MinSat);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), MinSat);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  MinSat);
+  CheckFloatToFixedConversion(Val, getULFractSema(), MinSat);
+
+  // Very large value
+  Val = APFloat(1.0e38f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), MaxSat);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  MaxSat);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), MaxSat);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), MaxSat);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  MaxSat);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), MaxSat);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), MaxSat);
+  CheckFloatToFixedConversion(Val, getFractSema(),  MaxSat);
+  CheckFloatToFixedConversion(Val, getLFractSema(), MaxSat);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), MaxSat);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  MaxSat);
+  CheckFloatToFixedConversion(Val, getULFractSema(), MaxSat);
+
+  // Very small value
+  Val = APFloat(1.0e-38f);
+  CheckFloatToFixedConversion(Val, getSAccumSema(), 0);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  0);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), 0);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), 0);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  0);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), 0);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), 0);
+  CheckFloatToFixedConversion(Val, getFractSema(),  0);
+  CheckFloatToFixedConversion(Val, getLFractSema(), 0);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), 0);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  0);
+  CheckFloatToFixedConversion(Val, getULFractSema(), 0);
+
+  // Half conversion
+  Val = APFloat(0.99951171875f);
+  bool Ignored;
+  Val.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored);
+
+  CheckFloatToFixedConversion(Val, getSAccumSema(), 0x7FULL);
+  CheckFloatToFixedConversion(Val, getAccumSema(),  0x7FFULL << 4);
+  CheckFloatToFixedConversion(Val, getLAccumSema(), 0x7FFULL << 20);
+
+  CheckFloatToFixedConversion(Val, getUSAccumSema(), 0xFFULL);
+  CheckFloatToFixedConversion(Val, getUAccumSema(),  0xFFEULL << 4);
+  CheckFloatToFixedConversion(Val, getULAccumSema(), 0xFFEULL << 20);
+
+  CheckFloatToFixedConversion(Val, getSFractSema(), 0x7FULL);
+  CheckFloatToFixedConversion(Val, getFractSema(),  0x7FFULL << 4);
+  CheckFloatToFixedConversion(Val, getLFractSema(), 0x7FFULL << 20);
+
+  CheckFloatToFixedConversion(Val, getUSFractSema(), 0xFFULL);
+  CheckFloatToFixedConversion(Val, getUFractSema(),  0xFFEULL << 4);
+  CheckFloatToFixedConversion(Val, getULFractSema(), 0xFFEULL << 20);
+}
+
+void CheckFixedToFloatConversion(int64_t Val, const FixedPointSemantics &Sema,
+                                 float Result) {
+  APFixedPoint FXVal(Val, Sema);
+  APFloat APRes(Result);
+  ASSERT_EQ(FXVal.convertToFloat(APFloat::IEEEsingle()), APRes);
+}
+
+void CheckFixedToHalfConversion(int64_t Val, const FixedPointSemantics &Sema,
+                                float Result) {
+  APFixedPoint FXVal(Val, Sema);
+  APFloat APRes(Result);
+  bool Ignored;
+  APRes.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored);
+  ASSERT_EQ(FXVal.convertToFloat(APFloat::IEEEhalf()), APRes);
+}
+
+TEST(FixedPoint, FixedToFloat) {
+  int64_t Val = 0x1ULL;
+  CheckFixedToFloatConversion(Val, getSAccumSema(), 0.0078125f);
+  CheckFixedToFloatConversion(Val, getFractSema(),  0.000030517578125f);
+  CheckFixedToFloatConversion(Val, getAccumSema(),  0.000030517578125f);
+  CheckFixedToFloatConversion(Val, getLFractSema(),
+                              0.0000000004656612873077392578125f);
+
+  CheckFixedToFloatConversion(Val, getUSAccumSema(), 0.00390625f);
+  CheckFixedToFloatConversion(Val, getUFractSema(),  0.0000152587890625f);
+  CheckFixedToFloatConversion(Val, getUAccumSema(),  0.0000152587890625f);
+  CheckFixedToFloatConversion(Val, getULFractSema(),
+                              0.00000000023283064365386962890625f);
+
+  Val = 0x7FULL;
+  CheckFixedToFloatConversion(Val, getSAccumSema(), 0.9921875f);
+  CheckFixedToFloatConversion(Val, getFractSema(),  0.003875732421875f);
+  CheckFixedToFloatConversion(Val, getAccumSema(),  0.003875732421875f);
+  CheckFixedToFloatConversion(Val, getLFractSema(),
+                              0.0000000591389834880828857421875f);
+
+  CheckFixedToFloatConversion(Val, getUSAccumSema(), 0.49609375f);
+  CheckFixedToFloatConversion(Val, getUFractSema(),  0.0019378662109375f);
+  CheckFixedToFloatConversion(Val, getUAccumSema(),  0.0019378662109375f);
+  CheckFixedToFloatConversion(Val, getULFractSema(),
+                              0.00000002956949174404144287109375f);
+
+  Val = -0x1ULL;
+  CheckFixedToFloatConversion(Val, getSAccumSema(), -0.0078125f);
+  CheckFixedToFloatConversion(Val, getFractSema(),  -0.000030517578125f);
+  CheckFixedToFloatConversion(Val, getAccumSema(),  -0.000030517578125f);
+  CheckFixedToFloatConversion(Val, getLFractSema(),
+                              -0.0000000004656612873077392578125f);
+
+
+  CheckFixedToFloatConversion(-0x80ULL,       getSAccumSema(), -1.0f);
+  CheckFixedToFloatConversion(-0x8000ULL,     getFractSema(),  -1.0f);
+  CheckFixedToFloatConversion(-0x8000ULL,     getAccumSema(),  -1.0f);
+  CheckFixedToFloatConversion(-0x80000000ULL, getLFractSema(), -1.0f);
+
+  Val = 0xAFAULL;
+  CheckFixedToFloatConversion(Val, getSAccumSema(), 21.953125f);
+  CheckFixedToFloatConversion(Val, getFractSema(),  0.08575439453125f);
+  CheckFixedToFloatConversion(Val, getAccumSema(),  0.08575439453125f);
+  CheckFixedToFloatConversion(Val, getLFractSema(),
+                              0.000001308508217334747314453125f);
+
+  CheckFixedToFloatConversion(Val, getUSAccumSema(), 10.9765625f);
+  CheckFixedToFloatConversion(Val, getUFractSema(),  0.042877197265625f);
+  CheckFixedToFloatConversion(Val, getUAccumSema(),  0.042877197265625f);
+  CheckFixedToFloatConversion(Val, getULFractSema(),
+                              0.0000006542541086673736572265625f);
+
+  Val = -0xAFAULL;
+  CheckFixedToFloatConversion(Val, getSAccumSema(), -21.953125f);
+  CheckFixedToFloatConversion(Val, getFractSema(),  -0.08575439453125f);
+  CheckFixedToFloatConversion(Val, getAccumSema(),  -0.08575439453125f);
+  CheckFixedToFloatConversion(Val, getLFractSema(),
+                              -0.000001308508217334747314453125f);
+
+  Val = 0x40000080ULL;
+  CheckFixedToFloatConversion(Val, getAccumSema(),  32768.00390625f);
+  CheckFixedToFloatConversion(Val, getLFractSema(),
+                              0.500000059604644775390625f);
+
+  CheckFixedToFloatConversion(Val, getUAccumSema(),  16384.001953125f);
+  CheckFixedToFloatConversion(Val, getULFractSema(),
+                              0.2500000298023223876953125f);
+
+  Val = 0x40000040ULL;
+  CheckFixedToFloatConversion(Val, getAccumSema(),  32768.0f);
+  CheckFixedToFloatConversion(Val, getLFractSema(), 0.5f);
+
+  CheckFixedToFloatConversion(Val, getUAccumSema(),  16384.0f);
+  CheckFixedToFloatConversion(Val, getULFractSema(), 0.25f);
+
+  Val = 0x7FF0ULL;
+  CheckFixedToHalfConversion(Val, getAccumSema(), 0.99951171875f);
+  CheckFixedToHalfConversion(Val, getLFractSema(), 0.000015251338481903076171875f);
+
+  CheckFixedToHalfConversion(Val, getUAccumSema(), 0.499755859375f);
+  CheckFixedToHalfConversion(Val, getULFractSema(), 0.0000076256692409515380859375f);
+}
+
 } // namespace


        


More information about the llvm-commits mailing list