xref: /freebsd/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 
296   if (Overflow)
297     *Overflow = Overflowed;
298 
299   return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
300                       CommonFXSema);
301 }
302 
303 APFixedPoint APFixedPoint::div(const APFixedPoint &Other,
304                                bool *Overflow) const {
305   auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
306   APFixedPoint ConvertedThis = convert(CommonFXSema);
307   APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
308   APSInt ThisVal = ConvertedThis.getValue();
309   APSInt OtherVal = ConvertedOther.getValue();
310   bool Overflowed = false;
311 
312   // Widen the LHS and RHS so we can perform a full division.
313   // Also make sure that there will be enough space for the shift below to not
314   // overflow
315   unsigned Wide =
316       CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0);
317   if (CommonFXSema.isSigned()) {
318     ThisVal = ThisVal.sext(Wide);
319     OtherVal = OtherVal.sext(Wide);
320   } else {
321     ThisVal = ThisVal.zext(Wide);
322     OtherVal = OtherVal.zext(Wide);
323   }
324 
325   // Upscale to compensate for the loss of precision from division, and
326   // perform the full division.
327   if (CommonFXSema.getLsbWeight() < 0)
328     ThisVal = ThisVal.shl(-CommonFXSema.getLsbWeight());
329   else if (CommonFXSema.getLsbWeight() > 0)
330     OtherVal = OtherVal.shl(CommonFXSema.getLsbWeight());
331   APSInt Result;
332   if (CommonFXSema.isSigned()) {
333     APInt Rem;
334     APInt::sdivrem(ThisVal, OtherVal, Result, Rem);
335     // If the quotient is negative and the remainder is nonzero, round
336     // towards negative infinity by subtracting epsilon from the result.
337     if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero())
338       Result = Result - 1;
339   } else {
340     Result = ThisVal.udiv(OtherVal);
341   }
342   Result.setIsSigned(CommonFXSema.isSigned());
343 
344   // If our result lies outside of the representative range of the common
345   // semantic, we either have overflow or saturation.
346   APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue()
347                                                  .extOrTrunc(Wide);
348   APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue()
349                                                  .extOrTrunc(Wide);
350   if (CommonFXSema.isSaturated()) {
351     if (Result < Min)
352       Result = Min;
353     else if (Result > Max)
354       Result = Max;
355   } else {
356     Overflowed = Result < Min || Result > Max;
357   }
358 
359   if (Overflow)
360     *Overflow = Overflowed;
361 
362   return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
363                       CommonFXSema);
364 }
365 
366 APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const {
367   APSInt ThisVal = Val;
368   bool Overflowed = false;
369 
370   // Widen the LHS.
371   unsigned Wide = Sema.getWidth() * 2;
372   if (Sema.isSigned())
373     ThisVal = ThisVal.sext(Wide);
374   else
375     ThisVal = ThisVal.zext(Wide);
376 
377   // Clamp the shift amount at the original width, and perform the shift.
378   Amt = std::min(Amt, ThisVal.getBitWidth());
379   APSInt Result = ThisVal << Amt;
380   Result.setIsSigned(Sema.isSigned());
381 
382   // If our result lies outside of the representative range of the
383   // semantic, we either have overflow or saturation.
384   APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide);
385   APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide);
386   if (Sema.isSaturated()) {
387     if (Result < Min)
388       Result = Min;
389     else if (Result > Max)
390       Result = Max;
391   } else {
392     Overflowed = Result < Min || Result > Max;
393   }
394 
395   if (Overflow)
396     *Overflow = Overflowed;
397 
398   return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema);
399 }
400 
401 void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
402   APSInt Val = getValue();
403   int Lsb = getLsbWeight();
404   int OrigWidth = getWidth();
405 
406   if (Lsb >= 0) {
407     APSInt IntPart = Val;
408     IntPart = IntPart.extend(IntPart.getBitWidth() + Lsb);
409     IntPart <<= Lsb;
410     IntPart.toString(Str, /*Radix=*/10);
411     Str.push_back('.');
412     Str.push_back('0');
413     return;
414   }
415 
416   if (Val.isSigned() && Val.isNegative()) {
417     Val = -Val;
418     Val.setIsUnsigned(true);
419     Str.push_back('-');
420   }
421 
422   int Scale = -getLsbWeight();
423   APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0);
424 
425   // Add 4 digits to hold the value after multiplying 10 (the radix)
426   unsigned Width = std::max(OrigWidth, Scale) + 4;
427   APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
428   APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width);
429   APInt RadixInt = APInt(Width, 10);
430 
431   IntPart.toString(Str, /*Radix=*/10);
432   Str.push_back('.');
433   do {
434     (FractPart * RadixInt)
435         .lshr(Scale)
436         .toString(Str, /*Radix=*/10, Val.isSigned());
437     FractPart = (FractPart * RadixInt) & FractPartMask;
438   } while (FractPart != 0);
439 }
440 
441 void APFixedPoint::print(raw_ostream &OS) const {
442   OS << "APFixedPoint(" << toString() << ", {";
443   Sema.print(OS);
444   OS << "})";
445 }
446 
447 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
448 LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); }
449 #endif
450 
451 APFixedPoint APFixedPoint::negate(bool *Overflow) const {
452   if (!isSaturated()) {
453     if (Overflow)
454       *Overflow =
455           (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue());
456     return APFixedPoint(-Val, Sema);
457   }
458 
459   // We never overflow for saturation
460   if (Overflow)
461     *Overflow = false;
462 
463   if (isSigned())
464     return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
465   else
466     return APFixedPoint(Sema);
467 }
468 
469 APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
470                                   bool *Overflow) const {
471   APSInt Result = getIntPart();
472   unsigned SrcWidth = getWidth();
473 
474   APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign);
475   APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign);
476 
477   if (SrcWidth < DstWidth) {
478     Result = Result.extend(DstWidth);
479   } else if (SrcWidth > DstWidth) {
480     DstMin = DstMin.extend(SrcWidth);
481     DstMax = DstMax.extend(SrcWidth);
482   }
483 
484   if (Overflow) {
485     if (Result.isSigned() && !DstSign) {
486       *Overflow = Result.isNegative() || Result.ugt(DstMax);
487     } else if (Result.isUnsigned() && DstSign) {
488       *Overflow = Result.ugt(DstMax);
489     } else {
490       *Overflow = Result < DstMin || Result > DstMax;
491     }
492   }
493 
494   Result.setIsSigned(DstSign);
495   return Result.extOrTrunc(DstWidth);
496 }
497 
498 const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) {
499   if (S == &APFloat::BFloat())
500     return &APFloat::IEEEdouble();
501   else if (S == &APFloat::IEEEhalf())
502     return &APFloat::IEEEsingle();
503   else if (S == &APFloat::IEEEsingle())
504     return &APFloat::IEEEdouble();
505   else if (S == &APFloat::IEEEdouble())
506     return &APFloat::IEEEquad();
507   llvm_unreachable("Could not promote float type!");
508 }
509 
510 APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {
511   // For some operations, rounding mode has an effect on the result, while
512   // other operations are lossless and should never result in rounding.
513   // To signify which these operations are, we define two rounding modes here.
514   APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
515   APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
516 
517   // Make sure that we are operating in a type that works with this fixed-point
518   // semantic.
519   const fltSemantics *OpSema = &FloatSema;
520   while (!Sema.fitsInFloatSemantics(*OpSema))
521     OpSema = promoteFloatSemantics(OpSema);
522 
523   // Convert the fixed point value bits as an integer. If the floating point
524   // value does not have the required precision, we will round according to the
525   // given mode.
526   APFloat Flt(*OpSema);
527   APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM);
528 
529   // If we cared about checking for precision loss, we could look at this
530   // status.
531   (void)S;
532 
533   // Scale down the integer value in the float to match the correct scaling
534   // factor.
535   APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight()));
536   bool Ignored;
537   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
538   Flt.multiply(ScaleFactor, LosslessRM);
539 
540   if (OpSema != &FloatSema)
541     Flt.convert(FloatSema, RM, &Ignored);
542 
543   return Flt;
544 }
545 
546 APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
547                                            const FixedPointSemantics &DstFXSema,
548                                            bool *Overflow) {
549   FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
550       Value.getBitWidth(), Value.isSigned());
551   return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
552 }
553 
554 APFixedPoint
555 APFixedPoint::getFromFloatValue(const APFloat &Value,
556                                 const FixedPointSemantics &DstFXSema,
557                                 bool *Overflow) {
558   // For some operations, rounding mode has an effect on the result, while
559   // other operations are lossless and should never result in rounding.
560   // To signify which these operations are, we define two rounding modes here,
561   // even though they are the same mode.
562   APFloat::roundingMode RM = APFloat::rmTowardZero;
563   APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
564 
565   const fltSemantics &FloatSema = Value.getSemantics();
566 
567   if (Value.isNaN()) {
568     // Handle NaN immediately.
569     if (Overflow)
570       *Overflow = true;
571     return APFixedPoint(DstFXSema);
572   }
573 
574   // Make sure that we are operating in a type that works with this fixed-point
575   // semantic.
576   const fltSemantics *OpSema = &FloatSema;
577   while (!DstFXSema.fitsInFloatSemantics(*OpSema))
578     OpSema = promoteFloatSemantics(OpSema);
579 
580   APFloat Val = Value;
581 
582   bool Ignored;
583   if (&FloatSema != OpSema)
584     Val.convert(*OpSema, LosslessRM, &Ignored);
585 
586   // Scale up the float so that the 'fractional' part of the mantissa ends up in
587   // the integer range instead. Rounding mode is irrelevant here.
588   // It is fine if this overflows to infinity even for saturating types,
589   // since we will use floating point comparisons to check for saturation.
590   APFloat ScaleFactor(std::pow(2, -DstFXSema.getLsbWeight()));
591   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
592   Val.multiply(ScaleFactor, LosslessRM);
593 
594   // Convert to the integral representation of the value. This rounding mode
595   // is significant.
596   APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned());
597   Val.convertToInteger(Res, RM, &Ignored);
598 
599   // Round the integral value and scale back. This makes the
600   // overflow calculations below work properly. If we do not round here,
601   // we risk checking for overflow with a value that is outside the
602   // representable range of the fixed-point semantic even though no overflow
603   // would occur had we rounded first.
604   ScaleFactor = APFloat(std::pow(2, DstFXSema.getLsbWeight()));
605   ScaleFactor.convert(*OpSema, LosslessRM, &Ignored);
606   Val.roundToIntegral(RM);
607   Val.multiply(ScaleFactor, LosslessRM);
608 
609   // Check for overflow/saturation by checking if the floating point value
610   // is outside the range representable by the fixed-point value.
611   APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema);
612   APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema);
613   bool Overflowed = false;
614   if (DstFXSema.isSaturated()) {
615     if (Val > FloatMax)
616       Res = getMax(DstFXSema).getValue();
617     else if (Val < FloatMin)
618       Res = getMin(DstFXSema).getValue();
619   } else {
620     Overflowed = Val > FloatMax || Val < FloatMin;
621   }
622 
623   if (Overflow)
624     *Overflow = Overflowed;
625 
626   return APFixedPoint(Res, DstFXSema);
627 }
628 
629 } // namespace llvm
630