1*af732203SDimitry Andric //===- APFixedPoint.cpp - Fixed point constant handling ---------*- C++ -*-===//
2*af732203SDimitry Andric //
3*af732203SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*af732203SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*af732203SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*af732203SDimitry Andric //
7*af732203SDimitry Andric //===----------------------------------------------------------------------===//
8*af732203SDimitry Andric //
9*af732203SDimitry Andric /// \file
10*af732203SDimitry Andric /// Defines the implementation for the fixed point number interface.
11*af732203SDimitry Andric //
12*af732203SDimitry Andric //===----------------------------------------------------------------------===//
13*af732203SDimitry Andric 
14*af732203SDimitry Andric #include "llvm/ADT/APFixedPoint.h"
15*af732203SDimitry Andric #include "llvm/ADT/APFloat.h"
16*af732203SDimitry Andric 
17*af732203SDimitry Andric namespace llvm {
18*af732203SDimitry Andric 
convert(const FixedPointSemantics & DstSema,bool * Overflow) const19*af732203SDimitry Andric APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema,
20*af732203SDimitry Andric                                    bool *Overflow) const {
21*af732203SDimitry Andric   APSInt NewVal = Val;
22*af732203SDimitry Andric   unsigned DstWidth = DstSema.getWidth();
23*af732203SDimitry Andric   unsigned DstScale = DstSema.getScale();
24*af732203SDimitry Andric   bool Upscaling = DstScale > getScale();
25*af732203SDimitry Andric   if (Overflow)
26*af732203SDimitry Andric     *Overflow = false;
27*af732203SDimitry Andric 
28*af732203SDimitry Andric   if (Upscaling) {
29*af732203SDimitry Andric     NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
30*af732203SDimitry Andric     NewVal <<= (DstScale - getScale());
31*af732203SDimitry Andric   } else {
32*af732203SDimitry Andric     NewVal >>= (getScale() - DstScale);
33*af732203SDimitry Andric   }
34*af732203SDimitry Andric 
35*af732203SDimitry Andric   auto Mask = APInt::getBitsSetFrom(
36*af732203SDimitry Andric       NewVal.getBitWidth(),
37*af732203SDimitry Andric       std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
38*af732203SDimitry Andric   APInt Masked(NewVal & Mask);
39*af732203SDimitry Andric 
40*af732203SDimitry Andric   // Change in the bits above the sign
41*af732203SDimitry Andric   if (!(Masked == Mask || Masked == 0)) {
42*af732203SDimitry Andric     // Found overflow in the bits above the sign
43*af732203SDimitry Andric     if (DstSema.isSaturated())
44*af732203SDimitry Andric       NewVal = NewVal.isNegative() ? Mask : ~Mask;
45*af732203SDimitry Andric     else if (Overflow)
46*af732203SDimitry Andric       *Overflow = true;
47*af732203SDimitry Andric   }
48*af732203SDimitry Andric 
49*af732203SDimitry Andric   // If the dst semantics are unsigned, but our value is signed and negative, we
50*af732203SDimitry Andric   // clamp to zero.
51*af732203SDimitry Andric   if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) {
52*af732203SDimitry Andric     // Found negative overflow for unsigned result
53*af732203SDimitry Andric     if (DstSema.isSaturated())
54*af732203SDimitry Andric       NewVal = 0;
55*af732203SDimitry Andric     else if (Overflow)
56*af732203SDimitry Andric       *Overflow = true;
57*af732203SDimitry Andric   }
58*af732203SDimitry Andric 
59*af732203SDimitry Andric   NewVal = NewVal.extOrTrunc(DstWidth);
60*af732203SDimitry Andric   NewVal.setIsSigned(DstSema.isSigned());
61*af732203SDimitry Andric   return APFixedPoint(NewVal, DstSema);
62*af732203SDimitry Andric }
63*af732203SDimitry Andric 
compare(const APFixedPoint & Other) const64*af732203SDimitry Andric int APFixedPoint::compare(const APFixedPoint &Other) const {
65*af732203SDimitry Andric   APSInt ThisVal = getValue();
66*af732203SDimitry Andric   APSInt OtherVal = Other.getValue();
67*af732203SDimitry Andric   bool ThisSigned = Val.isSigned();
68*af732203SDimitry Andric   bool OtherSigned = OtherVal.isSigned();
69*af732203SDimitry Andric   unsigned OtherScale = Other.getScale();
70*af732203SDimitry Andric   unsigned OtherWidth = OtherVal.getBitWidth();
71*af732203SDimitry Andric 
72*af732203SDimitry Andric   unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
73*af732203SDimitry Andric 
74*af732203SDimitry Andric   // Prevent overflow in the event the widths are the same but the scales differ
75*af732203SDimitry Andric   CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
76*af732203SDimitry Andric                                           : OtherScale - getScale();
77*af732203SDimitry Andric 
78*af732203SDimitry Andric   ThisVal = ThisVal.extOrTrunc(CommonWidth);
79*af732203SDimitry Andric   OtherVal = OtherVal.extOrTrunc(CommonWidth);
80*af732203SDimitry Andric 
81*af732203SDimitry Andric   unsigned CommonScale = std::max(getScale(), OtherScale);
82*af732203SDimitry Andric   ThisVal = ThisVal.shl(CommonScale - getScale());
83*af732203SDimitry Andric   OtherVal = OtherVal.shl(CommonScale - OtherScale);
84*af732203SDimitry Andric 
85*af732203SDimitry Andric   if (ThisSigned && OtherSigned) {
86*af732203SDimitry Andric     if (ThisVal.sgt(OtherVal))
87*af732203SDimitry Andric       return 1;
88*af732203SDimitry Andric     else if (ThisVal.slt(OtherVal))
89*af732203SDimitry Andric       return -1;
90*af732203SDimitry Andric   } else if (!ThisSigned && !OtherSigned) {
91*af732203SDimitry Andric     if (ThisVal.ugt(OtherVal))
92*af732203SDimitry Andric       return 1;
93*af732203SDimitry Andric     else if (ThisVal.ult(OtherVal))
94*af732203SDimitry Andric       return -1;
95*af732203SDimitry Andric   } else if (ThisSigned && !OtherSigned) {
96*af732203SDimitry Andric     if (ThisVal.isSignBitSet())
97*af732203SDimitry Andric       return -1;
98*af732203SDimitry Andric     else if (ThisVal.ugt(OtherVal))
99*af732203SDimitry Andric       return 1;
100*af732203SDimitry Andric     else if (ThisVal.ult(OtherVal))
101*af732203SDimitry Andric       return -1;
102*af732203SDimitry Andric   } else {
103*af732203SDimitry Andric     // !ThisSigned && OtherSigned
104*af732203SDimitry Andric     if (OtherVal.isSignBitSet())
105*af732203SDimitry Andric       return 1;
106*af732203SDimitry Andric     else if (ThisVal.ugt(OtherVal))
107*af732203SDimitry Andric       return 1;
108*af732203SDimitry Andric     else if (ThisVal.ult(OtherVal))
109*af732203SDimitry Andric       return -1;
110*af732203SDimitry Andric   }
111*af732203SDimitry Andric 
112*af732203SDimitry Andric   return 0;
113*af732203SDimitry Andric }
114*af732203SDimitry Andric 
getMax(const FixedPointSemantics & Sema)115*af732203SDimitry Andric APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
116*af732203SDimitry Andric   bool IsUnsigned = !Sema.isSigned();
117*af732203SDimitry Andric   auto Val = APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
118*af732203SDimitry Andric   if (IsUnsigned && Sema.hasUnsignedPadding())
119*af732203SDimitry Andric     Val = Val.lshr(1);
120*af732203SDimitry Andric   return APFixedPoint(Val, Sema);
121*af732203SDimitry Andric }
122*af732203SDimitry Andric 
getMin(const FixedPointSemantics & Sema)123*af732203SDimitry Andric APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
124*af732203SDimitry Andric   auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
125*af732203SDimitry Andric   return APFixedPoint(Val, Sema);
126*af732203SDimitry Andric }
127*af732203SDimitry Andric 
fitsInFloatSemantics(const fltSemantics & FloatSema) const128*af732203SDimitry Andric bool FixedPointSemantics::fitsInFloatSemantics(
129*af732203SDimitry Andric     const fltSemantics &FloatSema) const {
130*af732203SDimitry Andric   // A fixed point semantic fits in a floating point semantic if the maximum
131*af732203SDimitry Andric   // and minimum values as integers of the fixed point semantic can fit in the
132*af732203SDimitry Andric   // floating point semantic.
133*af732203SDimitry Andric 
134*af732203SDimitry Andric   // If these values do not fit, then a floating point rescaling of the true
135*af732203SDimitry Andric   // maximum/minimum value will not fit either, so the floating point semantic
136*af732203SDimitry Andric   // cannot be used to perform such a rescaling.
137*af732203SDimitry Andric 
138*af732203SDimitry Andric   APSInt MaxInt = APFixedPoint::getMax(*this).getValue();
139*af732203SDimitry Andric   APFloat F(FloatSema);
140*af732203SDimitry Andric   APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(),
141*af732203SDimitry Andric                                                 APFloat::rmNearestTiesToAway);
142*af732203SDimitry Andric   if ((Status & APFloat::opOverflow) || !isSigned())
143*af732203SDimitry Andric     return !(Status & APFloat::opOverflow);
144*af732203SDimitry Andric 
145*af732203SDimitry Andric   APSInt MinInt = APFixedPoint::getMin(*this).getValue();
146*af732203SDimitry Andric   Status = F.convertFromAPInt(MinInt, MinInt.isSigned(),
147*af732203SDimitry Andric                               APFloat::rmNearestTiesToAway);
148*af732203SDimitry Andric   return !(Status & APFloat::opOverflow);
149*af732203SDimitry Andric }
150*af732203SDimitry Andric 
getCommonSemantics(const FixedPointSemantics & Other) const151*af732203SDimitry Andric FixedPointSemantics FixedPointSemantics::getCommonSemantics(
152*af732203SDimitry Andric     const FixedPointSemantics &Other) const {
153*af732203SDimitry Andric   unsigned CommonScale = std::max(getScale(), Other.getScale());
154*af732203SDimitry Andric   unsigned CommonWidth =
155*af732203SDimitry Andric       std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
156*af732203SDimitry Andric 
157*af732203SDimitry Andric   bool ResultIsSigned = isSigned() || Other.isSigned();
158*af732203SDimitry Andric   bool ResultIsSaturated = isSaturated() || Other.isSaturated();
159*af732203SDimitry Andric   bool ResultHasUnsignedPadding = false;
160*af732203SDimitry Andric   if (!ResultIsSigned) {
161*af732203SDimitry Andric     // Both are unsigned.
162*af732203SDimitry Andric     ResultHasUnsignedPadding = hasUnsignedPadding() &&
163*af732203SDimitry Andric                                Other.hasUnsignedPadding() && !ResultIsSaturated;
164*af732203SDimitry Andric   }
165*af732203SDimitry Andric 
166*af732203SDimitry Andric   // If the result is signed, add an extra bit for the sign. Otherwise, if it is
167*af732203SDimitry Andric   // unsigned and has unsigned padding, we only need to add the extra padding
168*af732203SDimitry Andric   // bit back if we are not saturating.
169*af732203SDimitry Andric   if (ResultIsSigned || ResultHasUnsignedPadding)
170*af732203SDimitry Andric     CommonWidth++;
171*af732203SDimitry Andric 
172*af732203SDimitry Andric   return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
173*af732203SDimitry Andric                              ResultIsSaturated, ResultHasUnsignedPadding);
174*af732203SDimitry Andric }
175*af732203SDimitry Andric 
add(const APFixedPoint & Other,bool * Overflow) const176*af732203SDimitry Andric APFixedPoint APFixedPoint::add(const APFixedPoint &Other,
177*af732203SDimitry Andric                                bool *Overflow) const {
178*af732203SDimitry Andric   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
179*af732203SDimitry Andric   APFixedPoint ConvertedThis = convert(CommonFXSema);
180*af732203SDimitry Andric   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
181*af732203SDimitry Andric   APSInt ThisVal = ConvertedThis.getValue();
182*af732203SDimitry Andric   APSInt OtherVal = ConvertedOther.getValue();
183*af732203SDimitry Andric   bool Overflowed = false;
184*af732203SDimitry Andric 
185*af732203SDimitry Andric   APSInt Result;
186*af732203SDimitry Andric   if (CommonFXSema.isSaturated()) {
187*af732203SDimitry Andric     Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal)
188*af732203SDimitry Andric                                      : ThisVal.uadd_sat(OtherVal);
189*af732203SDimitry Andric   } else {
190*af732203SDimitry Andric     Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed)
191*af732203SDimitry Andric                                 : ThisVal.uadd_ov(OtherVal, Overflowed);
192*af732203SDimitry Andric   }
193*af732203SDimitry Andric 
194*af732203SDimitry Andric   if (Overflow)
195*af732203SDimitry Andric     *Overflow = Overflowed;
196*af732203SDimitry Andric 
197*af732203SDimitry Andric   return APFixedPoint(Result, CommonFXSema);
198*af732203SDimitry Andric }
199*af732203SDimitry Andric 
sub(const APFixedPoint & Other,bool * Overflow) const200*af732203SDimitry Andric APFixedPoint APFixedPoint::sub(const APFixedPoint &Other,
201*af732203SDimitry Andric                                bool *Overflow) const {
202*af732203SDimitry Andric   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
203*af732203SDimitry Andric   APFixedPoint ConvertedThis = convert(CommonFXSema);
204*af732203SDimitry Andric   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
205*af732203SDimitry Andric   APSInt ThisVal = ConvertedThis.getValue();
206*af732203SDimitry Andric   APSInt OtherVal = ConvertedOther.getValue();
207*af732203SDimitry Andric   bool Overflowed = false;
208*af732203SDimitry Andric 
209*af732203SDimitry Andric   APSInt Result;
210*af732203SDimitry Andric   if (CommonFXSema.isSaturated()) {
211*af732203SDimitry Andric     Result = CommonFXSema.isSigned() ? ThisVal.ssub_sat(OtherVal)
212*af732203SDimitry Andric                                      : ThisVal.usub_sat(OtherVal);
213*af732203SDimitry Andric   } else {
214*af732203SDimitry Andric     Result = ThisVal.isSigned() ? ThisVal.ssub_ov(OtherVal, Overflowed)
215*af732203SDimitry Andric                                 : ThisVal.usub_ov(OtherVal, Overflowed);
216*af732203SDimitry Andric   }
217*af732203SDimitry Andric 
218*af732203SDimitry Andric   if (Overflow)
219*af732203SDimitry Andric     *Overflow = Overflowed;
220*af732203SDimitry Andric 
221*af732203SDimitry Andric   return APFixedPoint(Result, CommonFXSema);
222*af732203SDimitry Andric }
223*af732203SDimitry Andric 
mul(const APFixedPoint & Other,bool * Overflow) const224*af732203SDimitry Andric APFixedPoint APFixedPoint::mul(const APFixedPoint &Other,
225*af732203SDimitry Andric                                bool *Overflow) const {
226*af732203SDimitry Andric   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
227*af732203SDimitry Andric   APFixedPoint ConvertedThis = convert(CommonFXSema);
228*af732203SDimitry Andric   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
229*af732203SDimitry Andric   APSInt ThisVal = ConvertedThis.getValue();
230*af732203SDimitry Andric   APSInt OtherVal = ConvertedOther.getValue();
231*af732203SDimitry Andric   bool Overflowed = false;
232*af732203SDimitry Andric 
233*af732203SDimitry Andric   // Widen the LHS and RHS so we can perform a full multiplication.
234*af732203SDimitry Andric   unsigned Wide = CommonFXSema.getWidth() * 2;
235*af732203SDimitry Andric   if (CommonFXSema.isSigned()) {
236*af732203SDimitry Andric     ThisVal = ThisVal.sextOrSelf(Wide);
237*af732203SDimitry Andric     OtherVal = OtherVal.sextOrSelf(Wide);
238*af732203SDimitry Andric   } else {
239*af732203SDimitry Andric     ThisVal = ThisVal.zextOrSelf(Wide);
240*af732203SDimitry Andric     OtherVal = OtherVal.zextOrSelf(Wide);
241*af732203SDimitry Andric   }
242*af732203SDimitry Andric 
243*af732203SDimitry Andric   // Perform the full multiplication and downscale to get the same scale.
244*af732203SDimitry Andric   //
245*af732203SDimitry Andric   // Note that the right shifts here perform an implicit downwards rounding.
246*af732203SDimitry Andric   // This rounding could discard bits that would technically place the result
247*af732203SDimitry Andric   // outside the representable range. We interpret the spec as allowing us to
248*af732203SDimitry Andric   // perform the rounding step first, avoiding the overflow case that would
249*af732203SDimitry Andric   // arise.
250*af732203SDimitry Andric   APSInt Result;
251*af732203SDimitry Andric   if (CommonFXSema.isSigned())
252*af732203SDimitry Andric     Result = ThisVal.smul_ov(OtherVal, Overflowed)
253*af732203SDimitry Andric                     .ashr(CommonFXSema.getScale());
254*af732203SDimitry Andric   else
255*af732203SDimitry Andric     Result = ThisVal.umul_ov(OtherVal, Overflowed)
256*af732203SDimitry Andric                     .lshr(CommonFXSema.getScale());
257*af732203SDimitry Andric   assert(!Overflowed && "Full multiplication cannot overflow!");
258*af732203SDimitry Andric   Result.setIsSigned(CommonFXSema.isSigned());
259*af732203SDimitry Andric 
260*af732203SDimitry Andric   // If our result lies outside of the representative range of the common
261*af732203SDimitry Andric   // semantic, we either have overflow or saturation.
262*af732203SDimitry Andric   APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
263*af732203SDimitry Andric                                                  .extOrTrunc(Wide);
264*af732203SDimitry Andric   APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
265*af732203SDimitry Andric                                                  .extOrTrunc(Wide);
266*af732203SDimitry Andric   if (CommonFXSema.isSaturated()) {
267*af732203SDimitry Andric     if (Result < Min)
268*af732203SDimitry Andric       Result = Min;
269*af732203SDimitry Andric     else if (Result > Max)
270*af732203SDimitry Andric       Result = Max;
271*af732203SDimitry Andric   } else
272*af732203SDimitry Andric     Overflowed = Result < Min || Result > Max;
273*af732203SDimitry Andric 
274*af732203SDimitry Andric   if (Overflow)
275*af732203SDimitry Andric     *Overflow = Overflowed;
276*af732203SDimitry Andric 
277*af732203SDimitry Andric   return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
278*af732203SDimitry Andric                       CommonFXSema);
279*af732203SDimitry Andric }
280*af732203SDimitry Andric 
div(const APFixedPoint & Other,bool * Overflow) const281*af732203SDimitry Andric APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
282*af732203SDimitry Andric                                bool *Overflow) const {
283*af732203SDimitry Andric   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
284*af732203SDimitry Andric   APFixedPoint ConvertedThis = convert(CommonFXSema);
285*af732203SDimitry Andric   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
286*af732203SDimitry Andric   APSInt ThisVal = ConvertedThis.getValue();
287*af732203SDimitry Andric   APSInt OtherVal = ConvertedOther.getValue();
288*af732203SDimitry Andric   bool Overflowed = false;
289*af732203SDimitry Andric 
290*af732203SDimitry Andric   // Widen the LHS and RHS so we can perform a full division.
291*af732203SDimitry Andric   unsigned Wide = CommonFXSema.getWidth() * 2;
292*af732203SDimitry Andric   if (CommonFXSema.isSigned()) {
293*af732203SDimitry Andric     ThisVal = ThisVal.sextOrSelf(Wide);
294*af732203SDimitry Andric     OtherVal = OtherVal.sextOrSelf(Wide);
295*af732203SDimitry Andric   } else {
296*af732203SDimitry Andric     ThisVal = ThisVal.zextOrSelf(Wide);
297*af732203SDimitry Andric     OtherVal = OtherVal.zextOrSelf(Wide);
298*af732203SDimitry Andric   }
299*af732203SDimitry Andric 
300*af732203SDimitry Andric   // Upscale to compensate for the loss of precision from division, and
301*af732203SDimitry Andric   // perform the full division.
302*af732203SDimitry Andric   ThisVal = ThisVal.shl(CommonFXSema.getScale());
303*af732203SDimitry Andric   APSInt Result;
304*af732203SDimitry Andric   if (CommonFXSema.isSigned()) {
305*af732203SDimitry Andric     APInt Rem;
306*af732203SDimitry Andric     APInt::sdivrem(ThisVal, OtherVal, Result, Rem);
307*af732203SDimitry Andric     // If the quotient is negative and the remainder is nonzero, round
308*af732203SDimitry Andric     // towards negative infinity by subtracting epsilon from the result.
309*af732203SDimitry Andric     if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isNullValue())
310*af732203SDimitry Andric       Result = Result - 1;
311*af732203SDimitry Andric   } else
312*af732203SDimitry Andric     Result = ThisVal.udiv(OtherVal);
313*af732203SDimitry Andric   Result.setIsSigned(CommonFXSema.isSigned());
314*af732203SDimitry Andric 
315*af732203SDimitry Andric   // If our result lies outside of the representative range of the common
316*af732203SDimitry Andric   // semantic, we either have overflow or saturation.
317*af732203SDimitry Andric   APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
318*af732203SDimitry Andric                                                  .extOrTrunc(Wide);
319*af732203SDimitry Andric   APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
320*af732203SDimitry Andric                                                  .extOrTrunc(Wide);
321*af732203SDimitry Andric   if (CommonFXSema.isSaturated()) {
322*af732203SDimitry Andric     if (Result < Min)
323*af732203SDimitry Andric       Result = Min;
324*af732203SDimitry Andric     else if (Result > Max)
325*af732203SDimitry Andric       Result = Max;
326*af732203SDimitry Andric   } else
327*af732203SDimitry Andric     Overflowed = Result < Min || Result > Max;
328*af732203SDimitry Andric 
329*af732203SDimitry Andric   if (Overflow)
330*af732203SDimitry Andric     *Overflow = Overflowed;
331*af732203SDimitry Andric 
332*af732203SDimitry Andric   return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
333*af732203SDimitry Andric                       CommonFXSema);
334*af732203SDimitry Andric }
335*af732203SDimitry Andric 
shl(unsigned Amt,bool * Overflow) const336*af732203SDimitry Andric APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const {
337*af732203SDimitry Andric   APSInt ThisVal = Val;
338*af732203SDimitry Andric   bool Overflowed = false;
339*af732203SDimitry Andric 
340*af732203SDimitry Andric   // Widen the LHS.
341*af732203SDimitry Andric   unsigned Wide = Sema.getWidth() * 2;
342*af732203SDimitry Andric   if (Sema.isSigned())
343*af732203SDimitry Andric     ThisVal = ThisVal.sextOrSelf(Wide);
344*af732203SDimitry Andric   else
345*af732203SDimitry Andric     ThisVal = ThisVal.zextOrSelf(Wide);
346*af732203SDimitry Andric 
347*af732203SDimitry Andric   // Clamp the shift amount at the original width, and perform the shift.
348*af732203SDimitry Andric   Amt = std::min(Amt, ThisVal.getBitWidth());
349*af732203SDimitry Andric   APSInt Result = ThisVal << Amt;
350*af732203SDimitry Andric   Result.setIsSigned(Sema.isSigned());
351*af732203SDimitry Andric 
352*af732203SDimitry Andric   // If our result lies outside of the representative range of the
353*af732203SDimitry Andric   // semantic, we either have overflow or saturation.
354*af732203SDimitry Andric   APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide);
355*af732203SDimitry Andric   APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide);
356*af732203SDimitry Andric   if (Sema.isSaturated()) {
357*af732203SDimitry Andric     if (Result < Min)
358*af732203SDimitry Andric       Result = Min;
359*af732203SDimitry Andric     else if (Result > Max)
360*af732203SDimitry Andric       Result = Max;
361*af732203SDimitry Andric   } else
362*af732203SDimitry Andric     Overflowed = Result < Min || Result > Max;
363*af732203SDimitry Andric 
364*af732203SDimitry Andric   if (Overflow)
365*af732203SDimitry Andric     *Overflow = Overflowed;
366*af732203SDimitry Andric 
367*af732203SDimitry Andric   return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema);
368*af732203SDimitry Andric }
369*af732203SDimitry Andric 
toString(SmallVectorImpl<char> & Str) const370*af732203SDimitry Andric void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
371*af732203SDimitry Andric   APSInt Val = getValue();
372*af732203SDimitry Andric   unsigned Scale = getScale();
373*af732203SDimitry Andric 
374*af732203SDimitry Andric   if (Val.isSigned() && Val.isNegative() && Val != -Val) {
375*af732203SDimitry Andric     Val = -Val;
376*af732203SDimitry Andric     Str.push_back('-');
377*af732203SDimitry Andric   }
378*af732203SDimitry Andric 
379*af732203SDimitry Andric   APSInt IntPart = Val >> Scale;
380*af732203SDimitry Andric 
381*af732203SDimitry Andric   // Add 4 digits to hold the value after multiplying 10 (the radix)
382*af732203SDimitry Andric   unsigned Width = Val.getBitWidth() + 4;
383*af732203SDimitry Andric   APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
384*af732203SDimitry Andric   APInt FractPartMask = APInt::getAllOnesValue(Scale).zext(Width);
385*af732203SDimitry Andric   APInt RadixInt = APInt(Width, 10);
386*af732203SDimitry Andric 
387*af732203SDimitry Andric   IntPart.toString(Str, /*Radix=*/10);
388*af732203SDimitry Andric   Str.push_back('.');
389*af732203SDimitry Andric   do {
390*af732203SDimitry Andric     (FractPart * RadixInt)
391*af732203SDimitry Andric         .lshr(Scale)
392*af732203SDimitry Andric         .toString(Str, /*Radix=*/10, Val.isSigned());
393*af732203SDimitry Andric     FractPart = (FractPart * RadixInt) & FractPartMask;
394*af732203SDimitry Andric   } while (FractPart != 0);
395*af732203SDimitry Andric }
396*af732203SDimitry Andric 
negate(bool * Overflow) const397*af732203SDimitry Andric APFixedPoint APFixedPoint::negate(bool *Overflow) const {
398*af732203SDimitry Andric   if (!isSaturated()) {
399*af732203SDimitry Andric     if (Overflow)
400*af732203SDimitry Andric       *Overflow =
401*af732203SDimitry Andric           (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue());
402*af732203SDimitry Andric     return APFixedPoint(-Val, Sema);
403*af732203SDimitry Andric   }
404*af732203SDimitry Andric 
405*af732203SDimitry Andric   // We never overflow for saturation
406*af732203SDimitry Andric   if (Overflow)
407*af732203SDimitry Andric     *Overflow = false;
408*af732203SDimitry Andric 
409*af732203SDimitry Andric   if (isSigned())
410*af732203SDimitry Andric     return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
411*af732203SDimitry Andric   else
412*af732203SDimitry Andric     return APFixedPoint(Sema);
413*af732203SDimitry Andric }
414*af732203SDimitry Andric 
convertToInt(unsigned DstWidth,bool DstSign,bool * Overflow) const415*af732203SDimitry Andric APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
416*af732203SDimitry Andric                                   bool *Overflow) const {
417*af732203SDimitry Andric   APSInt Result = getIntPart();
418*af732203SDimitry Andric   unsigned SrcWidth = getWidth();
419*af732203SDimitry Andric 
420*af732203SDimitry Andric   APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign);
421*af732203SDimitry Andric   APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign);
422*af732203SDimitry Andric 
423*af732203SDimitry Andric   if (SrcWidth < DstWidth) {
424*af732203SDimitry Andric     Result = Result.extend(DstWidth);
425*af732203SDimitry Andric   } else if (SrcWidth > DstWidth) {
426*af732203SDimitry Andric     DstMin = DstMin.extend(SrcWidth);
427*af732203SDimitry Andric     DstMax = DstMax.extend(SrcWidth);
428*af732203SDimitry Andric   }
429*af732203SDimitry Andric 
430*af732203SDimitry Andric   if (Overflow) {
431*af732203SDimitry Andric     if (Result.isSigned() && !DstSign) {
432*af732203SDimitry Andric       *Overflow = Result.isNegative() || Result.ugt(DstMax);
433*af732203SDimitry Andric     } else if (Result.isUnsigned() && DstSign) {
434*af732203SDimitry Andric       *Overflow = Result.ugt(DstMax);
435*af732203SDimitry Andric     } else {
436*af732203SDimitry Andric       *Overflow = Result < DstMin || Result > DstMax;
437*af732203SDimitry Andric     }
438*af732203SDimitry Andric   }
439*af732203SDimitry Andric 
440*af732203SDimitry Andric   Result.setIsSigned(DstSign);
441*af732203SDimitry Andric   return Result.extOrTrunc(DstWidth);
442*af732203SDimitry Andric }
443*af732203SDimitry Andric 
promoteFloatSemantics(const fltSemantics * S)444*af732203SDimitry Andric const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) {
445*af732203SDimitry Andric   if (S == &APFloat::BFloat())
446*af732203SDimitry Andric     return &APFloat::IEEEdouble();
447*af732203SDimitry Andric   else if (S == &APFloat::IEEEhalf())
448*af732203SDimitry Andric     return &APFloat::IEEEsingle();
449*af732203SDimitry Andric   else if (S == &APFloat::IEEEsingle())
450*af732203SDimitry Andric     return &APFloat::IEEEdouble();
451*af732203SDimitry Andric   else if (S == &APFloat::IEEEdouble())
452*af732203SDimitry Andric     return &APFloat::IEEEquad();
453*af732203SDimitry Andric   llvm_unreachable("Could not promote float type!");
454*af732203SDimitry Andric }
455*af732203SDimitry Andric 
convertToFloat(const fltSemantics & FloatSema) const456*af732203SDimitry Andric APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {
457*af732203SDimitry Andric   // For some operations, rounding mode has an effect on the result, while
458*af732203SDimitry Andric   // other operations are lossless and should never result in rounding.
459*af732203SDimitry Andric   // To signify which these operations are, we define two rounding modes here.
460*af732203SDimitry Andric   APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
461*af732203SDimitry Andric   APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
462*af732203SDimitry Andric 
463*af732203SDimitry Andric   // Make sure that we are operating in a type that works with this fixed-point
464*af732203SDimitry Andric   // semantic.
465*af732203SDimitry Andric   const fltSemantics *OpSema = &FloatSema;
466*af732203SDimitry Andric   while (!Sema.fitsInFloatSemantics(*OpSema))
467*af732203SDimitry Andric     OpSema = promoteFloatSemantics(OpSema);
468*af732203SDimitry Andric 
469*af732203SDimitry Andric   // Convert the fixed point value bits as an integer. If the floating point
470*af732203SDimitry Andric   // value does not have the required precision, we will round according to the
471*af732203SDimitry Andric   // given mode.
472*af732203SDimitry Andric   APFloat Flt(*OpSema);
473*af732203SDimitry Andric   APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM);
474*af732203SDimitry Andric 
475*af732203SDimitry Andric   // If we cared about checking for precision loss, we could look at this
476*af732203SDimitry Andric   // status.
477*af732203SDimitry Andric   (void)S;
478*af732203SDimitry Andric 
479*af732203SDimitry Andric   // Scale down the integer value in the float to match the correct scaling
480*af732203SDimitry Andric   // factor.
481*af732203SDimitry Andric   APFloat ScaleFactor(std::pow(2, -(int)Sema.getScale()));
482*af732203SDimitry Andric   bool Ignored;
483*af732203SDimitry Andric   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
484*af732203SDimitry Andric   Flt.multiply(ScaleFactor, LosslessRM);
485*af732203SDimitry Andric 
486*af732203SDimitry Andric   if (OpSema != &FloatSema)
487*af732203SDimitry Andric     Flt.convert(FloatSema, RM, &Ignored);
488*af732203SDimitry Andric 
489*af732203SDimitry Andric   return Flt;
490*af732203SDimitry Andric }
491*af732203SDimitry Andric 
getFromIntValue(const APSInt & Value,const FixedPointSemantics & DstFXSema,bool * Overflow)492*af732203SDimitry Andric APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
493*af732203SDimitry Andric                                            const FixedPointSemantics &DstFXSema,
494*af732203SDimitry Andric                                            bool *Overflow) {
495*af732203SDimitry Andric   FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
496*af732203SDimitry Andric       Value.getBitWidth(), Value.isSigned());
497*af732203SDimitry Andric   return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
498*af732203SDimitry Andric }
499*af732203SDimitry Andric 
500*af732203SDimitry Andric APFixedPoint
getFromFloatValue(const APFloat & Value,const FixedPointSemantics & DstFXSema,bool * Overflow)501*af732203SDimitry Andric APFixedPoint::getFromFloatValue(const APFloat &Value,
502*af732203SDimitry Andric                                 const FixedPointSemantics &DstFXSema,
503*af732203SDimitry Andric                                 bool *Overflow) {
504*af732203SDimitry Andric   // For some operations, rounding mode has an effect on the result, while
505*af732203SDimitry Andric   // other operations are lossless and should never result in rounding.
506*af732203SDimitry Andric   // To signify which these operations are, we define two rounding modes here,
507*af732203SDimitry Andric   // even though they are the same mode.
508*af732203SDimitry Andric   APFloat::roundingMode RM = APFloat::rmTowardZero;
509*af732203SDimitry Andric   APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
510*af732203SDimitry Andric 
511*af732203SDimitry Andric   const fltSemantics &FloatSema = Value.getSemantics();
512*af732203SDimitry Andric 
513*af732203SDimitry Andric   if (Value.isNaN()) {
514*af732203SDimitry Andric     // Handle NaN immediately.
515*af732203SDimitry Andric     if (Overflow)
516*af732203SDimitry Andric       *Overflow = true;
517*af732203SDimitry Andric     return APFixedPoint(DstFXSema);
518*af732203SDimitry Andric   }
519*af732203SDimitry Andric 
520*af732203SDimitry Andric   // Make sure that we are operating in a type that works with this fixed-point
521*af732203SDimitry Andric   // semantic.
522*af732203SDimitry Andric   const fltSemantics *OpSema = &FloatSema;
523*af732203SDimitry Andric   while (!DstFXSema.fitsInFloatSemantics(*OpSema))
524*af732203SDimitry Andric     OpSema = promoteFloatSemantics(OpSema);
525*af732203SDimitry Andric 
526*af732203SDimitry Andric   APFloat Val = Value;
527*af732203SDimitry Andric 
528*af732203SDimitry Andric   bool Ignored;
529*af732203SDimitry Andric   if (&FloatSema != OpSema)
530*af732203SDimitry Andric     Val.convert(*OpSema, LosslessRM, &Ignored);
531*af732203SDimitry Andric 
532*af732203SDimitry Andric   // Scale up the float so that the 'fractional' part of the mantissa ends up in
533*af732203SDimitry Andric   // the integer range instead. Rounding mode is irrelevant here.
534*af732203SDimitry Andric   // It is fine if this overflows to infinity even for saturating types,
535*af732203SDimitry Andric   // since we will use floating point comparisons to check for saturation.
536*af732203SDimitry Andric   APFloat ScaleFactor(std::pow(2, DstFXSema.getScale()));
537*af732203SDimitry Andric   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
538*af732203SDimitry Andric   Val.multiply(ScaleFactor, LosslessRM);
539*af732203SDimitry Andric 
540*af732203SDimitry Andric   // Convert to the integral representation of the value. This rounding mode
541*af732203SDimitry Andric   // is significant.
542*af732203SDimitry Andric   APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned());
543*af732203SDimitry Andric   Val.convertToInteger(Res, RM, &Ignored);
544*af732203SDimitry Andric 
545*af732203SDimitry Andric   // Round the integral value and scale back. This makes the
546*af732203SDimitry Andric   // overflow calculations below work properly. If we do not round here,
547*af732203SDimitry Andric   // we risk checking for overflow with a value that is outside the
548*af732203SDimitry Andric   // representable range of the fixed-point semantic even though no overflow
549*af732203SDimitry Andric   // would occur had we rounded first.
550*af732203SDimitry Andric   ScaleFactor = APFloat(std::pow(2, -(int)DstFXSema.getScale()));
551*af732203SDimitry Andric   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
552*af732203SDimitry Andric   Val.roundToIntegral(RM);
553*af732203SDimitry Andric   Val.multiply(ScaleFactor, LosslessRM);
554*af732203SDimitry Andric 
555*af732203SDimitry Andric   // Check for overflow/saturation by checking if the floating point value
556*af732203SDimitry Andric   // is outside the range representable by the fixed-point value.
557*af732203SDimitry Andric   APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema);
558*af732203SDimitry Andric   APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema);
559*af732203SDimitry Andric   bool Overflowed = false;
560*af732203SDimitry Andric   if (DstFXSema.isSaturated()) {
561*af732203SDimitry Andric     if (Val > FloatMax)
562*af732203SDimitry Andric       Res = getMax(DstFXSema).getValue();
563*af732203SDimitry Andric     else if (Val < FloatMin)
564*af732203SDimitry Andric       Res = getMin(DstFXSema).getValue();
565*af732203SDimitry Andric   } else
566*af732203SDimitry Andric     Overflowed = Val > FloatMax || Val < FloatMin;
567*af732203SDimitry Andric 
568*af732203SDimitry Andric   if (Overflow)
569*af732203SDimitry Andric     *Overflow = Overflowed;
570*af732203SDimitry Andric 
571*af732203SDimitry Andric   return APFixedPoint(Res, DstFXSema);
572*af732203SDimitry Andric }
573*af732203SDimitry Andric 
574*af732203SDimitry Andric } // namespace llvm
575