diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp | 103 |
1 files changed, 67 insertions, 36 deletions
diff --git a/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp b/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp index f1d07184793c..3eea01bc9809 100644 --- a/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp +++ b/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp @@ -14,27 +14,36 @@ #include "llvm/ADT/APFixedPoint.h" #include "llvm/ADT/APFloat.h" +#include <cmath> + 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 @@ -56,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); } @@ -66,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)) @@ -150,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(); @@ -169,7 +174,7 @@ FixedPointSemantics FixedPointSemantics::getCommonSemantics( if (ResultIsSigned || ResultHasUnsignedPadding) CommonWidth++; - return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned, + return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned, ResultIsSaturated, ResultHasUnsignedPadding); } @@ -250,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()); @@ -288,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); @@ -299,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; @@ -369,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 (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) { + 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); @@ -394,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) @@ -478,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); @@ -533,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); @@ -547,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); |