[clang] Add test for CWG190 "Layout-compatible POD-struct types" (#121668)
[llvm-project.git] / llvm / lib / Support / APFixedPoint.cpp
blobf395919287b729b123b10a8fc56f67f3517e8ed0
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.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/APFixedPoint.h"
15 #include "llvm/ADT/APFloat.h"
17 #include <cmath>
19 namespace llvm {
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;
32 uint32_t FixedPointSemantics::toOpaqueInt() const {
33 return llvm::bit_cast<uint32_t>(*this);
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;
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;
49 if (RelativeUpscale > 0)
50 NewVal = NewVal.extend(NewVal.getBitWidth() + RelativeUpscale);
51 NewVal = NewVal.relativeShl(RelativeUpscale);
53 auto Mask = APInt::getBitsSetFrom(
54 NewVal.getBitWidth(),
55 std::min(DstSema.getIntegralBits() - DstSema.getLsbWeight(),
56 NewVal.getBitWidth()));
57 APInt Masked(NewVal & Mask);
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;
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;
78 NewVal = NewVal.extOrTrunc(DstSema.getWidth());
79 NewVal.setIsSigned(DstSema.isSigned());
80 return APFixedPoint(NewVal, DstSema);
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();
89 int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight());
90 int CommonMsb = std::max(getMsbWeight(), Other.getMsbWeight());
91 unsigned CommonWidth = CommonMsb - CommonLsb + 1;
93 ThisVal = ThisVal.extOrTrunc(CommonWidth);
94 OtherVal = OtherVal.extOrTrunc(CommonWidth);
96 ThisVal = ThisVal.shl(getLsbWeight() - CommonLsb);
97 OtherVal = OtherVal.shl(Other.getLsbWeight() - CommonLsb);
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;
126 return 0;
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);
137 APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
138 auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
139 return APFixedPoint(Val, Sema);
142 APFixedPoint APFixedPoint::getEpsilon(const FixedPointSemantics &Sema) {
143 APSInt Val(Sema.getWidth(), !Sema.isSigned());
144 Val.setBit(/*BitPosition=*/0);
145 return APFixedPoint(Val, Sema);
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.
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.
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);
165 APSInt MinInt = APFixedPoint::getMin(*this).getValue();
166 Status = F.convertFromAPInt(MinInt, MinInt.isSigned(),
167 APFloat::rmNearestTiesToAway);
168 return !(Status & APFloat::opOverflow);
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;
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;
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++;
193 return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned,
194 ResultIsSaturated, ResultHasUnsignedPadding);
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;
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);
215 if (Overflow)
216 *Overflow = Overflowed;
218 return APFixedPoint(Result, CommonFXSema);
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;
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);
239 if (Overflow)
240 *Overflow = Overflowed;
242 return APFixedPoint(Result, CommonFXSema);
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;
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);
264 // Perform the full multiplication and downscale to get the same scale.
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());
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;
295 if (Overflow)
296 *Overflow = Overflowed;
298 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
299 CommonFXSema);
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;
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);
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());
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;
356 if (Overflow)
357 *Overflow = Overflowed;
359 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()),
360 CommonFXSema);
363 APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const {
364 APSInt ThisVal = Val;
365 bool Overflowed = false;
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);
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());
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;
391 if (Overflow)
392 *Overflow = Overflowed;
394 return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema);
397 void APFixedPoint::toString(SmallVectorImpl<char> &Str) const {
398 APSInt Val = getValue();
399 int Lsb = getLsbWeight();
400 int OrigWidth = getWidth();
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;
412 if (Val.isSigned() && Val.isNegative()) {
413 Val = -Val;
414 Val.setIsUnsigned(true);
415 Str.push_back('-');
418 int Scale = -getLsbWeight();
419 APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0);
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);
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);
437 void APFixedPoint::print(raw_ostream &OS) const {
438 OS << "APFixedPoint(" << toString() << ", {";
439 Sema.print(OS);
440 OS << "})";
442 LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); }
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);
452 // We never overflow for saturation
453 if (Overflow)
454 *Overflow = false;
456 if (isSigned())
457 return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
458 else
459 return APFixedPoint(Sema);
462 APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
463 bool *Overflow) const {
464 APSInt Result = getIntPart();
465 unsigned SrcWidth = getWidth();
467 APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign);
468 APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign);
470 if (SrcWidth < DstWidth) {
471 Result = Result.extend(DstWidth);
472 } else if (SrcWidth > DstWidth) {
473 DstMin = DstMin.extend(SrcWidth);
474 DstMax = DstMax.extend(SrcWidth);
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;
487 Result.setIsSigned(DstSign);
488 return Result.extOrTrunc(DstWidth);
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!");
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;
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);
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);
522 // If we cared about checking for precision loss, we could look at this
523 // status.
524 (void)S;
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);
533 if (OpSema != &FloatSema)
534 Flt.convert(FloatSema, RM, &Ignored);
536 return Flt;
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);
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;
558 const fltSemantics &FloatSema = Value.getSemantics();
560 if (Value.isNaN()) {
561 // Handle NaN immediately.
562 if (Overflow)
563 *Overflow = true;
564 return APFixedPoint(DstFXSema);
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);
573 APFloat Val = Value;
575 bool Ignored;
576 if (&FloatSema != OpSema)
577 Val.convert(*OpSema, LosslessRM, &Ignored);
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);
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);
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);
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;
615 if (Overflow)
616 *Overflow = Overflowed;
618 return APFixedPoint(Res, DstFXSema);
621 } // namespace llvm