forked from OSchip/llvm-project
[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:
parent
7ad7c4ea86
commit
1654b22ac0
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue