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 
fitsInFloatSemantics(const fltSemantics & FloatSema) const132 bool FixedPointSemantics::fitsInFloatSemantics(
133     const fltSemantics &FloatSema) const {
134   // A fixed point semantic fits in a floating point semantic if the maximum
135   // and minimum values as integers of the fixed point semantic can fit in the
136   // floating point semantic.
137 
138   // If these values do not fit, then a floating point rescaling of the true
139   // maximum/minimum value will not fit either, so the floating point semantic
140   // cannot be used to perform such a rescaling.
141 
142   APSInt MaxInt = APFixedPoint::getMax(*this).getValue();
143   APFloat F(FloatSema);
144   APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(),
145                                                 APFloat::rmNearestTiesToAway);
146   if ((Status & APFloat::opOverflow) || !isSigned())
147     return !(Status & APFloat::opOverflow);
148 
149   APSInt MinInt = APFixedPoint::getMin(*this).getValue();
150   Status = F.convertFromAPInt(MinInt, MinInt.isSigned(),
151                               APFloat::rmNearestTiesToAway);
152   return !(Status & APFloat::opOverflow);
153 }
154 
getCommonSemantics(const FixedPointSemantics & Other) const155 FixedPointSemantics FixedPointSemantics::getCommonSemantics(
156     const FixedPointSemantics &Other) const {
157   int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight());
158   int CommonMSb = std::max(getMsbWeight() - hasSignOrPaddingBit(),
159                            Other.getMsbWeight() - Other.hasSignOrPaddingBit());
160   unsigned CommonWidth = CommonMSb - CommonLsb + 1;
161 
162   bool ResultIsSigned = isSigned() || Other.isSigned();
163   bool ResultIsSaturated = isSaturated() || Other.isSaturated();
164   bool ResultHasUnsignedPadding = false;
165   if (!ResultIsSigned) {
166     // Both are unsigned.
167     ResultHasUnsignedPadding = hasUnsignedPadding() &&
168                                Other.hasUnsignedPadding() && !ResultIsSaturated;
169   }
170 
171   // If the result is signed, add an extra bit for the sign. Otherwise, if it is
172   // unsigned and has unsigned padding, we only need to add the extra padding
173   // bit back if we are not saturating.
174   if (ResultIsSigned || ResultHasUnsignedPadding)
175     CommonWidth++;
176 
177   return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned,
178                              ResultIsSaturated, ResultHasUnsignedPadding);
179 }
180 
add(const APFixedPoint & Other,bool * Overflow) const181 APFixedPoint APFixedPoint::add(const APFixedPoint &Other,
182                                bool *Overflow) const {
183   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
184   APFixedPoint ConvertedThis = convert(CommonFXSema);
185   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
186   APSInt ThisVal = ConvertedThis.getValue();
187   APSInt OtherVal = ConvertedOther.getValue();
188   bool Overflowed = false;
189 
190   APSInt Result;
191   if (CommonFXSema.isSaturated()) {
192     Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal)
193                                      : ThisVal.uadd_sat(OtherVal);
194   } else {
195     Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed)
196                                 : ThisVal.uadd_ov(OtherVal, Overflowed);
197   }
198 
199   if (Overflow)
200     *Overflow = Overflowed;
201 
202   return APFixedPoint(Result, CommonFXSema);
203 }
204 
sub(const APFixedPoint & Other,bool * Overflow) const205 APFixedPoint APFixedPoint::sub(const APFixedPoint &Other,
206                                bool *Overflow) const {
207   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
208   APFixedPoint ConvertedThis = convert(CommonFXSema);
209   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
210   APSInt ThisVal = ConvertedThis.getValue();
211   APSInt OtherVal = ConvertedOther.getValue();
212   bool Overflowed = false;
213 
214   APSInt Result;
215   if (CommonFXSema.isSaturated()) {
216     Result = CommonFXSema.isSigned() ? ThisVal.ssub_sat(OtherVal)
217                                      : ThisVal.usub_sat(OtherVal);
218   } else {
219     Result = ThisVal.isSigned() ? ThisVal.ssub_ov(OtherVal, Overflowed)
220                                 : ThisVal.usub_ov(OtherVal, Overflowed);
221   }
222 
223   if (Overflow)
224     *Overflow = Overflowed;
225 
226   return APFixedPoint(Result, CommonFXSema);
227 }
228 
mul(const APFixedPoint & Other,bool * Overflow) const229 APFixedPoint APFixedPoint::mul(const APFixedPoint &Other,
230                                bool *Overflow) const {
231   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
232   APFixedPoint ConvertedThis = convert(CommonFXSema);
233   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
234   APSInt ThisVal = ConvertedThis.getValue();
235   APSInt OtherVal = ConvertedOther.getValue();
236   bool Overflowed = false;
237 
238   // Widen the LHS and RHS so we can perform a full multiplication.
239   unsigned Wide = CommonFXSema.getWidth() * 2;
240   if (CommonFXSema.isSigned()) {
241     ThisVal = ThisVal.sext(Wide);
242     OtherVal = OtherVal.sext(Wide);
243   } else {
244     ThisVal = ThisVal.zext(Wide);
245     OtherVal = OtherVal.zext(Wide);
246   }
247 
248   // Perform the full multiplication and downscale to get the same scale.
249   //
250   // Note that the right shifts here perform an implicit downwards rounding.
251   // This rounding could discard bits that would technically place the result
252   // outside the representable range. We interpret the spec as allowing us to
253   // perform the rounding step first, avoiding the overflow case that would
254   // arise.
255   APSInt Result;
256   if (CommonFXSema.isSigned())
257     Result = ThisVal.smul_ov(OtherVal, Overflowed)
258                  .relativeAShl(CommonFXSema.getLsbWeight());
259   else
260     Result = ThisVal.umul_ov(OtherVal, Overflowed)
261                  .relativeLShl(CommonFXSema.getLsbWeight());
262   assert(!Overflowed && "Full multiplication cannot overflow!");
263   Result.setIsSigned(CommonFXSema.isSigned());
264 
265   // If our result lies outside of the representative range of the common
266   // semantic, we either have overflow or saturation.
267   APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
268                                                  .extOrTrunc(Wide);
269   APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
270                                                  .extOrTrunc(Wide);
271   if (CommonFXSema.isSaturated()) {
272     if (Result < Min)
273       Result = Min;
274     else if (Result > Max)
275       Result = Max;
276   } else
277     Overflowed = Result < Min || Result > Max;
278 
279   if (Overflow)
280     *Overflow = Overflowed;
281 
282   return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
283                       CommonFXSema);
284 }
285 
div(const APFixedPoint & Other,bool * Overflow) const286 APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
287                                bool *Overflow) const {
288   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
289   APFixedPoint ConvertedThis = convert(CommonFXSema);
290   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
291   APSInt ThisVal = ConvertedThis.getValue();
292   APSInt OtherVal = ConvertedOther.getValue();
293   bool Overflowed = false;
294 
295   // Widen the LHS and RHS so we can perform a full division.
296   // Also make sure that there will be enough space for the shift below to not
297   // overflow
298   unsigned Wide =
299       CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0);
300   if (CommonFXSema.isSigned()) {
301     ThisVal = ThisVal.sext(Wide);
302     OtherVal = OtherVal.sext(Wide);
303   } else {
304     ThisVal = ThisVal.zext(Wide);
305     OtherVal = OtherVal.zext(Wide);
306   }
307 
308   // Upscale to compensate for the loss of precision from division, and
309   // perform the full division.
310   if (CommonFXSema.getLsbWeight() < 0)
311     ThisVal = ThisVal.shl(-CommonFXSema.getLsbWeight());
312   else if (CommonFXSema.getLsbWeight() > 0)
313     OtherVal = OtherVal.shl(CommonFXSema.getLsbWeight());
314   APSInt Result;
315   if (CommonFXSema.isSigned()) {
316     APInt Rem;
317     APInt::sdivrem(ThisVal, OtherVal, Result, Rem);
318     // If the quotient is negative and the remainder is nonzero, round
319     // towards negative infinity by subtracting epsilon from the result.
320     if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero())
321       Result = Result - 1;
322   } else
323     Result = ThisVal.udiv(OtherVal);
324   Result.setIsSigned(CommonFXSema.isSigned());
325 
326   // If our result lies outside of the representative range of the common
327   // semantic, we either have overflow or saturation.
328   APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
329                                                  .extOrTrunc(Wide);
330   APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
331                                                  .extOrTrunc(Wide);
332   if (CommonFXSema.isSaturated()) {
333     if (Result < Min)
334       Result = Min;
335     else if (Result > Max)
336       Result = Max;
337   } else
338     Overflowed = Result < Min || Result > Max;
339 
340   if (Overflow)
341     *Overflow = Overflowed;
342 
343   return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
344                       CommonFXSema);
345 }
346 
shl(unsigned Amt,bool * Overflow) const347 APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const {
348   APSInt ThisVal = Val;
349   bool Overflowed = false;
350 
351   // Widen the LHS.
352   unsigned Wide = Sema.getWidth() * 2;
353   if (Sema.isSigned())
354     ThisVal = ThisVal.sext(Wide);
355   else
356     ThisVal = ThisVal.zext(Wide);
357 
358   // Clamp the shift amount at the original width, and perform the shift.
359   Amt = std::min(Amt, ThisVal.getBitWidth());
360   APSInt Result = ThisVal << Amt;
361   Result.setIsSigned(Sema.isSigned());
362 
363   // If our result lies outside of the representative range of the
364   // semantic, we either have overflow or saturation.
365   APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide);
366   APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide);
367   if (Sema.isSaturated()) {
368     if (Result < Min)
369       Result = Min;
370     else if (Result > Max)
371       Result = Max;
372   } else
373     Overflowed = Result < Min || Result > Max;
374 
375   if (Overflow)
376     *Overflow = Overflowed;
377 
378   return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema);
379 }
380 
toString(SmallVectorImpl<char> & Str) const381 void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
382   APSInt Val = getValue();
383   int Lsb = getLsbWeight();
384   int OrigWidth = getWidth();
385 
386   if (Lsb >= 0) {
387     APSInt IntPart = Val;
388     IntPart = IntPart.extend(IntPart.getBitWidth() + Lsb);
389     IntPart <<= Lsb;
390     IntPart.toString(Str, /*Radix=*/10);
391     Str.push_back('.');
392     Str.push_back('0');
393     return;
394   }
395 
396   if (Val.isSigned() && Val.isNegative()) {
397     Val = -Val;
398     Val.setIsUnsigned(true);
399     Str.push_back('-');
400   }
401 
402   int Scale = -getLsbWeight();
403   APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0);
404 
405   // Add 4 digits to hold the value after multiplying 10 (the radix)
406   unsigned Width = std::max(OrigWidth, Scale) + 4;
407   APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
408   APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width);
409   APInt RadixInt = APInt(Width, 10);
410 
411   IntPart.toString(Str, /*Radix=*/10);
412   Str.push_back('.');
413   do {
414     (FractPart * RadixInt)
415         .lshr(Scale)
416         .toString(Str, /*Radix=*/10, Val.isSigned());
417     FractPart = (FractPart * RadixInt) & FractPartMask;
418   } while (FractPart != 0);
419 }
420 
print(raw_ostream & OS) const421 void APFixedPoint::print(raw_ostream &OS) const {
422   OS << "APFixedPoint(" << toString() << ", {";
423   Sema.print(OS);
424   OS << "})";
425 }
dump() const426 LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); }
427 
negate(bool * Overflow) const428 APFixedPoint APFixedPoint::negate(bool *Overflow) const {
429   if (!isSaturated()) {
430     if (Overflow)
431       *Overflow =
432           (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue());
433     return APFixedPoint(-Val, Sema);
434   }
435 
436   // We never overflow for saturation
437   if (Overflow)
438     *Overflow = false;
439 
440   if (isSigned())
441     return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
442   else
443     return APFixedPoint(Sema);
444 }
445 
convertToInt(unsigned DstWidth,bool DstSign,bool * Overflow) const446 APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
447                                   bool *Overflow) const {
448   APSInt Result = getIntPart();
449   unsigned SrcWidth = getWidth();
450 
451   APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign);
452   APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign);
453 
454   if (SrcWidth < DstWidth) {
455     Result = Result.extend(DstWidth);
456   } else if (SrcWidth > DstWidth) {
457     DstMin = DstMin.extend(SrcWidth);
458     DstMax = DstMax.extend(SrcWidth);
459   }
460 
461   if (Overflow) {
462     if (Result.isSigned() && !DstSign) {
463       *Overflow = Result.isNegative() || Result.ugt(DstMax);
464     } else if (Result.isUnsigned() && DstSign) {
465       *Overflow = Result.ugt(DstMax);
466     } else {
467       *Overflow = Result < DstMin || Result > DstMax;
468     }
469   }
470 
471   Result.setIsSigned(DstSign);
472   return Result.extOrTrunc(DstWidth);
473 }
474 
promoteFloatSemantics(const fltSemantics * S)475 const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) {
476   if (S == &APFloat::BFloat())
477     return &APFloat::IEEEdouble();
478   else if (S == &APFloat::IEEEhalf())
479     return &APFloat::IEEEsingle();
480   else if (S == &APFloat::IEEEsingle())
481     return &APFloat::IEEEdouble();
482   else if (S == &APFloat::IEEEdouble())
483     return &APFloat::IEEEquad();
484   llvm_unreachable("Could not promote float type!");
485 }
486 
convertToFloat(const fltSemantics & FloatSema) const487 APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {
488   // For some operations, rounding mode has an effect on the result, while
489   // other operations are lossless and should never result in rounding.
490   // To signify which these operations are, we define two rounding modes here.
491   APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
492   APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
493 
494   // Make sure that we are operating in a type that works with this fixed-point
495   // semantic.
496   const fltSemantics *OpSema = &FloatSema;
497   while (!Sema.fitsInFloatSemantics(*OpSema))
498     OpSema = promoteFloatSemantics(OpSema);
499 
500   // Convert the fixed point value bits as an integer. If the floating point
501   // value does not have the required precision, we will round according to the
502   // given mode.
503   APFloat Flt(*OpSema);
504   APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM);
505 
506   // If we cared about checking for precision loss, we could look at this
507   // status.
508   (void)S;
509 
510   // Scale down the integer value in the float to match the correct scaling
511   // factor.
512   APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight()));
513   bool Ignored;
514   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
515   Flt.multiply(ScaleFactor, LosslessRM);
516 
517   if (OpSema != &FloatSema)
518     Flt.convert(FloatSema, RM, &Ignored);
519 
520   return Flt;
521 }
522 
getFromIntValue(const APSInt & Value,const FixedPointSemantics & DstFXSema,bool * Overflow)523 APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
524                                            const FixedPointSemantics &DstFXSema,
525                                            bool *Overflow) {
526   FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
527       Value.getBitWidth(), Value.isSigned());
528   return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
529 }
530 
531 APFixedPoint
getFromFloatValue(const APFloat & Value,const FixedPointSemantics & DstFXSema,bool * Overflow)532 APFixedPoint::getFromFloatValue(const APFloat &Value,
533                                 const FixedPointSemantics &DstFXSema,
534                                 bool *Overflow) {
535   // For some operations, rounding mode has an effect on the result, while
536   // other operations are lossless and should never result in rounding.
537   // To signify which these operations are, we define two rounding modes here,
538   // even though they are the same mode.
539   APFloat::roundingMode RM = APFloat::rmTowardZero;
540   APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
541 
542   const fltSemantics &FloatSema = Value.getSemantics();
543 
544   if (Value.isNaN()) {
545     // Handle NaN immediately.
546     if (Overflow)
547       *Overflow = true;
548     return APFixedPoint(DstFXSema);
549   }
550 
551   // Make sure that we are operating in a type that works with this fixed-point
552   // semantic.
553   const fltSemantics *OpSema = &FloatSema;
554   while (!DstFXSema.fitsInFloatSemantics(*OpSema))
555     OpSema = promoteFloatSemantics(OpSema);
556 
557   APFloat Val = Value;
558 
559   bool Ignored;
560   if (&FloatSema != OpSema)
561     Val.convert(*OpSema, LosslessRM, &Ignored);
562 
563   // Scale up the float so that the 'fractional' part of the mantissa ends up in
564   // the integer range instead. Rounding mode is irrelevant here.
565   // It is fine if this overflows to infinity even for saturating types,
566   // since we will use floating point comparisons to check for saturation.
567   APFloat ScaleFactor(std::pow(2, -DstFXSema.getLsbWeight()));
568   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
569   Val.multiply(ScaleFactor, LosslessRM);
570 
571   // Convert to the integral representation of the value. This rounding mode
572   // is significant.
573   APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned());
574   Val.convertToInteger(Res, RM, &Ignored);
575 
576   // Round the integral value and scale back. This makes the
577   // overflow calculations below work properly. If we do not round here,
578   // we risk checking for overflow with a value that is outside the
579   // representable range of the fixed-point semantic even though no overflow
580   // would occur had we rounded first.
581   ScaleFactor = APFloat(std::pow(2, DstFXSema.getLsbWeight()));
582   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
583   Val.roundToIntegral(RM);
584   Val.multiply(ScaleFactor, LosslessRM);
585 
586   // Check for overflow/saturation by checking if the floating point value
587   // is outside the range representable by the fixed-point value.
588   APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema);
589   APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema);
590   bool Overflowed = false;
591   if (DstFXSema.isSaturated()) {
592     if (Val > FloatMax)
593       Res = getMax(DstFXSema).getValue();
594     else if (Val < FloatMin)
595       Res = getMin(DstFXSema).getValue();
596   } else
597     Overflowed = Val > FloatMax || Val < FloatMin;
598 
599   if (Overflow)
600     *Overflow = Overflowed;
601 
602   return APFixedPoint(Res, DstFXSema);
603 }
604 
605 } // namespace llvm
606