12
12
// ===----------------------------------------------------------------------===//
13
13
14
14
#include " llvm/ADT/APFixedPoint.h"
15
+ #include " llvm/ADT/APFloat.h"
15
16
16
17
namespace llvm {
17
18
@@ -124,6 +125,29 @@ APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
124
125
return APFixedPoint (Val, Sema);
125
126
}
126
127
128
+ bool FixedPointSemantics::fitsInFloatSemantics (
129
+ const fltSemantics &FloatSema) const {
130
+ // A fixed point semantic fits in a floating point semantic if the maximum
131
+ // and minimum values as integers of the fixed point semantic can fit in the
132
+ // floating point semantic.
133
+
134
+ // If these values do not fit, then a floating point rescaling of the true
135
+ // maximum/minimum value will not fit either, so the floating point semantic
136
+ // cannot be used to perform such a rescaling.
137
+
138
+ APSInt MaxInt = APFixedPoint::getMax (*this ).getValue ();
139
+ APFloat F (FloatSema);
140
+ APFloat::opStatus Status = F.convertFromAPInt (MaxInt, MaxInt.isSigned (),
141
+ APFloat::rmNearestTiesToAway);
142
+ if ((Status & APFloat::opOverflow) || !isSigned ())
143
+ return !(Status & APFloat::opOverflow);
144
+
145
+ APSInt MinInt = APFixedPoint::getMin (*this ).getValue ();
146
+ Status = F.convertFromAPInt (MinInt, MinInt.isSigned (),
147
+ APFloat::rmNearestTiesToAway);
148
+ return !(Status & APFloat::opOverflow);
149
+ }
150
+
127
151
FixedPointSemantics FixedPointSemantics::getCommonSemantics (
128
152
const FixedPointSemantics &Other) const {
129
153
unsigned CommonScale = std::max (getScale (), Other.getScale ());
@@ -417,6 +441,54 @@ APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
417
441
return Result.extOrTrunc (DstWidth);
418
442
}
419
443
444
+ const fltSemantics *APFixedPoint::promoteFloatSemantics (const fltSemantics *S) {
445
+ if (S == &APFloat::BFloat ())
446
+ return &APFloat::IEEEdouble ();
447
+ else if (S == &APFloat::IEEEhalf ())
448
+ return &APFloat::IEEEsingle ();
449
+ else if (S == &APFloat::IEEEsingle ())
450
+ return &APFloat::IEEEdouble ();
451
+ else if (S == &APFloat::IEEEdouble ())
452
+ return &APFloat::IEEEquad ();
453
+ llvm_unreachable (" Could not promote float type!" );
454
+ }
455
+
456
+ APFloat APFixedPoint::convertToFloat (const fltSemantics &FloatSema) const {
457
+ // For some operations, rounding mode has an effect on the result, while
458
+ // other operations are lossless and should never result in rounding.
459
+ // To signify which these operations are, we define two rounding modes here.
460
+ APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
461
+ APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
462
+
463
+ // Make sure that we are operating in a type that works with this fixed-point
464
+ // semantic.
465
+ const fltSemantics *OpSema = &FloatSema;
466
+ while (!Sema.fitsInFloatSemantics (*OpSema))
467
+ OpSema = promoteFloatSemantics (OpSema);
468
+
469
+ // Convert the fixed point value bits as an integer. If the floating point
470
+ // value does not have the required precision, we will round according to the
471
+ // given mode.
472
+ APFloat Flt (*OpSema);
473
+ APFloat::opStatus S = Flt.convertFromAPInt (Val, Sema.isSigned (), RM);
474
+
475
+ // If we cared about checking for precision loss, we could look at this
476
+ // status.
477
+ (void )S;
478
+
479
+ // Scale down the integer value in the float to match the correct scaling
480
+ // factor.
481
+ APFloat ScaleFactor (std::pow (2 , -(int )Sema.getScale ()));
482
+ bool Ignored;
483
+ ScaleFactor.convert (*OpSema, LosslessRM, &Ignored);
484
+ Flt.multiply (ScaleFactor, LosslessRM);
485
+
486
+ if (OpSema != &FloatSema)
487
+ Flt.convert (FloatSema, RM, &Ignored);
488
+
489
+ return Flt;
490
+ }
491
+
420
492
APFixedPoint APFixedPoint::getFromIntValue (const APSInt &Value,
421
493
const FixedPointSemantics &DstFXSema,
422
494
bool *Overflow) {
@@ -425,4 +497,78 @@ APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
425
497
return APFixedPoint (Value, IntFXSema).convert (DstFXSema, Overflow);
426
498
}
427
499
428
- } // namespace clang
500
+ APFixedPoint
501
+ APFixedPoint::getFromFloatValue (const APFloat &Value,
502
+ const FixedPointSemantics &DstFXSema,
503
+ bool *Overflow) {
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
+ // even though they are the same mode.
508
+ APFloat::roundingMode RM = APFloat::rmTowardZero;
509
+ APFloat::roundingMode LosslessRM = APFloat::rmTowardZero;
510
+
511
+ const fltSemantics &FloatSema = Value.getSemantics ();
512
+
513
+ if (Value.isNaN ()) {
514
+ // Handle NaN immediately.
515
+ if (Overflow)
516
+ *Overflow = true ;
517
+ return APFixedPoint (DstFXSema);
518
+ }
519
+
520
+ // Make sure that we are operating in a type that works with this fixed-point
521
+ // semantic.
522
+ const fltSemantics *OpSema = &FloatSema;
523
+ while (!DstFXSema.fitsInFloatSemantics (*OpSema))
524
+ OpSema = promoteFloatSemantics (OpSema);
525
+
526
+ APFloat Val = Value;
527
+
528
+ bool Ignored;
529
+ if (&FloatSema != OpSema)
530
+ Val.convert (*OpSema, LosslessRM, &Ignored);
531
+
532
+ // Scale up the float so that the 'fractional' part of the mantissa ends up in
533
+ // the integer range instead. Rounding mode is irrelevant here.
534
+ // It is fine if this overflows to infinity even for saturating types,
535
+ // since we will use floating point comparisons to check for saturation.
536
+ APFloat ScaleFactor (std::pow (2 , DstFXSema.getScale ()));
537
+ ScaleFactor.convert (*OpSema, LosslessRM, &Ignored);
538
+ Val.multiply (ScaleFactor, LosslessRM);
539
+
540
+ // Convert to the integral representation of the value. This rounding mode
541
+ // is significant.
542
+ APSInt Res (DstFXSema.getWidth (), !DstFXSema.isSigned ());
543
+ Val.convertToInteger (Res, RM, &Ignored);
544
+
545
+ // Round the integral value and scale back. This makes the
546
+ // overflow calculations below work properly. If we do not round here,
547
+ // we risk checking for overflow with a value that is outside the
548
+ // representable range of the fixed-point semantic even though no overflow
549
+ // would occur had we rounded first.
550
+ ScaleFactor = APFloat (std::pow (2 , -(int )DstFXSema.getScale ()));
551
+ ScaleFactor.convert (*OpSema, LosslessRM, &Ignored);
552
+ Val.roundToIntegral (RM);
553
+ Val.multiply (ScaleFactor, LosslessRM);
554
+
555
+ // Check for overflow/saturation by checking if the floating point value
556
+ // is outside the range representable by the fixed-point value.
557
+ APFloat FloatMax = getMax (DstFXSema).convertToFloat (*OpSema);
558
+ APFloat FloatMin = getMin (DstFXSema).convertToFloat (*OpSema);
559
+ bool Overflowed = false ;
560
+ if (DstFXSema.isSaturated ()) {
561
+ if (Val > FloatMax)
562
+ Res = getMax (DstFXSema).getValue ();
563
+ else if (Val < FloatMin)
564
+ Res = getMin (DstFXSema).getValue ();
565
+ } else
566
+ Overflowed = Val > FloatMax || Val < FloatMin;
567
+
568
+ if (Overflow)
569
+ *Overflow = Overflowed;
570
+
571
+ return APFixedPoint (Res, DstFXSema);
572
+ }
573
+
574
+ } // namespace llvm
0 commit comments