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