11a995a0aSBevin Hansson //===- APFixedPoint.cpp - Fixed point constant handling ---------*- C++ -*-===//
21a995a0aSBevin Hansson //
31a995a0aSBevin Hansson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41a995a0aSBevin Hansson // See https://llvm.org/LICENSE.txt for license information.
51a995a0aSBevin Hansson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61a995a0aSBevin Hansson //
71a995a0aSBevin Hansson //===----------------------------------------------------------------------===//
81a995a0aSBevin Hansson //
91a995a0aSBevin Hansson /// \file
101a995a0aSBevin Hansson /// Defines the implementation for the fixed point number interface.
111a995a0aSBevin Hansson //
121a995a0aSBevin Hansson //===----------------------------------------------------------------------===//
131a995a0aSBevin Hansson
141a995a0aSBevin Hansson #include "llvm/ADT/APFixedPoint.h"
15dd3014f3SBevin Hansson #include "llvm/ADT/APFloat.h"
161a995a0aSBevin Hansson
171a995a0aSBevin Hansson namespace llvm {
181a995a0aSBevin Hansson
convert(const FixedPointSemantics & DstSema,bool * Overflow) const191a995a0aSBevin Hansson APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema,
201a995a0aSBevin Hansson bool *Overflow) const {
211a995a0aSBevin Hansson APSInt NewVal = Val;
221a995a0aSBevin Hansson unsigned DstWidth = DstSema.getWidth();
231a995a0aSBevin Hansson unsigned DstScale = DstSema.getScale();
241a995a0aSBevin Hansson bool Upscaling = DstScale > getScale();
251a995a0aSBevin Hansson if (Overflow)
261a995a0aSBevin Hansson *Overflow = false;
271a995a0aSBevin Hansson
281a995a0aSBevin Hansson if (Upscaling) {
291a995a0aSBevin Hansson NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
301a995a0aSBevin Hansson NewVal <<= (DstScale - getScale());
311a995a0aSBevin Hansson } else {
321a995a0aSBevin Hansson NewVal >>= (getScale() - DstScale);
331a995a0aSBevin Hansson }
341a995a0aSBevin Hansson
351a995a0aSBevin Hansson auto Mask = APInt::getBitsSetFrom(
361a995a0aSBevin Hansson NewVal.getBitWidth(),
371a995a0aSBevin Hansson std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
381a995a0aSBevin Hansson APInt Masked(NewVal & Mask);
391a995a0aSBevin Hansson
401a995a0aSBevin Hansson // Change in the bits above the sign
411a995a0aSBevin Hansson if (!(Masked == Mask || Masked == 0)) {
421a995a0aSBevin Hansson // Found overflow in the bits above the sign
431a995a0aSBevin Hansson if (DstSema.isSaturated())
441a995a0aSBevin Hansson NewVal = NewVal.isNegative() ? Mask : ~Mask;
451a995a0aSBevin Hansson else if (Overflow)
461a995a0aSBevin Hansson *Overflow = true;
471a995a0aSBevin Hansson }
481a995a0aSBevin Hansson
491a995a0aSBevin Hansson // If the dst semantics are unsigned, but our value is signed and negative, we
501a995a0aSBevin Hansson // clamp to zero.
511a995a0aSBevin Hansson if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) {
521a995a0aSBevin Hansson // Found negative overflow for unsigned result
531a995a0aSBevin Hansson if (DstSema.isSaturated())
541a995a0aSBevin Hansson NewVal = 0;
551a995a0aSBevin Hansson else if (Overflow)
561a995a0aSBevin Hansson *Overflow = true;
571a995a0aSBevin Hansson }
581a995a0aSBevin Hansson
591a995a0aSBevin Hansson NewVal = NewVal.extOrTrunc(DstWidth);
601a995a0aSBevin Hansson NewVal.setIsSigned(DstSema.isSigned());
611a995a0aSBevin Hansson return APFixedPoint(NewVal, DstSema);
621a995a0aSBevin Hansson }
631a995a0aSBevin Hansson
compare(const APFixedPoint & Other) const641a995a0aSBevin Hansson int APFixedPoint::compare(const APFixedPoint &Other) const {
651a995a0aSBevin Hansson APSInt ThisVal = getValue();
661a995a0aSBevin Hansson APSInt OtherVal = Other.getValue();
671a995a0aSBevin Hansson bool ThisSigned = Val.isSigned();
681a995a0aSBevin Hansson bool OtherSigned = OtherVal.isSigned();
691a995a0aSBevin Hansson unsigned OtherScale = Other.getScale();
701a995a0aSBevin Hansson unsigned OtherWidth = OtherVal.getBitWidth();
711a995a0aSBevin Hansson
721a995a0aSBevin Hansson unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
731a995a0aSBevin Hansson
741a995a0aSBevin Hansson // Prevent overflow in the event the widths are the same but the scales differ
751a995a0aSBevin Hansson CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
761a995a0aSBevin Hansson : OtherScale - getScale();
771a995a0aSBevin Hansson
781a995a0aSBevin Hansson ThisVal = ThisVal.extOrTrunc(CommonWidth);
791a995a0aSBevin Hansson OtherVal = OtherVal.extOrTrunc(CommonWidth);
801a995a0aSBevin Hansson
811a995a0aSBevin Hansson unsigned CommonScale = std::max(getScale(), OtherScale);
821a995a0aSBevin Hansson ThisVal = ThisVal.shl(CommonScale - getScale());
831a995a0aSBevin Hansson OtherVal = OtherVal.shl(CommonScale - OtherScale);
841a995a0aSBevin Hansson
851a995a0aSBevin Hansson if (ThisSigned && OtherSigned) {
861a995a0aSBevin Hansson if (ThisVal.sgt(OtherVal))
871a995a0aSBevin Hansson return 1;
881a995a0aSBevin Hansson else if (ThisVal.slt(OtherVal))
891a995a0aSBevin Hansson return -1;
901a995a0aSBevin Hansson } else if (!ThisSigned && !OtherSigned) {
911a995a0aSBevin Hansson if (ThisVal.ugt(OtherVal))
921a995a0aSBevin Hansson return 1;
931a995a0aSBevin Hansson else if (ThisVal.ult(OtherVal))
941a995a0aSBevin Hansson return -1;
951a995a0aSBevin Hansson } else if (ThisSigned && !OtherSigned) {
961a995a0aSBevin Hansson if (ThisVal.isSignBitSet())
971a995a0aSBevin Hansson return -1;
981a995a0aSBevin Hansson else if (ThisVal.ugt(OtherVal))
991a995a0aSBevin Hansson return 1;
1001a995a0aSBevin Hansson else if (ThisVal.ult(OtherVal))
1011a995a0aSBevin Hansson return -1;
1021a995a0aSBevin Hansson } else {
1031a995a0aSBevin Hansson // !ThisSigned && OtherSigned
1041a995a0aSBevin Hansson if (OtherVal.isSignBitSet())
1051a995a0aSBevin Hansson return 1;
1061a995a0aSBevin Hansson else if (ThisVal.ugt(OtherVal))
1071a995a0aSBevin Hansson return 1;
1081a995a0aSBevin Hansson else if (ThisVal.ult(OtherVal))
1091a995a0aSBevin Hansson return -1;
1101a995a0aSBevin Hansson }
1111a995a0aSBevin Hansson
1121a995a0aSBevin Hansson return 0;
1131a995a0aSBevin Hansson }
1141a995a0aSBevin Hansson
getMax(const FixedPointSemantics & Sema)1151a995a0aSBevin Hansson APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
1161a995a0aSBevin Hansson bool IsUnsigned = !Sema.isSigned();
1171a995a0aSBevin Hansson auto Val = APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
1181a995a0aSBevin Hansson if (IsUnsigned && Sema.hasUnsignedPadding())
1191a995a0aSBevin Hansson Val = Val.lshr(1);
1201a995a0aSBevin Hansson return APFixedPoint(Val, Sema);
1211a995a0aSBevin Hansson }
1221a995a0aSBevin Hansson
getMin(const FixedPointSemantics & Sema)1231a995a0aSBevin Hansson APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
1241a995a0aSBevin Hansson auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
1251a995a0aSBevin Hansson return APFixedPoint(Val, Sema);
1261a995a0aSBevin Hansson }
1271a995a0aSBevin Hansson
fitsInFloatSemantics(const fltSemantics & FloatSema) const128dd3014f3SBevin Hansson bool FixedPointSemantics::fitsInFloatSemantics(
129dd3014f3SBevin Hansson const fltSemantics &FloatSema) const {
130dd3014f3SBevin Hansson // A fixed point semantic fits in a floating point semantic if the maximum
131dd3014f3SBevin Hansson // and minimum values as integers of the fixed point semantic can fit in the
132dd3014f3SBevin Hansson // floating point semantic.
133dd3014f3SBevin Hansson
134dd3014f3SBevin Hansson // If these values do not fit, then a floating point rescaling of the true
135dd3014f3SBevin Hansson // maximum/minimum value will not fit either, so the floating point semantic
136dd3014f3SBevin Hansson // cannot be used to perform such a rescaling.
137dd3014f3SBevin Hansson
138dd3014f3SBevin Hansson APSInt MaxInt = APFixedPoint::getMax(*this).getValue();
139dd3014f3SBevin Hansson APFloat F(FloatSema);
140dd3014f3SBevin Hansson APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(),
141dd3014f3SBevin Hansson APFloat::rmNearestTiesToAway);
142dd3014f3SBevin Hansson if ((Status & APFloat::opOverflow) || !isSigned())
143dd3014f3SBevin Hansson return !(Status & APFloat::opOverflow);
144dd3014f3SBevin Hansson
145dd3014f3SBevin Hansson APSInt MinInt = APFixedPoint::getMin(*this).getValue();
146dd3014f3SBevin Hansson Status = F.convertFromAPInt(MinInt, MinInt.isSigned(),
147dd3014f3SBevin Hansson APFloat::rmNearestTiesToAway);
148dd3014f3SBevin Hansson return !(Status & APFloat::opOverflow);
149dd3014f3SBevin Hansson }
150dd3014f3SBevin Hansson
getCommonSemantics(const FixedPointSemantics & Other) const1511a995a0aSBevin Hansson FixedPointSemantics FixedPointSemantics::getCommonSemantics(
1521a995a0aSBevin Hansson const FixedPointSemantics &Other) const {
1531a995a0aSBevin Hansson unsigned CommonScale = std::max(getScale(), Other.getScale());
1541a995a0aSBevin Hansson unsigned CommonWidth =
1551a995a0aSBevin Hansson std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
1561a995a0aSBevin Hansson
1571a995a0aSBevin Hansson bool ResultIsSigned = isSigned() || Other.isSigned();
1581a995a0aSBevin Hansson bool ResultIsSaturated = isSaturated() || Other.isSaturated();
1591a995a0aSBevin Hansson bool ResultHasUnsignedPadding = false;
1601a995a0aSBevin Hansson if (!ResultIsSigned) {
1611a995a0aSBevin Hansson // Both are unsigned.
1621a995a0aSBevin Hansson ResultHasUnsignedPadding = hasUnsignedPadding() &&
1631a995a0aSBevin Hansson Other.hasUnsignedPadding() && !ResultIsSaturated;
1641a995a0aSBevin Hansson }
1651a995a0aSBevin Hansson
1661a995a0aSBevin Hansson // If the result is signed, add an extra bit for the sign. Otherwise, if it is
1671a995a0aSBevin Hansson // unsigned and has unsigned padding, we only need to add the extra padding
1681a995a0aSBevin Hansson // bit back if we are not saturating.
1691a995a0aSBevin Hansson if (ResultIsSigned || ResultHasUnsignedPadding)
1701a995a0aSBevin Hansson CommonWidth++;
1711a995a0aSBevin Hansson
1721a995a0aSBevin Hansson return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
1731a995a0aSBevin Hansson ResultIsSaturated, ResultHasUnsignedPadding);
1741a995a0aSBevin Hansson }
1751a995a0aSBevin Hansson
add(const APFixedPoint & Other,bool * Overflow) const1761a995a0aSBevin Hansson APFixedPoint APFixedPoint::add(const APFixedPoint &Other,
1771a995a0aSBevin Hansson bool *Overflow) const {
1781a995a0aSBevin Hansson auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
1791a995a0aSBevin Hansson APFixedPoint ConvertedThis = convert(CommonFXSema);
1801a995a0aSBevin Hansson APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
1811a995a0aSBevin Hansson APSInt ThisVal = ConvertedThis.getValue();
1821a995a0aSBevin Hansson APSInt OtherVal = ConvertedOther.getValue();
1831a995a0aSBevin Hansson bool Overflowed = false;
1841a995a0aSBevin Hansson
1851a995a0aSBevin Hansson APSInt Result;
1861a995a0aSBevin Hansson if (CommonFXSema.isSaturated()) {
1871a995a0aSBevin Hansson Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal)
1881a995a0aSBevin Hansson : ThisVal.uadd_sat(OtherVal);
1891a995a0aSBevin Hansson } else {
1901a995a0aSBevin Hansson Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed)
1911a995a0aSBevin Hansson : ThisVal.uadd_ov(OtherVal, Overflowed);
1921a995a0aSBevin Hansson }
1931a995a0aSBevin Hansson
1941a995a0aSBevin Hansson if (Overflow)
1951a995a0aSBevin Hansson *Overflow = Overflowed;
1961a995a0aSBevin Hansson
1971a995a0aSBevin Hansson return APFixedPoint(Result, CommonFXSema);
1981a995a0aSBevin Hansson }
1991a995a0aSBevin Hansson
sub(const APFixedPoint & Other,bool * Overflow) const2001a995a0aSBevin Hansson APFixedPoint APFixedPoint::sub(const APFixedPoint &Other,
2011a995a0aSBevin Hansson bool *Overflow) const {
2021a995a0aSBevin Hansson auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
2031a995a0aSBevin Hansson APFixedPoint ConvertedThis = convert(CommonFXSema);
2041a995a0aSBevin Hansson APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
2051a995a0aSBevin Hansson APSInt ThisVal = ConvertedThis.getValue();
2061a995a0aSBevin Hansson APSInt OtherVal = ConvertedOther.getValue();
2071a995a0aSBevin Hansson bool Overflowed = false;
2081a995a0aSBevin Hansson
2091a995a0aSBevin Hansson APSInt Result;
2101a995a0aSBevin Hansson if (CommonFXSema.isSaturated()) {
2111a995a0aSBevin Hansson Result = CommonFXSema.isSigned() ? ThisVal.ssub_sat(OtherVal)
2121a995a0aSBevin Hansson : ThisVal.usub_sat(OtherVal);
2131a995a0aSBevin Hansson } else {
2141a995a0aSBevin Hansson Result = ThisVal.isSigned() ? ThisVal.ssub_ov(OtherVal, Overflowed)
2151a995a0aSBevin Hansson : ThisVal.usub_ov(OtherVal, Overflowed);
2161a995a0aSBevin Hansson }
2171a995a0aSBevin Hansson
2181a995a0aSBevin Hansson if (Overflow)
2191a995a0aSBevin Hansson *Overflow = Overflowed;
2201a995a0aSBevin Hansson
2211a995a0aSBevin Hansson return APFixedPoint(Result, CommonFXSema);
2221a995a0aSBevin Hansson }
2231a995a0aSBevin Hansson
mul(const APFixedPoint & Other,bool * Overflow) const2241a995a0aSBevin Hansson APFixedPoint APFixedPoint::mul(const APFixedPoint &Other,
2251a995a0aSBevin Hansson bool *Overflow) const {
2261a995a0aSBevin Hansson auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
2271a995a0aSBevin Hansson APFixedPoint ConvertedThis = convert(CommonFXSema);
2281a995a0aSBevin Hansson APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
2291a995a0aSBevin Hansson APSInt ThisVal = ConvertedThis.getValue();
2301a995a0aSBevin Hansson APSInt OtherVal = ConvertedOther.getValue();
2311a995a0aSBevin Hansson bool Overflowed = false;
2321a995a0aSBevin Hansson
2331a995a0aSBevin Hansson // Widen the LHS and RHS so we can perform a full multiplication.
2341a995a0aSBevin Hansson unsigned Wide = CommonFXSema.getWidth() * 2;
2351a995a0aSBevin Hansson if (CommonFXSema.isSigned()) {
236*6bec3e93SJay Foad ThisVal = ThisVal.sext(Wide);
237*6bec3e93SJay Foad OtherVal = OtherVal.sext(Wide);
2381a995a0aSBevin Hansson } else {
239*6bec3e93SJay Foad ThisVal = ThisVal.zext(Wide);
240*6bec3e93SJay Foad OtherVal = OtherVal.zext(Wide);
2411a995a0aSBevin Hansson }
2421a995a0aSBevin Hansson
2431a995a0aSBevin Hansson // Perform the full multiplication and downscale to get the same scale.
2441a995a0aSBevin Hansson //
2451a995a0aSBevin Hansson // Note that the right shifts here perform an implicit downwards rounding.
2461a995a0aSBevin Hansson // This rounding could discard bits that would technically place the result
2471a995a0aSBevin Hansson // outside the representable range. We interpret the spec as allowing us to
2481a995a0aSBevin Hansson // perform the rounding step first, avoiding the overflow case that would
2491a995a0aSBevin Hansson // arise.
2501a995a0aSBevin Hansson APSInt Result;
2511a995a0aSBevin Hansson if (CommonFXSema.isSigned())
2521a995a0aSBevin Hansson Result = ThisVal.smul_ov(OtherVal, Overflowed)
2531a995a0aSBevin Hansson .ashr(CommonFXSema.getScale());
2541a995a0aSBevin Hansson else
2551a995a0aSBevin Hansson Result = ThisVal.umul_ov(OtherVal, Overflowed)
2561a995a0aSBevin Hansson .lshr(CommonFXSema.getScale());
2571a995a0aSBevin Hansson assert(!Overflowed && "Full multiplication cannot overflow!");
2581a995a0aSBevin Hansson Result.setIsSigned(CommonFXSema.isSigned());
2591a995a0aSBevin Hansson
2601a995a0aSBevin Hansson // If our result lies outside of the representative range of the common
2611a995a0aSBevin Hansson // semantic, we either have overflow or saturation.
2621a995a0aSBevin Hansson APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
2631a995a0aSBevin Hansson .extOrTrunc(Wide);
2641a995a0aSBevin Hansson APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
2651a995a0aSBevin Hansson .extOrTrunc(Wide);
2661a995a0aSBevin Hansson if (CommonFXSema.isSaturated()) {
2671a995a0aSBevin Hansson if (Result < Min)
2681a995a0aSBevin Hansson Result = Min;
2691a995a0aSBevin Hansson else if (Result > Max)
2701a995a0aSBevin Hansson Result = Max;
2711a995a0aSBevin Hansson } else
2721a995a0aSBevin Hansson Overflowed = Result < Min || Result > Max;
2731a995a0aSBevin Hansson
2741a995a0aSBevin Hansson if (Overflow)
2751a995a0aSBevin Hansson *Overflow = Overflowed;
2761a995a0aSBevin Hansson
2771a995a0aSBevin Hansson return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
2781a995a0aSBevin Hansson CommonFXSema);
2791a995a0aSBevin Hansson }
2801a995a0aSBevin Hansson
div(const APFixedPoint & Other,bool * Overflow) const2811a995a0aSBevin Hansson APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
2821a995a0aSBevin Hansson bool *Overflow) const {
2831a995a0aSBevin Hansson auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
2841a995a0aSBevin Hansson APFixedPoint ConvertedThis = convert(CommonFXSema);
2851a995a0aSBevin Hansson APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
2861a995a0aSBevin Hansson APSInt ThisVal = ConvertedThis.getValue();
2871a995a0aSBevin Hansson APSInt OtherVal = ConvertedOther.getValue();
2881a995a0aSBevin Hansson bool Overflowed = false;
2891a995a0aSBevin Hansson
2901a995a0aSBevin Hansson // Widen the LHS and RHS so we can perform a full division.
2911a995a0aSBevin Hansson unsigned Wide = CommonFXSema.getWidth() * 2;
2921a995a0aSBevin Hansson if (CommonFXSema.isSigned()) {
293*6bec3e93SJay Foad ThisVal = ThisVal.sext(Wide);
294*6bec3e93SJay Foad OtherVal = OtherVal.sext(Wide);
2951a995a0aSBevin Hansson } else {
296*6bec3e93SJay Foad ThisVal = ThisVal.zext(Wide);
297*6bec3e93SJay Foad OtherVal = OtherVal.zext(Wide);
2981a995a0aSBevin Hansson }
2991a995a0aSBevin Hansson
3001a995a0aSBevin Hansson // Upscale to compensate for the loss of precision from division, and
3011a995a0aSBevin Hansson // perform the full division.
3021a995a0aSBevin Hansson ThisVal = ThisVal.shl(CommonFXSema.getScale());
3031a995a0aSBevin Hansson APSInt Result;
3041a995a0aSBevin Hansson if (CommonFXSema.isSigned()) {
3051a995a0aSBevin Hansson APInt Rem;
3061a995a0aSBevin Hansson APInt::sdivrem(ThisVal, OtherVal, Result, Rem);
3071a995a0aSBevin Hansson // If the quotient is negative and the remainder is nonzero, round
3081a995a0aSBevin Hansson // towards negative infinity by subtracting epsilon from the result.
309a9bceb2bSJay Foad if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero())
3101a995a0aSBevin Hansson Result = Result - 1;
3111a995a0aSBevin Hansson } else
3121a995a0aSBevin Hansson Result = ThisVal.udiv(OtherVal);
3131a995a0aSBevin Hansson Result.setIsSigned(CommonFXSema.isSigned());
3141a995a0aSBevin Hansson
3151a995a0aSBevin Hansson // If our result lies outside of the representative range of the common
3161a995a0aSBevin Hansson // semantic, we either have overflow or saturation.
3171a995a0aSBevin Hansson APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
3181a995a0aSBevin Hansson .extOrTrunc(Wide);
3191a995a0aSBevin Hansson APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
3201a995a0aSBevin Hansson .extOrTrunc(Wide);
3211a995a0aSBevin Hansson if (CommonFXSema.isSaturated()) {
3221a995a0aSBevin Hansson if (Result < Min)
3231a995a0aSBevin Hansson Result = Min;
3241a995a0aSBevin Hansson else if (Result > Max)
3251a995a0aSBevin Hansson Result = Max;
3261a995a0aSBevin Hansson } else
3271a995a0aSBevin Hansson Overflowed = Result < Min || Result > Max;
3281a995a0aSBevin Hansson
3291a995a0aSBevin Hansson if (Overflow)
3301a995a0aSBevin Hansson *Overflow = Overflowed;
3311a995a0aSBevin Hansson
3321a995a0aSBevin Hansson return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
3331a995a0aSBevin Hansson CommonFXSema);
3341a995a0aSBevin Hansson }
3351a995a0aSBevin Hansson
shl(unsigned Amt,bool * Overflow) const3361a995a0aSBevin Hansson APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const {
3371a995a0aSBevin Hansson APSInt ThisVal = Val;
3381a995a0aSBevin Hansson bool Overflowed = false;
3391a995a0aSBevin Hansson
3401a995a0aSBevin Hansson // Widen the LHS.
3411a995a0aSBevin Hansson unsigned Wide = Sema.getWidth() * 2;
3421a995a0aSBevin Hansson if (Sema.isSigned())
343*6bec3e93SJay Foad ThisVal = ThisVal.sext(Wide);
3441a995a0aSBevin Hansson else
345*6bec3e93SJay Foad ThisVal = ThisVal.zext(Wide);
3461a995a0aSBevin Hansson
3471a995a0aSBevin Hansson // Clamp the shift amount at the original width, and perform the shift.
3481a995a0aSBevin Hansson Amt = std::min(Amt, ThisVal.getBitWidth());
3491a995a0aSBevin Hansson APSInt Result = ThisVal << Amt;
3501a995a0aSBevin Hansson Result.setIsSigned(Sema.isSigned());
3511a995a0aSBevin Hansson
3521a995a0aSBevin Hansson // If our result lies outside of the representative range of the
3531a995a0aSBevin Hansson // semantic, we either have overflow or saturation.
3541a995a0aSBevin Hansson APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide);
3551a995a0aSBevin Hansson APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide);
3561a995a0aSBevin Hansson if (Sema.isSaturated()) {
3571a995a0aSBevin Hansson if (Result < Min)
3581a995a0aSBevin Hansson Result = Min;
3591a995a0aSBevin Hansson else if (Result > Max)
3601a995a0aSBevin Hansson Result = Max;
3611a995a0aSBevin Hansson } else
3621a995a0aSBevin Hansson Overflowed = Result < Min || Result > Max;
3631a995a0aSBevin Hansson
3641a995a0aSBevin Hansson if (Overflow)
3651a995a0aSBevin Hansson *Overflow = Overflowed;
3661a995a0aSBevin Hansson
3671a995a0aSBevin Hansson return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema);
3681a995a0aSBevin Hansson }
3691a995a0aSBevin Hansson
toString(SmallVectorImpl<char> & Str) const3701a995a0aSBevin Hansson void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
3711a995a0aSBevin Hansson APSInt Val = getValue();
3721a995a0aSBevin Hansson unsigned Scale = getScale();
3731a995a0aSBevin Hansson
3741a995a0aSBevin Hansson if (Val.isSigned() && Val.isNegative() && Val != -Val) {
3751a995a0aSBevin Hansson Val = -Val;
3761a995a0aSBevin Hansson Str.push_back('-');
3771a995a0aSBevin Hansson }
3781a995a0aSBevin Hansson
3791a995a0aSBevin Hansson APSInt IntPart = Val >> Scale;
3801a995a0aSBevin Hansson
3811a995a0aSBevin Hansson // Add 4 digits to hold the value after multiplying 10 (the radix)
3821a995a0aSBevin Hansson unsigned Width = Val.getBitWidth() + 4;
3831a995a0aSBevin Hansson APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
384735f4671SChris Lattner APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width);
3851a995a0aSBevin Hansson APInt RadixInt = APInt(Width, 10);
3861a995a0aSBevin Hansson
3871a995a0aSBevin Hansson IntPart.toString(Str, /*Radix=*/10);
3881a995a0aSBevin Hansson Str.push_back('.');
3891a995a0aSBevin Hansson do {
3901a995a0aSBevin Hansson (FractPart * RadixInt)
3911a995a0aSBevin Hansson .lshr(Scale)
3921a995a0aSBevin Hansson .toString(Str, /*Radix=*/10, Val.isSigned());
3931a995a0aSBevin Hansson FractPart = (FractPart * RadixInt) & FractPartMask;
3941a995a0aSBevin Hansson } while (FractPart != 0);
3951a995a0aSBevin Hansson }
3961a995a0aSBevin Hansson
negate(bool * Overflow) const3971a995a0aSBevin Hansson APFixedPoint APFixedPoint::negate(bool *Overflow) const {
3981a995a0aSBevin Hansson if (!isSaturated()) {
3991a995a0aSBevin Hansson if (Overflow)
4001a995a0aSBevin Hansson *Overflow =
4011a995a0aSBevin Hansson (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue());
4021a995a0aSBevin Hansson return APFixedPoint(-Val, Sema);
4031a995a0aSBevin Hansson }
4041a995a0aSBevin Hansson
4051a995a0aSBevin Hansson // We never overflow for saturation
4061a995a0aSBevin Hansson if (Overflow)
4071a995a0aSBevin Hansson *Overflow = false;
4081a995a0aSBevin Hansson
4091a995a0aSBevin Hansson if (isSigned())
4101a995a0aSBevin Hansson return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
4111a995a0aSBevin Hansson else
4121a995a0aSBevin Hansson return APFixedPoint(Sema);
4131a995a0aSBevin Hansson }
4141a995a0aSBevin Hansson
convertToInt(unsigned DstWidth,bool DstSign,bool * Overflow) const4151a995a0aSBevin Hansson APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
4161a995a0aSBevin Hansson bool *Overflow) const {
4171a995a0aSBevin Hansson APSInt Result = getIntPart();
4181a995a0aSBevin Hansson unsigned SrcWidth = getWidth();
4191a995a0aSBevin Hansson
4201a995a0aSBevin Hansson APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign);
4211a995a0aSBevin Hansson APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign);
4221a995a0aSBevin Hansson
4231a995a0aSBevin Hansson if (SrcWidth < DstWidth) {
4241a995a0aSBevin Hansson Result = Result.extend(DstWidth);
4251a995a0aSBevin Hansson } else if (SrcWidth > DstWidth) {
4261a995a0aSBevin Hansson DstMin = DstMin.extend(SrcWidth);
4271a995a0aSBevin Hansson DstMax = DstMax.extend(SrcWidth);
4281a995a0aSBevin Hansson }
4291a995a0aSBevin Hansson
4301a995a0aSBevin Hansson if (Overflow) {
4311a995a0aSBevin Hansson if (Result.isSigned() && !DstSign) {
4321a995a0aSBevin Hansson *Overflow = Result.isNegative() || Result.ugt(DstMax);
4331a995a0aSBevin Hansson } else if (Result.isUnsigned() && DstSign) {
4341a995a0aSBevin Hansson *Overflow = Result.ugt(DstMax);
4351a995a0aSBevin Hansson } else {
4361a995a0aSBevin Hansson *Overflow = Result < DstMin || Result > DstMax;
4371a995a0aSBevin Hansson }
4381a995a0aSBevin Hansson }
4391a995a0aSBevin Hansson
4401a995a0aSBevin Hansson Result.setIsSigned(DstSign);
4411a995a0aSBevin Hansson return Result.extOrTrunc(DstWidth);
4421a995a0aSBevin Hansson }
4431a995a0aSBevin Hansson
promoteFloatSemantics(const fltSemantics * S)444dd3014f3SBevin Hansson const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) {
445dd3014f3SBevin Hansson if (S == &APFloat::BFloat())
446dd3014f3SBevin Hansson return &APFloat::IEEEdouble();
447dd3014f3SBevin Hansson else if (S == &APFloat::IEEEhalf())
448dd3014f3SBevin Hansson return &APFloat::IEEEsingle();
449dd3014f3SBevin Hansson else if (S == &APFloat::IEEEsingle())
450dd3014f3SBevin Hansson return &APFloat::IEEEdouble();
451dd3014f3SBevin Hansson else if (S == &APFloat::IEEEdouble())
452dd3014f3SBevin Hansson return &APFloat::IEEEquad();
453dd3014f3SBevin Hansson llvm_unreachable("Could not promote float type!");
454dd3014f3SBevin Hansson }
455dd3014f3SBevin Hansson
convertToFloat(const fltSemantics & FloatSema) const456dd3014f3SBevin Hansson APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {
457dd3014f3SBevin Hansson // For some operations, rounding mode has an effect on the result, while
458dd3014f3SBevin Hansson // other operations are lossless and should never result in rounding.
459dd3014f3SBevin Hansson // To signify which these operations are, we define two rounding modes here.
460dd3014f3SBevin Hansson APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
461dd3014f3SBevin Hansson APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
462dd3014f3SBevin Hansson
463dd3014f3SBevin Hansson // Make sure that we are operating in a type that works with this fixed-point
464dd3014f3SBevin Hansson // semantic.
465dd3014f3SBevin Hansson const fltSemantics *OpSema = &FloatSema;
466dd3014f3SBevin Hansson while (!Sema.fitsInFloatSemantics(*OpSema))
467dd3014f3SBevin Hansson OpSema = promoteFloatSemantics(OpSema);
468dd3014f3SBevin Hansson
469dd3014f3SBevin Hansson // Convert the fixed point value bits as an integer. If the floating point
470dd3014f3SBevin Hansson // value does not have the required precision, we will round according to the
471dd3014f3SBevin Hansson // given mode.
472dd3014f3SBevin Hansson APFloat Flt(*OpSema);
473dd3014f3SBevin Hansson APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM);
474dd3014f3SBevin Hansson
475dd3014f3SBevin Hansson // If we cared about checking for precision loss, we could look at this
476dd3014f3SBevin Hansson // status.
477dd3014f3SBevin Hansson (void)S;
478dd3014f3SBevin Hansson
479dd3014f3SBevin Hansson // Scale down the integer value in the float to match the correct scaling
480dd3014f3SBevin Hansson // factor.
481dd3014f3SBevin Hansson APFloat ScaleFactor(std::pow(2, -(int)Sema.getScale()));
482dd3014f3SBevin Hansson bool Ignored;
483dd3014f3SBevin Hansson ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
484dd3014f3SBevin Hansson Flt.multiply(ScaleFactor, LosslessRM);
485dd3014f3SBevin Hansson
486dd3014f3SBevin Hansson if (OpSema != &FloatSema)
487dd3014f3SBevin Hansson Flt.convert(FloatSema, RM, &Ignored);
488dd3014f3SBevin Hansson
489dd3014f3SBevin Hansson return Flt;
490dd3014f3SBevin Hansson }
491dd3014f3SBevin Hansson
getFromIntValue(const APSInt & Value,const FixedPointSemantics & DstFXSema,bool * Overflow)4921a995a0aSBevin Hansson APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
4931a995a0aSBevin Hansson const FixedPointSemantics &DstFXSema,
4941a995a0aSBevin Hansson bool *Overflow) {
4951a995a0aSBevin Hansson FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
4961a995a0aSBevin Hansson Value.getBitWidth(), Value.isSigned());
4971a995a0aSBevin Hansson return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
4981a995a0aSBevin Hansson }
4991a995a0aSBevin Hansson
500dd3014f3SBevin Hansson APFixedPoint
getFromFloatValue(const APFloat & Value,const FixedPointSemantics & DstFXSema,bool * Overflow)501dd3014f3SBevin Hansson APFixedPoint::getFromFloatValue(const APFloat &Value,
502dd3014f3SBevin Hansson const FixedPointSemantics &DstFXSema,
503dd3014f3SBevin Hansson bool *Overflow) {
504dd3014f3SBevin Hansson // For some operations, rounding mode has an effect on the result, while
505dd3014f3SBevin Hansson // other operations are lossless and should never result in rounding.
506dd3014f3SBevin Hansson // To signify which these operations are, we define two rounding modes here,
507dd3014f3SBevin Hansson // even though they are the same mode.
508dd3014f3SBevin Hansson APFloat::roundingMode RM = APFloat::rmTowardZero;
509dd3014f3SBevin Hansson APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
510dd3014f3SBevin Hansson
511dd3014f3SBevin Hansson const fltSemantics &FloatSema = Value.getSemantics();
512dd3014f3SBevin Hansson
513dd3014f3SBevin Hansson if (Value.isNaN()) {
514dd3014f3SBevin Hansson // Handle NaN immediately.
515dd3014f3SBevin Hansson if (Overflow)
516dd3014f3SBevin Hansson *Overflow = true;
517dd3014f3SBevin Hansson return APFixedPoint(DstFXSema);
518dd3014f3SBevin Hansson }
519dd3014f3SBevin Hansson
520dd3014f3SBevin Hansson // Make sure that we are operating in a type that works with this fixed-point
521dd3014f3SBevin Hansson // semantic.
522dd3014f3SBevin Hansson const fltSemantics *OpSema = &FloatSema;
523dd3014f3SBevin Hansson while (!DstFXSema.fitsInFloatSemantics(*OpSema))
524dd3014f3SBevin Hansson OpSema = promoteFloatSemantics(OpSema);
525dd3014f3SBevin Hansson
526dd3014f3SBevin Hansson APFloat Val = Value;
527dd3014f3SBevin Hansson
528dd3014f3SBevin Hansson bool Ignored;
529dd3014f3SBevin Hansson if (&FloatSema != OpSema)
530dd3014f3SBevin Hansson Val.convert(*OpSema, LosslessRM, &Ignored);
531dd3014f3SBevin Hansson
532dd3014f3SBevin Hansson // Scale up the float so that the 'fractional' part of the mantissa ends up in
533dd3014f3SBevin Hansson // the integer range instead. Rounding mode is irrelevant here.
534dd3014f3SBevin Hansson // It is fine if this overflows to infinity even for saturating types,
535dd3014f3SBevin Hansson // since we will use floating point comparisons to check for saturation.
536dd3014f3SBevin Hansson APFloat ScaleFactor(std::pow(2, DstFXSema.getScale()));
537dd3014f3SBevin Hansson ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
538dd3014f3SBevin Hansson Val.multiply(ScaleFactor, LosslessRM);
539dd3014f3SBevin Hansson
540dd3014f3SBevin Hansson // Convert to the integral representation of the value. This rounding mode
541dd3014f3SBevin Hansson // is significant.
542dd3014f3SBevin Hansson APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned());
543dd3014f3SBevin Hansson Val.convertToInteger(Res, RM, &Ignored);
544dd3014f3SBevin Hansson
545dd3014f3SBevin Hansson // Round the integral value and scale back. This makes the
546dd3014f3SBevin Hansson // overflow calculations below work properly. If we do not round here,
547dd3014f3SBevin Hansson // we risk checking for overflow with a value that is outside the
548dd3014f3SBevin Hansson // representable range of the fixed-point semantic even though no overflow
549dd3014f3SBevin Hansson // would occur had we rounded first.
550dd3014f3SBevin Hansson ScaleFactor = APFloat(std::pow(2, -(int)DstFXSema.getScale()));
551dd3014f3SBevin Hansson ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
552dd3014f3SBevin Hansson Val.roundToIntegral(RM);
553dd3014f3SBevin Hansson Val.multiply(ScaleFactor, LosslessRM);
554dd3014f3SBevin Hansson
555dd3014f3SBevin Hansson // Check for overflow/saturation by checking if the floating point value
556dd3014f3SBevin Hansson // is outside the range representable by the fixed-point value.
557dd3014f3SBevin Hansson APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema);
558dd3014f3SBevin Hansson APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema);
559dd3014f3SBevin Hansson bool Overflowed = false;
560dd3014f3SBevin Hansson if (DstFXSema.isSaturated()) {
561dd3014f3SBevin Hansson if (Val > FloatMax)
562dd3014f3SBevin Hansson Res = getMax(DstFXSema).getValue();
563dd3014f3SBevin Hansson else if (Val < FloatMin)
564dd3014f3SBevin Hansson Res = getMin(DstFXSema).getValue();
565dd3014f3SBevin Hansson } else
566dd3014f3SBevin Hansson Overflowed = Val > FloatMax || Val < FloatMin;
567dd3014f3SBevin Hansson
568dd3014f3SBevin Hansson if (Overflow)
569dd3014f3SBevin Hansson *Overflow = Overflowed;
570dd3014f3SBevin Hansson
571dd3014f3SBevin Hansson return APFixedPoint(Res, DstFXSema);
572dd3014f3SBevin Hansson }
573dd3014f3SBevin Hansson
574dd3014f3SBevin Hansson } // namespace llvm
575