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