Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Support/APFixedPoint.cpp
35232 views
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
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
73
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
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
127
APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
128
auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
129
return APFixedPoint(Val, Sema);
130
}
131
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
138
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
161
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
187
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
211
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
235
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
292
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
353
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
387
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
427
void APFixedPoint::print(raw_ostream &OS) const {
428
OS << "APFixedPoint(" << toString() << ", {";
429
Sema.print(OS);
430
OS << "})";
431
}
432
LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); }
433
434
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
452
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
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
493
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
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
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
613