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