1//===- APFixedPoint.cpp - Fixed point constant handling ---------*- C++ -*-===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
10/// Defines the implementation for the fixed point number interface.
12//===----------------------------------------------------------------------===//
22 OS <<
"width=" <<
getWidth() <<
", ";
24 OS <<
"scale=" <<
getScale() <<
", ";
27 OS <<
"IsSigned=" << IsSigned <<
", ";
28 OS <<
"HasUnsignedPadding=" << HasUnsignedPadding <<
", ";
29 OS <<
"IsSaturated=" << IsSaturated;
38 std::memcpy(&
F, &
I,
sizeof(
F));
43 bool *Overflow)
const {
49 if (RelativeUpscale > 0)
59 // Change in the bits above the sign
61 // Found overflow in the bits above the sign
68 // If the dst semantics are unsigned, but our value is signed and negative, we
71 // Found negative overflow for unsigned result
86 bool ThisSigned = Val.isSigned();
87 bool OtherSigned = OtherVal.
isSigned();
91 unsigned CommonWidth = CommonMsb - CommonLsb + 1;
97 OtherVal = OtherVal.
shl(
Other.getLsbWeight() - CommonLsb);
99 if (ThisSigned && OtherSigned) {
100 if (ThisVal.
sgt(OtherVal))
102 else if (ThisVal.
slt(OtherVal))
104 }
else if (!ThisSigned && !OtherSigned) {
105 if (ThisVal.
ugt(OtherVal))
107 else if (ThisVal.
ult(OtherVal))
109 }
else if (ThisSigned && !OtherSigned) {
112 else if (ThisVal.
ugt(OtherVal))
114 else if (ThisVal.
ult(OtherVal))
117 // !ThisSigned && OtherSigned
120 else if (ThisVal.
ugt(OtherVal))
122 else if (ThisVal.
ult(OtherVal))
132 if (IsUnsigned && Sema.hasUnsignedPadding())
143 APSInt Val(Sema.getWidth(), !Sema.isSigned());
144 Val.setBit(
/*BitPosition=*/0);
150 // A fixed point semantic fits in a floating point semantic if the maximum
151 // and minimum values as integers of the fixed point semantic can fit in the
152 // floating point semantic.
154 // If these values do not fit, then a floating point rescaling of the true
155 // maximum/minimum value will not fit either, so the floating point semantic
156 // cannot be used to perform such a rescaling.
175 Other.getMsbWeight() -
Other.hasSignOrPaddingBit());
176 unsigned CommonWidth = CommonMSb - CommonLsb + 1;
180 bool ResultHasUnsignedPadding =
false;
181 if (!ResultIsSigned) {
182 // Both are unsigned.
184 Other.hasUnsignedPadding() && !ResultIsSaturated;
187 // If the result is signed, add an extra bit for the sign. Otherwise, if it is
188 // unsigned and has unsigned padding, we only need to add the extra padding
189 // bit back if we are not saturating.
190 if (ResultIsSigned || ResultHasUnsignedPadding)
194 ResultIsSaturated, ResultHasUnsignedPadding);
198 bool *Overflow)
const {
199 auto CommonFXSema = Sema.getCommonSemantics(
Other.getSemantics());
204 bool Overflowed =
false;
207 if (CommonFXSema.isSaturated()) {
208 Result = CommonFXSema.isSigned() ? ThisVal.
sadd_sat(OtherVal)
212 : ThisVal.
uadd_ov(OtherVal, Overflowed);
216 *Overflow = Overflowed;
222 bool *Overflow)
const {
223 auto CommonFXSema = Sema.getCommonSemantics(
Other.getSemantics());
228 bool Overflowed =
false;
231 if (CommonFXSema.isSaturated()) {
232 Result = CommonFXSema.isSigned() ? ThisVal.
ssub_sat(OtherVal)
236 : ThisVal.
usub_ov(OtherVal, Overflowed);
240 *Overflow = Overflowed;
246 bool *Overflow)
const {
247 auto CommonFXSema = Sema.getCommonSemantics(
Other.getSemantics());
252 bool Overflowed =
false;
254 // Widen the LHS and RHS so we can perform a full multiplication.
255 unsigned Wide = CommonFXSema.getWidth() * 2;
256 if (CommonFXSema.isSigned()) {
257 ThisVal = ThisVal.
sext(Wide);
258 OtherVal = OtherVal.
sext(Wide);
260 ThisVal = ThisVal.
zext(Wide);
261 OtherVal = OtherVal.
zext(Wide);
264 // Perform the full multiplication and downscale to get the same scale.
266 // Note that the right shifts here perform an implicit downwards rounding.
267 // This rounding could discard bits that would technically place the result
268 // outside the representable range. We interpret the spec as allowing us to
269 // perform the rounding step first, avoiding the overflow case that would
272 if (CommonFXSema.isSigned())
273 Result = ThisVal.
smul_ov(OtherVal, Overflowed)
276 Result = ThisVal.
umul_ov(OtherVal, Overflowed)
278 assert(!Overflowed &&
"Full multiplication cannot overflow!");
279 Result.setIsSigned(CommonFXSema.isSigned());
281 // If our result lies outside of the representative range of the common
282 // semantic, we either have overflow or saturation.
287 if (CommonFXSema.isSaturated()) {
290 else if (Result > Max)
293 Overflowed = Result < Min || Result > Max;
297 *Overflow = Overflowed;
299 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
304 bool *Overflow)
const {
305 auto CommonFXSema = Sema.getCommonSemantics(
Other.getSemantics());
310 bool Overflowed =
false;
312 // Widen the LHS and RHS so we can perform a full division.
313 // Also make sure that there will be enough space for the shift below to not
316 CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0);
317 if (CommonFXSema.isSigned()) {
318 ThisVal = ThisVal.
sext(Wide);
319 OtherVal = OtherVal.
sext(Wide);
321 ThisVal = ThisVal.
zext(Wide);
322 OtherVal = OtherVal.
zext(Wide);
325 // Upscale to compensate for the loss of precision from division, and
326 // perform the full division.
327 if (CommonFXSema.getLsbWeight() < 0)
328 ThisVal = ThisVal.
shl(-CommonFXSema.getLsbWeight());
329 else if (CommonFXSema.getLsbWeight() > 0)
330 OtherVal = OtherVal.
shl(CommonFXSema.getLsbWeight());
332 if (CommonFXSema.isSigned()) {
335 // If the quotient is negative and the remainder is nonzero, round
336 // towards negative infinity by subtracting epsilon from the result.
340 Result = ThisVal.
udiv(OtherVal);
342 Result.setIsSigned(CommonFXSema.isSigned());
344 // If our result lies outside of the representative range of the common
345 // semantic, we either have overflow or saturation.
350 if (CommonFXSema.isSaturated()) {
353 else if (Result > Max)
356 Overflowed = Result < Min || Result > Max;
360 *Overflow = Overflowed;
362 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
368 bool Overflowed =
false;
371 unsigned Wide = Sema.getWidth() * 2;
373 ThisVal = ThisVal.
sext(Wide);
375 ThisVal = ThisVal.
zext(Wide);
377 // Clamp the shift amount at the original width, and perform the shift.
379 APSInt Result = ThisVal << Amt;
380 Result.setIsSigned(Sema.isSigned());
382 // If our result lies outside of the representative range of the
383 // semantic, we either have overflow or saturation.
386 if (Sema.isSaturated()) {
389 else if (Result > Max)
392 Overflowed = Result < Min || Result > Max;
396 *Overflow = Overflowed;
398 return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema);
410 IntPart.toString(Str,
/*Radix=*/10);
416 if (Val.isSigned() && Val.isNegative()) {
418 Val.setIsUnsigned(
true);
425 // Add 4 digits to hold the value after multiplying 10 (the radix)
426 unsigned Width = std::max(OrigWidth, Scale) + 4;
431 IntPart.toString(Str,
/*Radix=*/10);
434 (FractPart * RadixInt)
436 .toString(Str,
/*Radix=*/10, Val.isSigned());
437 FractPart = (FractPart * RadixInt) & FractPartMask;
438 }
while (FractPart != 0);
442 OS <<
"APFixedPoint(" <<
toString() <<
", {";
447#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
459 // We never overflow for saturation
470 bool *Overflow)
const {
477 if (SrcWidth < DstWidth) {
478 Result = Result.extend(DstWidth);
479 }
else if (SrcWidth > DstWidth) {
480 DstMin = DstMin.
extend(SrcWidth);
481 DstMax = DstMax.
extend(SrcWidth);
485 if (Result.isSigned() && !DstSign) {
486 *Overflow = Result.isNegative() || Result.ugt(DstMax);
487 }
else if (Result.isUnsigned() && DstSign) {
488 *Overflow = Result.ugt(DstMax);
490 *Overflow = Result < DstMin || Result > DstMax;
494 Result.setIsSigned(DstSign);
495 return Result.extOrTrunc(DstWidth);
511 // For some operations, rounding mode has an effect on the result, while
512 // other operations are lossless and should never result in rounding.
513 // To signify which these operations are, we define two rounding modes here.
517 // Make sure that we are operating in a type that works with this fixed-point
520 while (!Sema.fitsInFloatSemantics(*OpSema))
523 // Convert the fixed point value bits as an integer. If the floating point
524 // value does not have the required precision, we will round according to the
529 // If we cared about checking for precision loss, we could look at this
533 // Scale down the integer value in the float to match the correct scaling
535 APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight()));
537 ScaleFactor.
convert(*OpSema, LosslessRM, &Ignored);
538 Flt.multiply(ScaleFactor, LosslessRM);
540 if (OpSema != &FloatSema)
541 Flt.convert(FloatSema, RM, &Ignored);
558 // For some operations, rounding mode has an effect on the result, while
559 // other operations are lossless and should never result in rounding.
560 // To signify which these operations are, we define two rounding modes here,
561 // even though they are the same mode.
568 // Handle NaN immediately.
574 // Make sure that we are operating in a type that works with this fixed-point
583 if (&FloatSema != OpSema)
584 Val.convert(*OpSema, LosslessRM, &Ignored);
586 // Scale up the float so that the 'fractional' part of the mantissa ends up in
587 // the integer range instead. Rounding mode is irrelevant here.
588 // It is fine if this overflows to infinity even for saturating types,
589 // since we will use floating point comparisons to check for saturation.
591 ScaleFactor.
convert(*OpSema, LosslessRM, &Ignored);
592 Val.multiply(ScaleFactor, LosslessRM);
594 // Convert to the integral representation of the value. This rounding mode
597 Val.convertToInteger(Res, RM, &Ignored);
599 // Round the integral value and scale back. This makes the
600 // overflow calculations below work properly. If we do not round here,
601 // we risk checking for overflow with a value that is outside the
602 // representable range of the fixed-point semantic even though no overflow
603 // would occur had we rounded first.
605 ScaleFactor.
convert(*OpSema, LosslessRM, &Ignored);
606 Val.roundToIntegral(RM);
607 Val.multiply(ScaleFactor, LosslessRM);
609 // Check for overflow/saturation by checking if the floating point value
610 // is outside the range representable by the fixed-point value.
613 bool Overflowed =
false;
617 else if (Val < FloatMin)
620 Overflowed = Val > FloatMax || Val < FloatMin;
624 *Overflow = Overflowed;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Defines the fixed point number interface.
This file declares a class to represent arbitrary precision floating point values and provide a varie...
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
The APFixedPoint class works similarly to APInt/APSInt in that it is a functional replacement for a s...
LLVM_ABI APFixedPoint convert(const FixedPointSemantics &DstSema, bool *Overflow=nullptr) const
APFixedPoint(const APInt &Val, const FixedPointSemantics &Sema)
static LLVM_ABI APFixedPoint getMin(const FixedPointSemantics &Sema)
LLVM_ABI int compare(const APFixedPoint &Other) const
LLVM_ABI APSInt convertToInt(unsigned DstWidth, bool DstSign, bool *Overflow=nullptr) const
Return the integral part of this fixed point number, rounded towards zero.
static LLVM_ABI APFixedPoint getFromFloatValue(const APFloat &Value, const FixedPointSemantics &DstFXSema, bool *Overflow=nullptr)
Create an APFixedPoint with a value equal to that of the provided floating point value,...
LLVM_ABI APFixedPoint sub(const APFixedPoint &Other, bool *Overflow=nullptr) const
LLVM_ABI APFloat convertToFloat(const fltSemantics &FloatSema) const
Convert this fixed point number to a floating point value with the provided semantics.
LLVM_DUMP_METHOD void dump() const
static LLVM_ABI APFixedPoint getFromIntValue(const APSInt &Value, const FixedPointSemantics &DstFXSema, bool *Overflow=nullptr)
Create an APFixedPoint with a value equal to that of the provided integer, and in the same semantics ...
std::string toString() const
LLVM_ABI void print(raw_ostream &) const
unsigned getWidth() const
LLVM_ABI APFixedPoint negate(bool *Overflow=nullptr) const
Perform a unary negation (-X) on this fixed point type, taking into account saturation if applicable.
LLVM_ABI APFixedPoint shl(unsigned Amt, bool *Overflow=nullptr) const
static LLVM_ABI APFixedPoint getEpsilon(const FixedPointSemantics &Sema)
static LLVM_ABI const fltSemantics * promoteFloatSemantics(const fltSemantics *S)
Given a floating point semantic, return the next floating point semantic with a larger exponent and l...
LLVM_ABI APFixedPoint div(const APFixedPoint &Other, bool *Overflow=nullptr) const
LLVM_ABI APFixedPoint mul(const APFixedPoint &Other, bool *Overflow=nullptr) const
APSInt getIntPart() const
Return the integral part of this fixed point number, rounded towards zero.
LLVM_ABI APFixedPoint add(const APFixedPoint &Other, bool *Overflow=nullptr) const
static LLVM_ABI APFixedPoint getMax(const FixedPointSemantics &Sema)
static const fltSemantics & IEEEsingle()
static constexpr roundingMode rmTowardZero
llvm::RoundingMode roundingMode
IEEE-754R 4.3: Rounding-direction attributes.
static const fltSemantics & BFloat()
static const fltSemantics & IEEEquad()
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmNearestTiesToEven
static const fltSemantics & IEEEhalf()
static constexpr roundingMode rmNearestTiesToAway
opStatus
IEEE-754R 7: Default exception handling.
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Class for arbitrary precision integers.
LLVM_ABI APInt umul_ov(const APInt &RHS, bool &Overflow) const
LLVM_ABI APInt usub_sat(const APInt &RHS) const
LLVM_ABI APInt udiv(const APInt &RHS) const
Unsigned division operation.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
static LLVM_ABI void sdivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, APInt &Remainder)
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
APInt relativeLShl(int RelativeShift) const
relative logical shift left
LLVM_ABI APInt sadd_sat(const APInt &RHS) const
bool sgt(const APInt &RHS) const
Signed greater than comparison.
LLVM_ABI APInt usub_ov(const APInt &RHS, bool &Overflow) const
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
LLVM_ABI APInt sadd_ov(const APInt &RHS, bool &Overflow) const
APInt relativeAShl(int RelativeShift) const
relative arithmetic shift left
LLVM_ABI APInt uadd_ov(const APInt &RHS, bool &Overflow) const
LLVM_ABI APInt uadd_sat(const APInt &RHS) const
LLVM_ABI APInt smul_ov(const APInt &RHS, bool &Overflow) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
APInt shl(unsigned shiftAmt) const
Left-shift function.
bool isSignBitSet() const
Determine if sign bit of this APInt is set.
bool slt(const APInt &RHS) const
Signed less than comparison.
LLVM_ABI APInt ssub_ov(const APInt &RHS, bool &Overflow) const
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
LLVM_ABI APInt ssub_sat(const APInt &RHS) const
An arbitrary precision integer that knows its signedness.
APSInt extOrTrunc(uint32_t width) const
static APSInt getMinValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the minimum integer value with the given bit width and signedness.
static APSInt get(int64_t X)
bool isNegative() const
Determine sign of this APSInt.
static APSInt getMaxValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the maximum integer value with the given bit width and signedness.
void setIsSigned(bool Val)
APSInt relativeShl(unsigned Amt) const
APSInt extend(uint32_t width) const
The fixed point semantics work similarly to fltSemantics.
static LLVM_ABI FixedPointSemantics getFromOpaqueInt(uint32_t)
Create a FixedPointSemantics object from an integer created via toOpaqueInt().
unsigned getWidth() const
bool hasUnsignedPadding() const
unsigned getScale() const
unsigned getIntegralBits() const
Return the number of integral bits represented by these semantics.
LLVM_ABI FixedPointSemantics getCommonSemantics(const FixedPointSemantics &Other) const
Return the FixedPointSemantics that allows for calculating the full precision semantic that can preci...
LLVM_ABI void print(llvm::raw_ostream &OS) const
Print semantics for debug purposes.
LLVM_ABI bool fitsInFloatSemantics(const fltSemantics &FloatSema) const
Returns true if this fixed-point semantic with its value bits interpreted as an integer can fit in th...
bool hasSignOrPaddingBit() const
return true if the first bit doesn't have a strictly positive weight
LLVM_ABI uint32_t toOpaqueInt() const
Convert the semantics to a 32-bit unsigned integer.
FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned, bool IsSaturated, bool HasUnsignedPadding)
bool isValidLegacySema() const
Check if the Semantic follow the requirements of an older more limited version of this class.
static FixedPointSemantics GetIntegerSemantics(unsigned Width, bool IsSigned)
Return the FixedPointSemantics for an integer type.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
LLVM Value Representation.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
To bit_cast(const From &from) noexcept
Used to differentiate between constructors with Width and Lsb from the default Width and scale.