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