llvm-project/llvm/unittests/ADT/APFixedPointTest.cpp
Nikita Popov 255a99c29f
[APInt] Fix APInt constructions where value does not fit bitwidth (NFCI) (#80309)
This fixes all the places that hit the new assertion added in
https://github.com/llvm/llvm-project/pull/106524 in tests. That is,
cases where the value passed to the APInt constructor is not an N-bit
signed/unsigned integer, where N is the bit width and signedness is
determined by the isSigned flag.

The fixes either set the correct value for isSigned, set the
implicitTrunc flag, or perform more calculations inside APInt.

Note that the assertion is currently still disabled by default, so this
patch is mostly NFC.
2024-10-17 08:48:08 +02:00

1310 lines
55 KiB
C++

//===- 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(), /*implicitTrunc=*/true),
Sema);
ASSERT_EQ(ValWithFract.getIntPart(), IntPart);
// Just fraction
APFixedPoint JustFract(APInt(Sema.getWidth(), FullFactPart, Sema.isSigned(),
/*implicitTrunc=*/true),
Sema);
ASSERT_EQ(JustFract.getIntPart(), 0);
// Whole number
APFixedPoint WholeNum(APInt(Sema.getWidth(),
relativeShr(IntPart, Sema.getLsbWeight()),
Sema.isSigned(), /*implicitTrunc=*/true),
Sema);
ASSERT_EQ(WholeNum.getIntPart(), IntPart);
// Negative
if (Sema.isSigned()) {
APFixedPoint Negative(APInt(Sema.getWidth(),
relativeShr(IntPart, Sema.getLsbWeight()),
Sema.isSigned(), /*implicitTrunc=*/true),
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)));
}
TEST(FixedPoint, semanticsSerialization) {
auto roundTrip = [](FixedPointSemantics FPS) -> bool {
uint32_t I = FPS.toOpaqueInt();
FixedPointSemantics FPS2 = FixedPointSemantics::getFromOpaqueInt(I);
return FPS == FPS2;
};
ASSERT_TRUE(roundTrip(getS32Pos2()));
ASSERT_TRUE(roundTrip(getU8Pos4()));
ASSERT_TRUE(roundTrip(getS16Neg18()));
ASSERT_TRUE(roundTrip(getU8Neg10()));
ASSERT_TRUE(roundTrip(getPadULFractSema()));
ASSERT_TRUE(roundTrip(getPadUFractSema()));
ASSERT_TRUE(roundTrip(getPadUSFractSema()));
ASSERT_TRUE(roundTrip(getPadULAccumSema()));
ASSERT_TRUE(roundTrip(getPadUAccumSema()));
ASSERT_TRUE(roundTrip(getPadUSAccumSema()));
ASSERT_TRUE(roundTrip(getULFractSema()));
ASSERT_TRUE(roundTrip(getUFractSema()));
ASSERT_TRUE(roundTrip(getUSFractSema()));
ASSERT_TRUE(roundTrip(getULAccumSema()));
ASSERT_TRUE(roundTrip(getUAccumSema()));
ASSERT_TRUE(roundTrip(getUSAccumSema()));
ASSERT_TRUE(roundTrip(getLFractSema()));
ASSERT_TRUE(roundTrip(getFractSema()));
ASSERT_TRUE(roundTrip(getSFractSema()));
ASSERT_TRUE(roundTrip(getLAccumSema()));
ASSERT_TRUE(roundTrip(getAccumSema()));
ASSERT_TRUE(roundTrip(getSAccumSema()));
}
} // namespace