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