//===- unittests/ADT/FixedPointTest.cpp -- fixed point number tests -----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ADT/APFixedPoint.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "gtest/gtest.h" using llvm::APFixedPoint; using llvm::APFloat; using llvm::APInt; using llvm::APSInt; using llvm::FixedPointSemantics; namespace { FixedPointSemantics Saturated(FixedPointSemantics Sema) { Sema.setSaturated(true); return Sema; } FixedPointSemantics getSAccumSema() { return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getAccumSema() { return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getLAccumSema() { return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getSFractSema() { return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getFractSema() { return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getLFractSema() { return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getUSAccumSema() { return FixedPointSemantics(/*width=*/16, /*scale=*/8, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getUAccumSema() { return FixedPointSemantics(/*width=*/32, /*scale=*/16, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getULAccumSema() { return FixedPointSemantics(/*width=*/64, /*scale=*/32, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getUSFractSema() { return FixedPointSemantics(/*width=*/8, /*scale=*/8, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getUFractSema() { return FixedPointSemantics(/*width=*/16, /*scale=*/16, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getULFractSema() { return FixedPointSemantics(/*width=*/32, /*scale=*/32, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getPadUSAccumSema() { return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/true); } FixedPointSemantics getPadUAccumSema() { return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/true); } FixedPointSemantics getPadULAccumSema() { return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/true); } FixedPointSemantics getPadUSFractSema() { return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/true); } FixedPointSemantics getPadUFractSema() { return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/true); } FixedPointSemantics getPadULFractSema() { return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/true); } FixedPointSemantics getU8Neg10() { return FixedPointSemantics(/*width=*/8, /*lsb=*/FixedPointSemantics::Lsb{-10}, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getS16Neg18() { return FixedPointSemantics(/*width=*/16, /*lsb=*/FixedPointSemantics::Lsb{-18}, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getU8Pos4() { return FixedPointSemantics(/*width=*/8, /*lsb=*/FixedPointSemantics::Lsb{4}, /*isSigned=*/false, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } FixedPointSemantics getS32Pos2() { return FixedPointSemantics(/*width=*/32, /*lsb=*/FixedPointSemantics::Lsb{2}, /*isSigned=*/true, /*isSaturated=*/false, /*hasUnsignedPadding=*/false); } void CheckUnpaddedMax(const FixedPointSemantics &Sema) { ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(), APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned())); } void CheckPaddedMax(const FixedPointSemantics &Sema) { ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(), APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned()) >> 1); } void CheckMin(const FixedPointSemantics &Sema) { ASSERT_EQ(APFixedPoint::getMin(Sema).getValue(), APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned())); } TEST(FixedPointTest, getMax) { CheckUnpaddedMax(getSAccumSema()); CheckUnpaddedMax(getAccumSema()); CheckUnpaddedMax(getLAccumSema()); CheckUnpaddedMax(getUSAccumSema()); CheckUnpaddedMax(getUAccumSema()); CheckUnpaddedMax(getULAccumSema()); CheckUnpaddedMax(getSFractSema()); CheckUnpaddedMax(getFractSema()); CheckUnpaddedMax(getLFractSema()); CheckUnpaddedMax(getUSFractSema()); CheckUnpaddedMax(getUFractSema()); CheckUnpaddedMax(getULFractSema()); CheckUnpaddedMax(getU8Neg10()); CheckUnpaddedMax(getS16Neg18()); CheckUnpaddedMax(getU8Pos4()); CheckUnpaddedMax(getS32Pos2()); CheckPaddedMax(getPadUSAccumSema()); CheckPaddedMax(getPadUAccumSema()); CheckPaddedMax(getPadULAccumSema()); CheckPaddedMax(getPadUSFractSema()); CheckPaddedMax(getPadUFractSema()); CheckPaddedMax(getPadULFractSema()); } TEST(FixedPointTest, getMin) { CheckMin(getSAccumSema()); CheckMin(getAccumSema()); CheckMin(getLAccumSema()); CheckMin(getUSAccumSema()); CheckMin(getUAccumSema()); CheckMin(getULAccumSema()); CheckMin(getSFractSema()); CheckMin(getFractSema()); CheckMin(getLFractSema()); CheckMin(getUSFractSema()); CheckMin(getUFractSema()); CheckMin(getULFractSema()); CheckMin(getU8Neg10()); CheckMin(getS16Neg18()); CheckMin(getU8Pos4()); CheckMin(getS32Pos2()); CheckMin(getPadUSAccumSema()); CheckMin(getPadUAccumSema()); CheckMin(getPadULAccumSema()); CheckMin(getPadUSFractSema()); CheckMin(getPadUFractSema()); CheckMin(getPadULFractSema()); } int64_t relativeShr(int64_t Int, int64_t Shift) { return (Shift > 0) ? Int >> Shift : Int << -Shift; } void CheckIntPart(const FixedPointSemantics &Sema, int64_t IntPart) { int64_t FullFactPart = (Sema.getLsbWeight() > 0) ? 0 : (1ULL << (-Sema.getLsbWeight() - 1)); // Value with a fraction APFixedPoint ValWithFract( APInt(Sema.getWidth(), relativeShr(IntPart, Sema.getLsbWeight()) + FullFactPart, Sema.isSigned()), Sema); ASSERT_EQ(ValWithFract.getIntPart(), IntPart); // Just fraction APFixedPoint JustFract(APInt(Sema.getWidth(), FullFactPart, Sema.isSigned()), Sema); ASSERT_EQ(JustFract.getIntPart(), 0); // Whole number APFixedPoint WholeNum(APInt(Sema.getWidth(), relativeShr(IntPart, Sema.getLsbWeight()), Sema.isSigned()), Sema); ASSERT_EQ(WholeNum.getIntPart(), IntPart); // Negative if (Sema.isSigned()) { APFixedPoint Negative(APInt(Sema.getWidth(), relativeShr(IntPart, Sema.getLsbWeight()), Sema.isSigned()), Sema); ASSERT_EQ(Negative.getIntPart(), IntPart); } } void CheckIntPartMin(const FixedPointSemantics &Sema, int64_t Expected) { EXPECT_TRUE(APSInt::compareValues(APFixedPoint::getMin(Sema).getIntPart(), APSInt::get(Expected)) == 0); } void CheckIntPartMax(const FixedPointSemantics &Sema, uint64_t Expected) { EXPECT_TRUE(APSInt::compareValues(APFixedPoint::getMax(Sema).getIntPart(), APSInt::getUnsigned(Expected)) == 0); } void CheckIntPartRes(const FixedPointSemantics &Sema, int64_t Representation, uint64_t Result) { APFixedPoint Val(Representation, Sema); ASSERT_EQ(Val.getIntPart().getZExtValue(), Result) ; } TEST(FixedPoint, getIntPart) { // Normal values CheckIntPart(getSAccumSema(), 2); CheckIntPart(getAccumSema(), 2); CheckIntPart(getLAccumSema(), 2); CheckIntPart(getUSAccumSema(), 2); CheckIntPart(getUAccumSema(), 2); CheckIntPart(getULAccumSema(), 2); CheckIntPart(getU8Pos4(), 32); CheckIntPart(getS32Pos2(), 32); // Zero CheckIntPart(getSAccumSema(), 0); CheckIntPart(getAccumSema(), 0); CheckIntPart(getLAccumSema(), 0); CheckIntPart(getUSAccumSema(), 0); CheckIntPart(getUAccumSema(), 0); CheckIntPart(getULAccumSema(), 0); CheckIntPart(getSFractSema(), 0); CheckIntPart(getFractSema(), 0); CheckIntPart(getLFractSema(), 0); CheckIntPart(getUSFractSema(), 0); CheckIntPart(getUFractSema(), 0); CheckIntPart(getULFractSema(), 0); CheckIntPart(getS16Neg18(), 0); CheckIntPart(getU8Neg10(), 0); CheckIntPart(getU8Pos4(), 0); CheckIntPart(getS32Pos2(), 0); // Min CheckIntPartMin(getSAccumSema(), -256); CheckIntPartMin(getAccumSema(), -65536); CheckIntPartMin(getLAccumSema(), -4294967296); CheckIntPartMin(getSFractSema(), -1); CheckIntPartMin(getFractSema(), -1); CheckIntPartMin(getLFractSema(), -1); CheckIntPartMin(getS32Pos2(), -8589934592); // Max CheckIntPartMax(getSAccumSema(), 255); CheckIntPartMax(getAccumSema(), 65535); CheckIntPartMax(getLAccumSema(), 4294967295); CheckIntPartMax(getUSAccumSema(), 255); CheckIntPartMax(getUAccumSema(), 65535); CheckIntPartMax(getULAccumSema(), 4294967295); CheckIntPartMax(getU8Pos4(), 255 << 4); CheckIntPartMax(getS32Pos2(), 2147483647ull << 2); CheckIntPartMax(getSFractSema(), 0); CheckIntPartMax(getFractSema(), 0); CheckIntPartMax(getLFractSema(), 0); CheckIntPartMax(getUSFractSema(), 0); CheckIntPartMax(getUFractSema(), 0); CheckIntPartMax(getULFractSema(), 0); // Padded // Normal Values CheckIntPart(getPadUSAccumSema(), 2); CheckIntPart(getPadUAccumSema(), 2); CheckIntPart(getPadULAccumSema(), 2); // Zero CheckIntPart(getPadUSAccumSema(), 0); CheckIntPart(getPadUAccumSema(), 0); CheckIntPart(getPadULAccumSema(), 0); CheckIntPart(getPadUSFractSema(), 0); CheckIntPart(getPadUFractSema(), 0); CheckIntPart(getPadULFractSema(), 0); // Max CheckIntPartMax(getPadUSAccumSema(), 255); CheckIntPartMax(getPadUAccumSema(), 65535); CheckIntPartMax(getPadULAccumSema(), 4294967295); CheckIntPartMax(getPadUSFractSema(), 0); CheckIntPartMax(getPadUFractSema(), 0); CheckIntPartMax(getPadULFractSema(), 0); // Rounded Towards Zero CheckIntPartRes(getSFractSema(), -127, 0); CheckIntPartRes(getFractSema(), -32767, 0); CheckIntPartRes(getLFractSema(), -2147483647, 0); CheckIntPartRes(getS16Neg18(), -32768, 0); } TEST(FixedPoint, compare) { // Equality // With fractional part (2.5) // Across sizes ASSERT_EQ(APFixedPoint(320, getSAccumSema()), APFixedPoint(81920, getAccumSema())); ASSERT_EQ(APFixedPoint(320, getSAccumSema()), APFixedPoint(5368709120, getLAccumSema())); ASSERT_EQ(APFixedPoint(0, getSAccumSema()), APFixedPoint(0, getLAccumSema())); ASSERT_EQ(APFixedPoint(0, getS16Neg18()), APFixedPoint(0, getU8Neg10())); ASSERT_EQ(APFixedPoint(256, getS16Neg18()), APFixedPoint(1, getU8Neg10())); ASSERT_EQ(APFixedPoint(32512, getS16Neg18()), APFixedPoint(127, getU8Neg10())); ASSERT_EQ(APFixedPoint(4, getS32Pos2()), APFixedPoint(1, getU8Pos4())); ASSERT_EQ(APFixedPoint(1020, getS32Pos2()), APFixedPoint(255, getU8Pos4())); // Across types (0.5) ASSERT_EQ(APFixedPoint(64, getSAccumSema()), APFixedPoint(64, getSFractSema())); ASSERT_EQ(APFixedPoint(16384, getAccumSema()), APFixedPoint(16384, getFractSema())); ASSERT_EQ(APFixedPoint(1073741824, getLAccumSema()), APFixedPoint(1073741824, getLFractSema())); // Across widths and types (0.5) ASSERT_EQ(APFixedPoint(64, getSAccumSema()), APFixedPoint(16384, getFractSema())); ASSERT_EQ(APFixedPoint(64, getSAccumSema()), APFixedPoint(1073741824, getLFractSema())); // Across saturation ASSERT_EQ(APFixedPoint(320, getSAccumSema()), APFixedPoint(81920, Saturated(getAccumSema()))); // Across signs ASSERT_EQ(APFixedPoint(320, getSAccumSema()), APFixedPoint(640, getUSAccumSema())); ASSERT_EQ(APFixedPoint(-320, getSAccumSema()), APFixedPoint(-81920, getAccumSema())); // Across padding ASSERT_EQ(APFixedPoint(320, getSAccumSema()), APFixedPoint(320, getPadUSAccumSema())); ASSERT_EQ(APFixedPoint(640, getUSAccumSema()), APFixedPoint(320, getPadUSAccumSema())); // Less than ASSERT_LT(APFixedPoint(-1, getSAccumSema()), APFixedPoint(0, getAccumSema())); ASSERT_LT(APFixedPoint(-1, getSAccumSema()), APFixedPoint(0, getUAccumSema())); ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getAccumSema())); ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getUAccumSema())); ASSERT_LT(APFixedPoint(0, getUSAccumSema()), APFixedPoint(1, getAccumSema())); ASSERT_LT(APFixedPoint(0, getUSAccumSema()), APFixedPoint(1, getUAccumSema())); ASSERT_LT(APFixedPoint(65280, getS16Neg18()), APFixedPoint(255, getU8Neg10())); // Greater than ASSERT_GT(APFixedPoint(0, getAccumSema()), APFixedPoint(-1, getSAccumSema())); ASSERT_GT(APFixedPoint(0, getUAccumSema()), APFixedPoint(-1, getSAccumSema())); ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getSAccumSema())); ASSERT_GT(APFixedPoint(1, getUAccumSema()), APFixedPoint(0, getSAccumSema())); ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getUSAccumSema())); ASSERT_GT(APFixedPoint(1, getUAccumSema()), APFixedPoint(0, getUSAccumSema())); } // Check that a fixed point value in one sema is the same in another sema void CheckUnsaturatedConversion(FixedPointSemantics Src, FixedPointSemantics Dst, int64_t TestVal) { int64_t ScaledVal = TestVal; bool IsNegative = ScaledVal < 0; if (IsNegative) ScaledVal = -ScaledVal; if (Dst.getLsbWeight() < Src.getLsbWeight()) { ScaledVal <<= (Src.getLsbWeight() - Dst.getLsbWeight()); } else { ScaledVal >>= (Dst.getLsbWeight() - Src.getLsbWeight()); } if (IsNegative) ScaledVal = -ScaledVal; APFixedPoint Fixed(TestVal, Src); APFixedPoint Expected(ScaledVal, Dst); ASSERT_EQ(Fixed.convert(Dst), Expected); } // Check the value in a given fixed point sema overflows to the saturated min // for another sema void CheckSaturatedConversionMin(FixedPointSemantics Src, FixedPointSemantics Dst, int64_t TestVal) { APFixedPoint Fixed(TestVal, Src); ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMin(Dst)); } // Check the value in a given fixed point sema overflows to the saturated max // for another sema void CheckSaturatedConversionMax(FixedPointSemantics Src, FixedPointSemantics Dst, int64_t TestVal) { APFixedPoint Fixed(TestVal, Src); ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMax(Dst)); } // Check one signed _Accum sema converted to other sema for different values. void CheckSignedAccumConversionsAgainstOthers(FixedPointSemantics Src, int64_t OneVal) { int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5 int64_t HalfVal = (OneVal / 2); // 0.5 // +Accums to Accums CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal); // -Accums to Accums CheckUnsaturatedConversion(Src, getSAccumSema(), -NormalVal); CheckUnsaturatedConversion(Src, getAccumSema(), -NormalVal); CheckUnsaturatedConversion(Src, getLAccumSema(), -NormalVal); CheckSaturatedConversionMin(Src, Saturated(getUSAccumSema()), -NormalVal); CheckSaturatedConversionMin(Src, Saturated(getUAccumSema()), -NormalVal); CheckSaturatedConversionMin(Src, Saturated(getULAccumSema()), -NormalVal); CheckSaturatedConversionMin(Src, Saturated(getPadUSAccumSema()), -NormalVal); CheckSaturatedConversionMin(Src, Saturated(getPadUAccumSema()), -NormalVal); CheckSaturatedConversionMin(Src, Saturated(getPadULAccumSema()), -NormalVal); // +Accums to Fracts CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal); // -Accums to Fracts CheckUnsaturatedConversion(Src, getSFractSema(), -HalfVal); CheckUnsaturatedConversion(Src, getFractSema(), -HalfVal); CheckUnsaturatedConversion(Src, getLFractSema(), -HalfVal); CheckSaturatedConversionMin(Src, Saturated(getUSFractSema()), -HalfVal); CheckSaturatedConversionMin(Src, Saturated(getUFractSema()), -HalfVal); CheckSaturatedConversionMin(Src, Saturated(getULFractSema()), -HalfVal); CheckSaturatedConversionMin(Src, Saturated(getPadUSFractSema()), -HalfVal); CheckSaturatedConversionMin(Src, Saturated(getPadUFractSema()), -HalfVal); CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), -HalfVal); // 0 to Accums CheckUnsaturatedConversion(Src, getSAccumSema(), 0); CheckUnsaturatedConversion(Src, getAccumSema(), 0); CheckUnsaturatedConversion(Src, getLAccumSema(), 0); CheckUnsaturatedConversion(Src, getUSAccumSema(), 0); CheckUnsaturatedConversion(Src, getUAccumSema(), 0); CheckUnsaturatedConversion(Src, getULAccumSema(), 0); CheckUnsaturatedConversion(Src, getPadUSAccumSema(), 0); CheckUnsaturatedConversion(Src, getPadUAccumSema(), 0); CheckUnsaturatedConversion(Src, getPadULAccumSema(), 0); // 0 to Fracts CheckUnsaturatedConversion(Src, getSFractSema(), 0); CheckUnsaturatedConversion(Src, getFractSema(), 0); CheckUnsaturatedConversion(Src, getLFractSema(), 0); CheckUnsaturatedConversion(Src, getUSFractSema(), 0); CheckUnsaturatedConversion(Src, getUFractSema(), 0); CheckUnsaturatedConversion(Src, getULFractSema(), 0); CheckUnsaturatedConversion(Src, getPadUSFractSema(), 0); CheckUnsaturatedConversion(Src, getPadUFractSema(), 0); CheckUnsaturatedConversion(Src, getPadULFractSema(), 0); } // Check one unsigned _Accum sema converted to other sema for different // values. void CheckUnsignedAccumConversionsAgainstOthers(FixedPointSemantics Src, int64_t OneVal) { int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5 int64_t HalfVal = (OneVal / 2); // 0.5 // +UAccums to Accums CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal); CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal); // +UAccums to Fracts CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal); CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal); } TEST(FixedPoint, AccumConversions) { // Normal conversions CheckSignedAccumConversionsAgainstOthers(getSAccumSema(), 128); CheckUnsignedAccumConversionsAgainstOthers(getUSAccumSema(), 256); CheckSignedAccumConversionsAgainstOthers(getAccumSema(), 32768); CheckUnsignedAccumConversionsAgainstOthers(getUAccumSema(), 65536); CheckSignedAccumConversionsAgainstOthers(getLAccumSema(), 2147483648); CheckUnsignedAccumConversionsAgainstOthers(getULAccumSema(), 4294967296); CheckUnsignedAccumConversionsAgainstOthers(getPadUSAccumSema(), 128); CheckUnsignedAccumConversionsAgainstOthers(getPadUAccumSema(), 32768); CheckUnsignedAccumConversionsAgainstOthers(getPadULAccumSema(), 2147483648); } TEST(FixedPoint, AccumConversionOverflow) { // To SAccum max limit (65536) CheckSaturatedConversionMax(getLAccumSema(), Saturated(getAccumSema()), 140737488355328); CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUAccumSema()), 140737488355328); CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUAccumSema()), 140737488355328); CheckSaturatedConversionMax(getULAccumSema(), Saturated(getAccumSema()), 281474976710656); CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUAccumSema()), 281474976710656); CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUAccumSema()), 281474976710656); CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getAccumSema()), 140737488355328); CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUAccumSema()), 140737488355328); CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getPadUAccumSema()), 140737488355328); // To SAccum min limit (-65536) CheckSaturatedConversionMin(getLAccumSema(), Saturated(getAccumSema()), -140737488355328); CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUAccumSema()), -140737488355328); CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUAccumSema()), -140737488355328); } TEST(FixedPoint, SAccumConversionOverflow) { // To SAccum max limit (256) CheckSaturatedConversionMax(getAccumSema(), Saturated(getSAccumSema()), 8388608); CheckSaturatedConversionMax(getAccumSema(), Saturated(getUSAccumSema()), 8388608); CheckSaturatedConversionMax(getAccumSema(), Saturated(getPadUSAccumSema()), 8388608); CheckSaturatedConversionMax(getUAccumSema(), Saturated(getSAccumSema()), 16777216); CheckSaturatedConversionMax(getUAccumSema(), Saturated(getUSAccumSema()), 16777216); CheckSaturatedConversionMax(getUAccumSema(), Saturated(getPadUSAccumSema()), 16777216); CheckSaturatedConversionMax(getLAccumSema(), Saturated(getSAccumSema()), 549755813888); CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUSAccumSema()), 549755813888); CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUSAccumSema()), 549755813888); CheckSaturatedConversionMax(getULAccumSema(), Saturated(getSAccumSema()), 1099511627776); CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUSAccumSema()), 1099511627776); CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUSAccumSema()), 1099511627776); CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getSAccumSema()), 8388608); CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getUSAccumSema()), 8388608); CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getPadUSAccumSema()), 8388608); CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getSAccumSema()), 549755813888); CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUSAccumSema()), 549755813888); CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getPadUSAccumSema()), 549755813888); // To SAccum min limit (-256) CheckSaturatedConversionMin(getAccumSema(), Saturated(getSAccumSema()), -8388608); CheckSaturatedConversionMin(getAccumSema(), Saturated(getUSAccumSema()), -8388608); CheckSaturatedConversionMin(getAccumSema(), Saturated(getPadUSAccumSema()), -8388608); CheckSaturatedConversionMin(getLAccumSema(), Saturated(getSAccumSema()), -549755813888); CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUSAccumSema()), -549755813888); CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUSAccumSema()), -549755813888); } TEST(FixedPoint, GetValueSignAfterConversion) { APFixedPoint Fixed(255 << 7, getSAccumSema()); ASSERT_TRUE(Fixed.getValue().isSigned()); APFixedPoint UFixed = Fixed.convert(getUSAccumSema()); ASSERT_TRUE(UFixed.getValue().isUnsigned()); ASSERT_EQ(UFixed.getValue(), APSInt::getUnsigned(255 << 8).extOrTrunc(16)); } TEST(FixedPoint, ModularWrapAround) { // Positive to negative APFixedPoint Val = APFixedPoint(1ULL << 7, getSAccumSema()); ASSERT_EQ(Val.convert(getLFractSema()).getValue(), -(1ULL << 31)); Val = APFixedPoint(1ULL << 23, getAccumSema()); ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), -(1ULL << 15)); Val = APFixedPoint(1ULL << 47, getLAccumSema()); ASSERT_EQ(Val.convert(getAccumSema()).getValue(), -(1ULL << 31)); // Negative to positive Val = APFixedPoint(/*-1.5*/ -192, getSAccumSema()); ASSERT_EQ(Val.convert(getLFractSema()).getValue(), 1ULL << 30); Val = APFixedPoint(-(257 << 15), getAccumSema()); ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), 255 << 7); Val = APFixedPoint(-(65537ULL << 31), getLAccumSema()); ASSERT_EQ(Val.convert(getAccumSema()).getValue(), 65535 << 15); // Signed to unsigned Val = APFixedPoint(-(1 << 7), getSAccumSema()); ASSERT_EQ(Val.convert(getUSAccumSema()).getValue(), 255 << 8); Val = APFixedPoint(-(1 << 15), getAccumSema()); ASSERT_EQ(Val.convert(getUAccumSema()).getValue(), 65535ULL << 16); Val = APFixedPoint(-(1ULL << 31), getLAccumSema()); ASSERT_EQ(Val.convert(getULAccumSema()).getValue().getZExtValue(), 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, toString) { ASSERT_EQ(APFixedPoint::getMax(getS16Neg18()).toString(), "0.124996185302734375"); ASSERT_EQ(APFixedPoint::getMin(getS16Neg18()) .add(APFixedPoint(1, getS16Neg18())) .toString(), "-0.124996185302734375"); ASSERT_EQ(APFixedPoint::getMin(getS16Neg18()).toString(), "-0.125"); ASSERT_EQ(APFixedPoint::getMax(getU8Neg10()).toString(), "0.2490234375"); ASSERT_EQ(APFixedPoint::getMin(getU8Neg10()).toString(), "0.0"); ASSERT_EQ(APFixedPoint::getMax(getS32Pos2()).toString(), "8589934588.0"); ASSERT_EQ(APFixedPoint::getMin(getS32Pos2()) .add(APFixedPoint(1, getS32Pos2())) .toString(), "-8589934588.0"); ASSERT_EQ(APFixedPoint::getMin(getS32Pos2()).toString(), "-8589934592.0"); ASSERT_EQ(APFixedPoint::getMax(getU8Pos4()).toString(), "4080.0"); ASSERT_EQ(APFixedPoint::getMin(getU8Pos4()).toString(), "0.0"); } 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); CheckFloatToFixedConversion(Val, getS32Pos2(), 0); // 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MinSat); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), MinSat); CheckFloatToFixedConversion(Val, getS32Pos2(), 0); // 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); CheckFloatToFixedConversion(Val, getS32Pos2(), 0); // 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); CheckFloatToFixedConversion(Val, getU8Pos4(), 1); CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); CheckFloatToFixedConversion(Val, getS32Pos2(), 1 << 2); // 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MinSat); CheckFloatToFixedConversion(Val, getU8Pos4(), MinSat); CheckFloatToFixedConversion(Val, getS16Neg18(), MinSat); CheckFloatToFixedConversion(Val, getS32Pos2(), -4); // 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); CheckFloatToFixedConversion(Val, getU8Pos4(), MaxSat); CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); CheckFloatToFixedConversion(Val, getS32Pos2(), 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); CheckFloatToFixedConversion(Val, getU8Neg10(), 0); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), 0); CheckFloatToFixedConversion(Val, getS32Pos2(), 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); CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); CheckFloatToFixedConversion(Val, getS32Pos2(), 0); Val = APFloat(0.124996185302734375); CheckFloatToFixedConversion(Val, getU8Neg10(), 0x7f); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), 0x7fff); CheckFloatToFixedConversion(Val, getS32Pos2(), 0); Val = APFloat(-0.124996185302734375); CheckFloatToFixedConversion(Val, getU8Neg10(), MinSat); CheckFloatToFixedConversion(Val, getU8Pos4(), 0); CheckFloatToFixedConversion(Val, getS16Neg18(), -0x7fff); CheckFloatToFixedConversion(Val, getS32Pos2(), 0); } 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); CheckFixedToFloatConversion(Val, getU8Neg10(), 0.0009765625f); CheckFixedToFloatConversion(Val, getU8Pos4(), 16.0f); CheckFixedToFloatConversion(Val, getS16Neg18(), 0.000003814697265625f); CheckFixedToFloatConversion(Val, getS32Pos2(), 4.0f); 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); CheckFixedToFloatConversion(Val, getU8Neg10(), 0.1240234375f); CheckFixedToFloatConversion(Val, getU8Pos4(), 2032.0f); CheckFixedToFloatConversion(Val, getS16Neg18(), 0.000484466552734375f); CheckFixedToFloatConversion(Val, getS32Pos2(), 508.0f); Val = -0x1ULL; CheckFixedToFloatConversion(Val, getSAccumSema(), -0.0078125f); CheckFixedToFloatConversion(Val, getFractSema(), -0.000030517578125f); CheckFixedToFloatConversion(Val, getAccumSema(), -0.000030517578125f); CheckFixedToFloatConversion(Val, getLFractSema(), -0.0000000004656612873077392578125f); CheckFixedToFloatConversion(Val, getU8Neg10(), 0.249023437f); CheckFixedToFloatConversion(Val, getU8Pos4(), 4080.0f); CheckFixedToFloatConversion(Val, getS16Neg18(), -0.000003814697265625f); CheckFixedToFloatConversion(Val, getS32Pos2(), -4.0f); 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); CheckFixedToFloatConversion(Val, getS16Neg18(), 0.01071929931640625f); CheckFixedToFloatConversion(Val, getS32Pos2(), 11240.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, getS16Neg18(), -0.01071929931640625f); CheckFixedToFloatConversion(Val, getS32Pos2(), -11240.0f); Val = 0x40000080ULL; CheckFixedToFloatConversion(Val, getAccumSema(), 32768.00390625f); CheckFixedToFloatConversion(Val, getLFractSema(), 0.500000059604644775390625f); CheckFixedToFloatConversion(Val, getUAccumSema(), 16384.001953125f); CheckFixedToFloatConversion(Val, getULFractSema(), 0.2500000298023223876953125f); CheckFixedToFloatConversion(Val, getS32Pos2(), 4294967808.0f); Val = 0x40000040ULL; CheckFixedToFloatConversion(Val, getAccumSema(), 32768.0f); CheckFixedToFloatConversion(Val, getLFractSema(), 0.5f); CheckFixedToFloatConversion(Val, getUAccumSema(), 16384.0f); CheckFixedToFloatConversion(Val, getULFractSema(), 0.25f); CheckFixedToFloatConversion(Val, getS32Pos2(), 4294967552.0f); Val = 0x7FF0ULL; CheckFixedToHalfConversion(Val, getAccumSema(), 0.99951171875f); CheckFixedToHalfConversion(Val, getLFractSema(), 0.000015251338481903076171875f); CheckFixedToHalfConversion(Val, getUAccumSema(), 0.499755859375f); CheckFixedToHalfConversion(Val, getULFractSema(), 0.0000076256692409515380859375f); CheckFixedToFloatConversion(Val, getS32Pos2(), 131008.0f); } void CheckAdd(const APFixedPoint &Lhs, const APFixedPoint &Rhs, const APFixedPoint &Res) { bool Overflow = false; APFixedPoint Result = Lhs.add(Rhs, &Overflow); ASSERT_FALSE(Overflow); ASSERT_EQ(Result.getSemantics(), Res.getSemantics()); ASSERT_EQ(Result, Res); } void CheckAddOverflow(const APFixedPoint &Lhs, const APFixedPoint &Rhs) { bool Overflow = false; APFixedPoint Result = Lhs.add(Rhs, &Overflow); ASSERT_TRUE(Overflow); } TEST(FixedPoint, add) { CheckAdd(APFixedPoint(1, getS32Pos2()), APFixedPoint(1, getS32Pos2()), APFixedPoint(2, getS32Pos2())); CheckAdd(APFixedPoint(1, getS16Neg18()), APFixedPoint(1, getS16Neg18()), APFixedPoint(2, getS16Neg18())); CheckAdd(APFixedPoint(1, getU8Neg10()), APFixedPoint(1, getU8Neg10()), APFixedPoint(2, getU8Neg10())); CheckAdd(APFixedPoint(1, getU8Pos4()), APFixedPoint(1, getU8Pos4()), APFixedPoint(2, getU8Pos4())); CheckAdd(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS32Pos2()), APFixedPoint(12, getS32Pos2())); CheckAdd(APFixedPoint(11, getS16Neg18()), APFixedPoint(1, getS16Neg18()), APFixedPoint(12, getS16Neg18())); CheckAdd(APFixedPoint(11, getU8Neg10()), APFixedPoint(1, getU8Neg10()), APFixedPoint(12, getU8Neg10())); CheckAdd(APFixedPoint(11, getU8Pos4()), APFixedPoint(1, getU8Pos4()), APFixedPoint(12, getU8Pos4())); CheckAdd(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS16Neg18()), APFixedPoint(11534337, FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckAdd( APFixedPoint(11, getU8Neg10()), APFixedPoint(-9472, getS16Neg18()), APFixedPoint(-6656, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckAddOverflow( APFixedPoint::getMax(getU8Neg10()), APFixedPoint::getMax(getS16Neg18())); CheckAdd(APFixedPoint::getMin(getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), APFixedPoint::getMin(getS16Neg18()) .convert(FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckAddOverflow(APFixedPoint::getMin(getS32Pos2()), APFixedPoint::getMin(getS16Neg18())); } void CheckMul(const APFixedPoint &Lhs, const APFixedPoint &Rhs, const APFixedPoint &Res) { bool Overflow = false; APFixedPoint Result = Lhs.mul(Rhs, &Overflow); ASSERT_FALSE(Overflow); ASSERT_EQ(Result.getSemantics(), Res.getSemantics()); ASSERT_EQ(Result, Res); } void CheckMulOverflow(const APFixedPoint &Lhs, const APFixedPoint &Rhs) { bool Overflow = false; APFixedPoint Result = Lhs.mul(Rhs, &Overflow); ASSERT_TRUE(Overflow); } TEST(FixedPoint, mul) { CheckMul(APFixedPoint(1, getS32Pos2()), APFixedPoint(1, getS32Pos2()), APFixedPoint(4, getS32Pos2())); CheckMul(APFixedPoint(1, getS16Neg18()), APFixedPoint(1, getS16Neg18()), APFixedPoint(0, getS16Neg18())); CheckMul(APFixedPoint(1, getU8Neg10()), APFixedPoint(1, getU8Neg10()), APFixedPoint(0, getU8Neg10())); CheckMul(APFixedPoint(1, getU8Pos4()), APFixedPoint(1, getU8Pos4()), APFixedPoint(16, getU8Pos4())); CheckMul(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS32Pos2()), APFixedPoint(44, getS32Pos2())); CheckMul(APFixedPoint(11, getS16Neg18()), APFixedPoint(1, getS16Neg18()), APFixedPoint(0, getS16Neg18())); CheckMul(APFixedPoint(11, getU8Neg10()), APFixedPoint(1, getU8Neg10()), APFixedPoint(0, getU8Neg10())); CheckMul(APFixedPoint(11, getU8Pos4()), APFixedPoint(1, getU8Pos4()), APFixedPoint(176, getU8Pos4())); CheckMul(APFixedPoint(512, getS16Neg18()), APFixedPoint(512, getS16Neg18()), APFixedPoint(1, getS16Neg18())); CheckMul(APFixedPoint(32, getU8Neg10()), APFixedPoint(32, getU8Neg10()), APFixedPoint(1, getU8Neg10())); CheckMul(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS16Neg18()), APFixedPoint(44, FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckMul( APFixedPoint(11, getU8Neg10()), APFixedPoint(-9472, getS16Neg18()), APFixedPoint(-102, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckMul( APFixedPoint::getMax(getU8Neg10()), APFixedPoint::getMax(getS16Neg18()), APFixedPoint(8159, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckMul( APFixedPoint::getMin(getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), APFixedPoint(0, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckMul(APFixedPoint::getMin(getS32Pos2()), APFixedPoint::getMin(getS16Neg18()), APFixedPoint(281474976710656, FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckMulOverflow(APFixedPoint::getMax(getS32Pos2()), APFixedPoint::getMax(getU8Pos4())); CheckMulOverflow(APFixedPoint::getMin(getS32Pos2()), APFixedPoint::getMax(getU8Pos4())); } void CheckDiv(const APFixedPoint &Lhs, const APFixedPoint &Rhs, const APFixedPoint &Expected) { bool Overflow = false; APFixedPoint Result = Lhs.div(Rhs, &Overflow); ASSERT_FALSE(Overflow); ASSERT_EQ(Result.getSemantics(), Expected.getSemantics()); ASSERT_EQ(Result, Expected); } void CheckDivOverflow(const APFixedPoint &Lhs, const APFixedPoint &Rhs) { bool Overflow = false; APFixedPoint Result = Lhs.div(Rhs, &Overflow); ASSERT_TRUE(Overflow); } TEST(FixedPoint, div) { CheckDiv(APFixedPoint(1, getS32Pos2()), APFixedPoint(1, getS32Pos2()), APFixedPoint(0, getS32Pos2())); CheckDivOverflow(APFixedPoint(1, getS16Neg18()), APFixedPoint(1, getS16Neg18())); CheckDivOverflow(APFixedPoint(1, getU8Neg10()), APFixedPoint(1, getU8Neg10())); CheckDiv(APFixedPoint(1, getU8Pos4()), APFixedPoint(1, getU8Pos4()), APFixedPoint(0, getU8Pos4())); CheckDiv(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS32Pos2()), APFixedPoint(2, getS32Pos2())); CheckDiv(APFixedPoint(11, getU8Pos4()), APFixedPoint(1, getU8Pos4()), APFixedPoint(0, getU8Pos4())); CheckDiv(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS16Neg18()), APFixedPoint(3023656976384, FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckDiv(APFixedPoint(11, getU8Neg10()), APFixedPoint(-11264, getS16Neg18()), APFixedPoint::getMin(FixedPointSemantics( 17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckDiv(APFixedPoint(11, getU8Neg10()), APFixedPoint(11265, getS16Neg18()), APFixedPoint(0xfffa, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckDivOverflow(APFixedPoint(11, getU8Neg10()), APFixedPoint(11264, getS16Neg18())); CheckDivOverflow(APFixedPoint(11, getU8Neg10()), APFixedPoint(-9472, getS16Neg18())); CheckDivOverflow(APFixedPoint::getMax(getU8Neg10()), APFixedPoint::getMax(getS16Neg18())); CheckDiv( APFixedPoint::getMin(getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), APFixedPoint(0, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); CheckDiv( APFixedPoint(1, getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), APFixedPoint(-2048, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, true, false, false))); } } // namespace