[ADT] Add support for more formats in APFixedPoint

Prior to this patch FixedPointSemantics and APFixedPoint only support semantics where
the Scale larger or equal to zero and the Width is larger or equal to the Scale.
This patch removes both those requirements while staying API compatible.
This commit is contained in:
Tyker 2022-09-13 18:55:32 -07:00
parent 7ad7c4ea86
commit 1654b22ac0
5 changed files with 550 additions and 67 deletions

View File

@ -17,6 +17,7 @@
#define LLVM_ADT_APFIXEDPOINT_H
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@ -32,31 +33,51 @@ struct fltSemantics;
/// in the value this represents is treated as padding.
class FixedPointSemantics {
public:
static constexpr unsigned WidthBitWidth = 16;
static constexpr unsigned LsbWeightBitWidth = 13;
/// Used to differentiate between constructors with Width and Lsb from the
/// default Width and scale
struct Lsb {
int LsbWeight;
};
FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned,
bool IsSaturated, bool HasUnsignedPadding)
: Width(Width), Scale(Scale), IsSigned(IsSigned),
: FixedPointSemantics(Width, Lsb{-static_cast<int>(Scale)}, IsSigned,
IsSaturated, HasUnsignedPadding) {}
FixedPointSemantics(unsigned Width, Lsb Weight, bool IsSigned,
bool IsSaturated, bool HasUnsignedPadding)
: Width(Width), LsbWeight(Weight.LsbWeight), IsSigned(IsSigned),
IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) {
assert(Width >= Scale && "Not enough room for the scale");
assert(isUInt<WidthBitWidth>(Width) && isInt<LsbWeightBitWidth>(Weight.LsbWeight));
assert(!(IsSigned && HasUnsignedPadding) &&
"Cannot have unsigned padding on a signed type.");
}
/// Check if the Semantic follow the requirements of an older more limited
/// version of this class
bool isValidLegacySema() const {
return LsbWeight <= 0 && Width >= -LsbWeight;
}
unsigned getWidth() const { return Width; }
unsigned getScale() const { return Scale; }
unsigned getScale() const { assert(isValidLegacySema()); return -LsbWeight; }
int getLsbWeight() const { return LsbWeight; }
int getMsbWeight() const {
return LsbWeight + Width - 1 /*Both lsb and msb are both part of width*/;
}
bool isSigned() const { return IsSigned; }
bool isSaturated() const { return IsSaturated; }
bool hasUnsignedPadding() const { return HasUnsignedPadding; }
void setSaturated(bool Saturated) { IsSaturated = Saturated; }
/// return true if the first bit doesn't have a strictly positive weight
bool hasSignOrPaddingBit() const { return IsSigned || HasUnsignedPadding; }
/// Return the number of integral bits represented by these semantics. These
/// are separate from the fractional bits and do not include the sign or
/// padding bit.
unsigned getIntegralBits() const {
if (IsSigned || (!IsSigned && HasUnsignedPadding))
return Width - Scale - 1;
else
return Width - Scale;
return std::max(getMsbWeight() + 1 - hasSignOrPaddingBit(), 0);
}
/// Return the FixedPointSemantics that allows for calculating the full
@ -66,6 +87,9 @@ public:
FixedPointSemantics
getCommonSemantics(const FixedPointSemantics &Other) const;
/// Print semantics for debug purposes
void print(llvm::raw_ostream& OS) const;
/// Returns true if this fixed-point semantic with its value bits interpreted
/// as an integer can fit in the given floating point semantic without
/// overflowing to infinity.
@ -83,20 +107,49 @@ public:
/*HasUnsignedPadding=*/false);
}
bool operator==(FixedPointSemantics Other) const {
return Width == Other.Width && LsbWeight == Other.LsbWeight &&
IsSigned == Other.IsSigned && IsSaturated == Other.IsSaturated &&
HasUnsignedPadding == Other.HasUnsignedPadding;
}
bool operator!=(FixedPointSemantics Other) const { return !(*this == Other); }
private:
unsigned Width : 16;
unsigned Scale : 13;
unsigned Width : WidthBitWidth;
signed int LsbWeight : LsbWeightBitWidth;
unsigned IsSigned : 1;
unsigned IsSaturated : 1;
unsigned HasUnsignedPadding : 1;
};
static_assert(sizeof(FixedPointSemantics) == 4, "");
inline hash_code hash_value(const FixedPointSemantics &Val) {
return hash_value(bit_cast<uint32_t>(Val));
}
template <> struct DenseMapInfo<FixedPointSemantics> {
static inline FixedPointSemantics getEmptyKey() {
return FixedPointSemantics(0, 0, false, false, false);
}
static inline FixedPointSemantics getTombstoneKey() {
return FixedPointSemantics(0, 1, false, false, false);
}
static unsigned getHashValue(const FixedPointSemantics &Val) {
return hash_value(Val);
}
static bool isEqual(const char &LHS, const char &RHS) { return LHS == RHS; }
};
/// The APFixedPoint class works similarly to APInt/APSInt in that it is a
/// functional replacement for a scaled integer. It is meant to replicate the
/// fixed point types proposed in ISO/IEC JTC1 SC22 WG14 N1169. The class carries
/// info about the fixed point type's width, sign, scale, and saturation, and
/// provides different operations that would normally be performed on fixed point
/// types.
/// functional replacement for a scaled integer. It supports a wide range of
/// semantics including the one used by fixed point types proposed in ISO/IEC
/// JTC1 SC22 WG14 N1169. The class carries the value and semantics of
/// a fixed point, and provides different operations that would normally be
/// performed on fixed point types.
class APFixedPoint {
public:
APFixedPoint(const APInt &Val, const FixedPointSemantics &Sema)
@ -114,6 +167,8 @@ public:
APSInt getValue() const { return APSInt(Val, !Sema.isSigned()); }
inline unsigned getWidth() const { return Sema.getWidth(); }
inline unsigned getScale() const { return Sema.getScale(); }
int getLsbWeight() const { return Sema.getLsbWeight(); }
int getMsbWeight() const { return Sema.getMsbWeight(); }
inline bool isSaturated() const { return Sema.isSaturated(); }
inline bool isSigned() const { return Sema.isSigned(); }
inline bool hasPadding() const { return Sema.hasUnsignedPadding(); }
@ -154,10 +209,13 @@ public:
/// Return the integral part of this fixed point number, rounded towards
/// zero. (-2.5k -> -2)
APSInt getIntPart() const {
if (getMsbWeight() < 0)
return APSInt(APInt::getZero(getWidth()), Val.isUnsigned());
APSInt ExtVal =
(getLsbWeight() > 0) ? Val.extend(getWidth() + getLsbWeight()) : Val;
if (Val < 0 && Val != -Val) // Cover the case when we have the min val
return -(-Val >> getScale());
else
return Val >> getScale();
return -(-ExtVal.relativeShl(getLsbWeight()));
return ExtVal.relativeShl(getLsbWeight());
}
/// Return the integral part of this fixed point number, rounded towards
@ -179,6 +237,9 @@ public:
return std::string(S.str());
}
void print(raw_ostream &) const;
void dump() const;
// If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1.
int compare(const APFixedPoint &Other) const;
bool operator==(const APFixedPoint &Other) const {
@ -232,6 +293,29 @@ inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) {
return OS;
}
inline hash_code hash_value(const APFixedPoint &Val) {
return hash_combine(Val.getSemantics(), Val.getValue());
}
template <> struct DenseMapInfo<APFixedPoint> {
static inline APFixedPoint getEmptyKey() {
return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getEmptyKey());
}
static inline APFixedPoint getTombstoneKey() {
return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getTombstoneKey());
}
static unsigned getHashValue(const APFixedPoint &Val) {
return hash_value(Val);
}
static bool isEqual(const APFixedPoint &LHS, const APFixedPoint &RHS) {
return LHS.getSemantics() == RHS.getSemantics() &&
LHS.getValue() == RHS.getValue();
}
};
} // namespace llvm
#endif

View File

@ -19,6 +19,7 @@
#include "llvm/Support/MathExtras.h"
#include <cassert>
#include <climits>
#include <cmath>
#include <cstring>
#include <utility>
@ -857,6 +858,28 @@ public:
return R;
}
/// relative logical shift right
APInt relativeLShr(int RelativeShift) const {
int Shift = std::abs(RelativeShift);
return RelativeShift > 0 ? lshr(Shift) : shl(Shift);
}
/// relative logical shift left
APInt relativeLShl(int RelativeShift) const {
return relativeLShr(-RelativeShift);
}
/// relative arithmetic shift right
APInt relativeAShr(int RelativeShift) const {
int Shift = std::abs(RelativeShift);
return RelativeShift > 0 ? ashr(Shift) : shl(Shift);
}
/// relative arithmetic shift left
APInt relativeAShl(int RelativeShift) const {
return relativeAShr(-RelativeShift);
}
/// Rotate left by rotateAmt.
APInt rotl(unsigned rotateAmt) const;

View File

@ -144,6 +144,10 @@ public:
ashrInPlace(Amt);
return *this;
}
APSInt relativeShr(unsigned Amt) const {
return IsUnsigned ? APSInt(relativeLShr(Amt), true)
: APSInt(relativeAShr(Amt), false);
}
inline bool operator<(const APSInt& RHS) const {
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
@ -198,6 +202,10 @@ public:
static_cast<APInt&>(*this) <<= Amt;
return *this;
}
APSInt relativeShl(unsigned Amt) const {
return IsUnsigned ? APSInt(relativeLShl(Amt), true)
: APSInt(relativeAShl(Amt), false);
}
APSInt& operator++() {
++(static_cast<APInt&>(*this));

View File

@ -18,25 +18,32 @@
namespace llvm {
void FixedPointSemantics::print(llvm::raw_ostream &OS) const {
OS << "width=" << getWidth() << ", ";
if (isValidLegacySema())
OS << "scale=" << getScale() << ", ";
OS << "msb=" << getMsbWeight() << ", ";
OS << "lsb=" << getLsbWeight() << ", ";
OS << "IsSigned=" << IsSigned << ", ";
OS << "HasUnsignedPadding=" << HasUnsignedPadding << ", ";
OS << "IsSaturated=" << IsSaturated;
}
APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema,
bool *Overflow) const {
APSInt NewVal = Val;
unsigned DstWidth = DstSema.getWidth();
unsigned DstScale = DstSema.getScale();
bool Upscaling = DstScale > getScale();
int RelativeUpscale = getLsbWeight() - DstSema.getLsbWeight();
if (Overflow)
*Overflow = false;
if (Upscaling) {
NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
NewVal <<= (DstScale - getScale());
} else {
NewVal >>= (getScale() - DstScale);
}
if (RelativeUpscale > 0)
NewVal = NewVal.extend(NewVal.getBitWidth() + RelativeUpscale);
NewVal = NewVal.relativeShl(RelativeUpscale);
auto Mask = APInt::getBitsSetFrom(
NewVal.getBitWidth(),
std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
std::min(DstSema.getIntegralBits() - DstSema.getLsbWeight(),
NewVal.getBitWidth()));
APInt Masked(NewVal & Mask);
// Change in the bits above the sign
@ -58,7 +65,7 @@ APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema,
*Overflow = true;
}
NewVal = NewVal.extOrTrunc(DstWidth);
NewVal = NewVal.extOrTrunc(DstSema.getWidth());
NewVal.setIsSigned(DstSema.isSigned());
return APFixedPoint(NewVal, DstSema);
}
@ -68,21 +75,16 @@ int APFixedPoint::compare(const APFixedPoint &Other) const {
APSInt OtherVal = Other.getValue();
bool ThisSigned = Val.isSigned();
bool OtherSigned = OtherVal.isSigned();
unsigned OtherScale = Other.getScale();
unsigned OtherWidth = OtherVal.getBitWidth();
unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
// Prevent overflow in the event the widths are the same but the scales differ
CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
: OtherScale - getScale();
int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight());
int CommonMsb = std::max(getMsbWeight(), Other.getMsbWeight());
unsigned CommonWidth = CommonMsb - CommonLsb + 1;
ThisVal = ThisVal.extOrTrunc(CommonWidth);
OtherVal = OtherVal.extOrTrunc(CommonWidth);
unsigned CommonScale = std::max(getScale(), OtherScale);
ThisVal = ThisVal.shl(CommonScale - getScale());
OtherVal = OtherVal.shl(CommonScale - OtherScale);
ThisVal = ThisVal.shl(getLsbWeight() - CommonLsb);
OtherVal = OtherVal.shl(Other.getLsbWeight() - CommonLsb);
if (ThisSigned && OtherSigned) {
if (ThisVal.sgt(OtherVal))
@ -152,9 +154,10 @@ bool FixedPointSemantics::fitsInFloatSemantics(
FixedPointSemantics FixedPointSemantics::getCommonSemantics(
const FixedPointSemantics &Other) const {
unsigned CommonScale = std::max(getScale(), Other.getScale());
unsigned CommonWidth =
std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight());
int CommonMSb = std::max(getMsbWeight() - hasSignOrPaddingBit(),
Other.getMsbWeight() - Other.hasSignOrPaddingBit());
unsigned CommonWidth = CommonMSb - CommonLsb + 1;
bool ResultIsSigned = isSigned() || Other.isSigned();
bool ResultIsSaturated = isSaturated() || Other.isSaturated();
@ -171,7 +174,7 @@ FixedPointSemantics FixedPointSemantics::getCommonSemantics(
if (ResultIsSigned || ResultHasUnsignedPadding)
CommonWidth++;
return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned,
ResultIsSaturated, ResultHasUnsignedPadding);
}
@ -252,10 +255,10 @@ APFixedPoint APFixedPoint::mul(const APFixedPoint &Other,
APSInt Result;
if (CommonFXSema.isSigned())
Result = ThisVal.smul_ov(OtherVal, Overflowed)
.ashr(CommonFXSema.getScale());
.relativeAShl(CommonFXSema.getLsbWeight());
else
Result = ThisVal.umul_ov(OtherVal, Overflowed)
.lshr(CommonFXSema.getScale());
.relativeLShl(CommonFXSema.getLsbWeight());
assert(!Overflowed && "Full multiplication cannot overflow!");
Result.setIsSigned(CommonFXSema.isSigned());
@ -290,7 +293,10 @@ APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
bool Overflowed = false;
// Widen the LHS and RHS so we can perform a full division.
unsigned Wide = CommonFXSema.getWidth() * 2;
// Also make sure that there will be enough space for the shift below to not
// overflow
unsigned Wide =
CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0);
if (CommonFXSema.isSigned()) {
ThisVal = ThisVal.sext(Wide);
OtherVal = OtherVal.sext(Wide);
@ -301,7 +307,10 @@ APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
// Upscale to compensate for the loss of precision from division, and
// perform the full division.
ThisVal = ThisVal.shl(CommonFXSema.getScale());
if (CommonFXSema.getLsbWeight() < 0)
ThisVal = ThisVal.shl(-CommonFXSema.getLsbWeight());
else if (CommonFXSema.getLsbWeight() > 0)
OtherVal = OtherVal.shl(CommonFXSema.getLsbWeight());
APSInt Result;
if (CommonFXSema.isSigned()) {
APInt Rem;
@ -371,17 +380,30 @@ APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const {
void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
APSInt Val = getValue();
unsigned Scale = getScale();
int Lsb = getLsbWeight();
int OrigWidth = getWidth();
if (Val.isSigned() && Val.isNegative() && Val != -Val) {
if (Lsb >= 0) {
APSInt IntPart = Val;
IntPart = IntPart.extend(IntPart.getBitWidth() + Lsb);
IntPart <<= Lsb;
IntPart.toString(Str, /*Radix=*/10);
Str.push_back('.');
Str.push_back('0');
return;
}
if (Val.isSigned() && Val.isNegative()) {
Val = -Val;
Val.setIsUnsigned(true);
Str.push_back('-');
}
APSInt IntPart = Val >> Scale;
int Scale = -getLsbWeight();
APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0);
// Add 4 digits to hold the value after multiplying 10 (the radix)
unsigned Width = Val.getBitWidth() + 4;
unsigned Width = std::max(OrigWidth, Scale) + 4;
APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width);
APInt RadixInt = APInt(Width, 10);
@ -396,6 +418,13 @@ void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
} while (FractPart != 0);
}
void APFixedPoint::print(raw_ostream &OS) const {
OS << "APFixedPoint(" << toString() << ", {";
Sema.print(OS);
OS << "})";
}
LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); }
APFixedPoint APFixedPoint::negate(bool *Overflow) const {
if (!isSaturated()) {
if (Overflow)
@ -480,7 +509,7 @@ APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {
// Scale down the integer value in the float to match the correct scaling
// factor.
APFloat ScaleFactor(std::pow(2, -(int)Sema.getScale()));
APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight()));
bool Ignored;
ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
Flt.multiply(ScaleFactor, LosslessRM);
@ -535,7 +564,7 @@ APFixedPoint::getFromFloatValue(const APFloat &Value,
// the integer range instead. Rounding mode is irrelevant here.
// It is fine if this overflows to infinity even for saturating types,
// since we will use floating point comparisons to check for saturation.
APFloat ScaleFactor(std::pow(2, DstFXSema.getScale()));
APFloat ScaleFactor(std::pow(2, -DstFXSema.getLsbWeight()));
ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
Val.multiply(ScaleFactor, LosslessRM);
@ -549,7 +578,7 @@ APFixedPoint::getFromFloatValue(const APFloat &Value,
// we risk checking for overflow with a value that is outside the
// representable range of the fixed-point semantic even though no overflow
// would occur had we rounded first.
ScaleFactor = APFloat(std::pow(2, -(int)DstFXSema.getScale()));
ScaleFactor = APFloat(std::pow(2, DstFXSema.getLsbWeight()));
ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
Val.roundToIntegral(RM);
Val.multiply(ScaleFactor, LosslessRM);

View File

@ -132,6 +132,35 @@ FixedPointSemantics getPadULFractSema() {
/*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()));
@ -160,6 +189,10 @@ TEST(FixedPointTest, getMax) {
CheckUnpaddedMax(getUSFractSema());
CheckUnpaddedMax(getUFractSema());
CheckUnpaddedMax(getULFractSema());
CheckUnpaddedMax(getU8Neg10());
CheckUnpaddedMax(getS16Neg18());
CheckUnpaddedMax(getU8Pos4());
CheckUnpaddedMax(getS32Pos2());
CheckPaddedMax(getPadUSAccumSema());
CheckPaddedMax(getPadUAccumSema());
@ -182,6 +215,10 @@ TEST(FixedPointTest, getMin) {
CheckMin(getUSFractSema());
CheckMin(getUFractSema());
CheckMin(getULFractSema());
CheckMin(getU8Neg10());
CheckMin(getS16Neg18());
CheckMin(getU8Pos4());
CheckMin(getS32Pos2());
CheckMin(getPadUSAccumSema());
CheckMin(getPadUAccumSema());
@ -191,30 +228,40 @@ TEST(FixedPointTest, getMin) {
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) {
unsigned Scale = Sema.getScale();
int64_t FullFactPart =
(Sema.getLsbWeight() > 0) ? 0 : (1ULL << (-Sema.getLsbWeight() - 1));
// Value with a fraction
APFixedPoint ValWithFract(APInt(Sema.getWidth(),
(IntPart << Scale) + (1ULL << (Scale - 1)),
Sema.isSigned()),
Sema);
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(), (1ULL << (Scale - 1)), Sema.isSigned()), Sema);
APFixedPoint JustFract(APInt(Sema.getWidth(), FullFactPart, Sema.isSigned()),
Sema);
ASSERT_EQ(JustFract.getIntPart(), 0);
// Whole number
APFixedPoint WholeNum(
APInt(Sema.getWidth(), (IntPart << Scale), Sema.isSigned()), Sema);
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(), (IntPart << Scale), Sema.isSigned()), Sema);
APFixedPoint Negative(APInt(Sema.getWidth(),
relativeShr(IntPart, Sema.getLsbWeight()),
Sema.isSigned()),
Sema);
ASSERT_EQ(Negative.getIntPart(), IntPart);
}
}
@ -237,6 +284,8 @@ TEST(FixedPoint, getIntPart) {
CheckIntPart(getUSAccumSema(), 2);
CheckIntPart(getUAccumSema(), 2);
CheckIntPart(getULAccumSema(), 2);
CheckIntPart(getU8Pos4(), 32);
CheckIntPart(getS32Pos2(), 32);
// Zero
CheckIntPart(getSAccumSema(), 0);
@ -253,6 +302,11 @@ TEST(FixedPoint, getIntPart) {
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);
@ -262,6 +316,8 @@ TEST(FixedPoint, getIntPart) {
CheckIntPartMin(getFractSema(), -1);
CheckIntPartMin(getLFractSema(), -1);
CheckIntPartMin(getS32Pos2(), -8589934592);
// Max
CheckIntPartMax(getSAccumSema(), 255);
CheckIntPartMax(getAccumSema(), 65535);
@ -270,6 +326,9 @@ TEST(FixedPoint, getIntPart) {
CheckIntPartMax(getUAccumSema(), 65535);
CheckIntPartMax(getULAccumSema(), 4294967295);
CheckIntPartMax(getU8Pos4(), 255 << 4);
CheckIntPartMax(getS32Pos2(), 2147483647ull << 2);
CheckIntPartMax(getSFractSema(), 0);
CheckIntPartMax(getFractSema(), 0);
CheckIntPartMax(getLFractSema(), 0);
@ -312,6 +371,13 @@ TEST(FixedPoint, compare) {
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()));
@ -351,6 +417,8 @@ TEST(FixedPoint, compare) {
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()));
@ -371,10 +439,10 @@ void CheckUnsaturatedConversion(FixedPointSemantics Src,
if (IsNegative)
ScaledVal = -ScaledVal;
if (Dst.getScale() > Src.getScale()) {
ScaledVal <<= (Dst.getScale() - Src.getScale());
if (Dst.getLsbWeight() < Src.getLsbWeight()) {
ScaledVal <<= (Src.getLsbWeight() - Dst.getLsbWeight());
} else {
ScaledVal >>= (Src.getScale() - Dst.getScale());
ScaledVal >>= (Dst.getLsbWeight() - Src.getLsbWeight());
}
if (IsNegative)
@ -672,6 +740,26 @@ void CheckFloatToFixedConversion(APFloat &Val, const FixedPointSemantics &Sema,
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);
@ -693,6 +781,11 @@ TEST(FixedPoint, FloatToFixed) {
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);
@ -711,6 +804,11 @@ TEST(FixedPoint, FloatToFixed) {
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);
@ -729,6 +827,11 @@ TEST(FixedPoint, FloatToFixed) {
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);
@ -747,6 +850,11 @@ TEST(FixedPoint, FloatToFixed) {
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);
@ -765,6 +873,11 @@ TEST(FixedPoint, FloatToFixed) {
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);
@ -783,6 +896,11 @@ TEST(FixedPoint, FloatToFixed) {
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);
@ -801,6 +919,11 @@ TEST(FixedPoint, FloatToFixed) {
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;
@ -821,6 +944,23 @@ TEST(FixedPoint, FloatToFixed) {
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,
@ -853,6 +993,11 @@ TEST(FixedPoint, FixedToFloat) {
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);
@ -866,6 +1011,11 @@ TEST(FixedPoint, FixedToFloat) {
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);
@ -873,6 +1023,10 @@ TEST(FixedPoint, FixedToFloat) {
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);
@ -892,6 +1046,9 @@ TEST(FixedPoint, FixedToFloat) {
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);
@ -899,6 +1056,9 @@ TEST(FixedPoint, FixedToFloat) {
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(),
@ -908,6 +1068,8 @@ TEST(FixedPoint, FixedToFloat) {
CheckFixedToFloatConversion(Val, getULFractSema(),
0.2500000298023223876953125f);
CheckFixedToFloatConversion(Val, getS32Pos2(), 4294967808.0f);
Val = 0x40000040ULL;
CheckFixedToFloatConversion(Val, getAccumSema(), 32768.0f);
CheckFixedToFloatConversion(Val, getLFractSema(), 0.5f);
@ -915,12 +1077,189 @@ TEST(FixedPoint, FixedToFloat) {
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