Skip to content

Commit ed9af1f

Browse files
author
git apple-llvm automerger
committed
Merge commit 'b70caadb2df2' from apple/main into swift/next
2 parents 4597e23 + b70caad commit ed9af1f

File tree

3 files changed

+460
-6
lines changed

3 files changed

+460
-6
lines changed

llvm/include/llvm/ADT/APFixedPoint.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
namespace llvm {
2424

25+
class APFloat;
26+
struct fltSemantics;
27+
2528
/// The fixed point semantics work similarly to fltSemantics. The width
2629
/// specifies the whole bit width of the underlying scaled integer (with padding
2730
/// if any). The scale represents the number of fractional bits in this type.
@@ -63,6 +66,15 @@ class FixedPointSemantics {
6366
FixedPointSemantics
6467
getCommonSemantics(const FixedPointSemantics &Other) const;
6568

69+
/// Returns true if this fixed-point semantic with its value bits interpreted
70+
/// as an integer can fit in the given floating point semantic without
71+
/// overflowing to infinity.
72+
/// For example, a signed 8-bit fixed-point semantic has a maximum and
73+
/// minimum integer representation of 127 and -128, respectively. If both of
74+
/// these values can be represented (possibly inexactly) in the floating
75+
/// point semantic without overflowing, this returns true.
76+
bool fitsInFloatSemantics(const fltSemantics &FloatSema) const;
77+
6678
/// Return the FixedPointSemantics for an integer type.
6779
static FixedPointSemantics GetIntegerSemantics(unsigned Width,
6880
bool IsSigned) {
@@ -153,12 +165,13 @@ class APFixedPoint {
153165
/// If the overflow parameter is provided, and the integral value is not able
154166
/// to be fully stored in the provided width and sign, the overflow parameter
155167
/// is set to true.
156-
///
157-
/// If the overflow parameter is provided, set this value to true or false to
158-
/// indicate if this operation results in an overflow.
159168
APSInt convertToInt(unsigned DstWidth, bool DstSign,
160169
bool *Overflow = nullptr) const;
161170

171+
/// Convert this fixed point number to a floating point value with the
172+
/// provided semantics.
173+
APFloat convertToFloat(const fltSemantics &FloatSema) const;
174+
162175
void toString(SmallVectorImpl<char> &Str) const;
163176
std::string toString() const {
164177
SmallString<40> S;
@@ -186,6 +199,10 @@ class APFixedPoint {
186199
static APFixedPoint getMax(const FixedPointSemantics &Sema);
187200
static APFixedPoint getMin(const FixedPointSemantics &Sema);
188201

202+
/// Given a floating point semantic, return the next floating point semantic
203+
/// with a larger exponent and larger or equal mantissa.
204+
static const fltSemantics *promoteFloatSemantics(const fltSemantics *S);
205+
189206
/// Create an APFixedPoint with a value equal to that of the provided integer,
190207
/// and in the same semantics as the provided target semantics. If the value
191208
/// is not able to fit in the specified fixed point semantics, and the
@@ -194,6 +211,17 @@ class APFixedPoint {
194211
const FixedPointSemantics &DstFXSema,
195212
bool *Overflow = nullptr);
196213

214+
/// Create an APFixedPoint with a value equal to that of the provided
215+
/// floating point value, in the provided target semantics. If the value is
216+
/// not able to fit in the specified fixed point semantics and the overflow
217+
/// parameter is specified, it is set to true.
218+
/// For NaN, the Overflow flag is always set. For +inf and -inf, if the
219+
/// semantic is saturating, the value saturates. Otherwise, the Overflow flag
220+
/// is set.
221+
static APFixedPoint getFromFloatValue(const APFloat &Value,
222+
const FixedPointSemantics &DstFXSema,
223+
bool *Overflow = nullptr);
224+
197225
private:
198226
APSInt Val;
199227
FixedPointSemantics Sema;
@@ -204,6 +232,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) {
204232
return OS;
205233
}
206234

207-
} // namespace llvm
235+
} // namespace llvm
208236

209237
#endif

llvm/lib/Support/APFixedPoint.cpp

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm/ADT/APFixedPoint.h"
15+
#include "llvm/ADT/APFloat.h"
1516

1617
namespace llvm {
1718

@@ -124,6 +125,29 @@ APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
124125
return APFixedPoint(Val, Sema);
125126
}
126127

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+
127151
FixedPointSemantics FixedPointSemantics::getCommonSemantics(
128152
const FixedPointSemantics &Other) const {
129153
unsigned CommonScale = std::max(getScale(), Other.getScale());
@@ -417,6 +441,54 @@ APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
417441
return Result.extOrTrunc(DstWidth);
418442
}
419443

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+
420492
APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
421493
const FixedPointSemantics &DstFXSema,
422494
bool *Overflow) {
@@ -425,4 +497,78 @@ APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value,
425497
return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
426498
}
427499

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

Comments
 (0)