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