diff --git a/llvm/include/llvm/ADT/APFixedPoint.h b/llvm/include/llvm/ADT/APFixedPoint.h --- 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 @@ 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 @@ /// 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 &Str) const; std::string toString() const { SmallString<40> S; @@ -186,6 +199,10 @@ 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 @@ 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 @@ return OS; } -} // namespace llvm +} // namespace llvm #endif diff --git a/llvm/lib/Support/APFixedPoint.cpp b/llvm/lib/Support/APFixedPoint.cpp --- 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 @@ 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 @@ 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 @@ 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 --- 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 @@ 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