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 bool FixedPointSemantics::fitsInFloatSemantics( 133 const fltSemantics &FloatSema) const { 134 // A fixed point semantic fits in a floating point semantic if the maximum 135 // and minimum values as integers of the fixed point semantic can fit in the 136 // floating point semantic. 137 138 // If these values do not fit, then a floating point rescaling of the true 139 // maximum/minimum value will not fit either, so the floating point semantic 140 // cannot be used to perform such a rescaling. 141 142 APSInt MaxInt = APFixedPoint::getMax(*this).getValue(); 143 APFloat F(FloatSema); 144 APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(), 145 APFloat::rmNearestTiesToAway); 146 if ((Status & APFloat::opOverflow) || !isSigned()) 147 return !(Status & APFloat::opOverflow); 148 149 APSInt MinInt = APFixedPoint::getMin(*this).getValue(); 150 Status = F.convertFromAPInt(MinInt, MinInt.isSigned(), 151 APFloat::rmNearestTiesToAway); 152 return !(Status & APFloat::opOverflow); 153 } 154 155 FixedPointSemantics FixedPointSemantics::getCommonSemantics( 156 const FixedPointSemantics &Other) const { 157 int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight()); 158 int CommonMSb = std::max(getMsbWeight() - hasSignOrPaddingBit(), 159 Other.getMsbWeight() - Other.hasSignOrPaddingBit()); 160 unsigned CommonWidth = CommonMSb - CommonLsb + 1; 161 162 bool ResultIsSigned = isSigned() || Other.isSigned(); 163 bool ResultIsSaturated = isSaturated() || Other.isSaturated(); 164 bool ResultHasUnsignedPadding = false; 165 if (!ResultIsSigned) { 166 // Both are unsigned. 167 ResultHasUnsignedPadding = hasUnsignedPadding() && 168 Other.hasUnsignedPadding() && !ResultIsSaturated; 169 } 170 171 // If the result is signed, add an extra bit for the sign. Otherwise, if it is 172 // unsigned and has unsigned padding, we only need to add the extra padding 173 // bit back if we are not saturating. 174 if (ResultIsSigned || ResultHasUnsignedPadding) 175 CommonWidth++; 176 177 return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned, 178 ResultIsSaturated, ResultHasUnsignedPadding); 179 } 180 181 APFixedPoint APFixedPoint::add(const APFixedPoint &Other, 182 bool *Overflow) const { 183 auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 184 APFixedPoint ConvertedThis = convert(CommonFXSema); 185 APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 186 APSInt ThisVal = ConvertedThis.getValue(); 187 APSInt OtherVal = ConvertedOther.getValue(); 188 bool Overflowed = false; 189 190 APSInt Result; 191 if (CommonFXSema.isSaturated()) { 192 Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal) 193 : ThisVal.uadd_sat(OtherVal); 194 } else { 195 Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed) 196 : ThisVal.uadd_ov(OtherVal, Overflowed); 197 } 198 199 if (Overflow) 200 *Overflow = Overflowed; 201 202 return APFixedPoint(Result, CommonFXSema); 203 } 204 205 APFixedPoint APFixedPoint::sub(const APFixedPoint &Other, 206 bool *Overflow) const { 207 auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 208 APFixedPoint ConvertedThis = convert(CommonFXSema); 209 APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 210 APSInt ThisVal = ConvertedThis.getValue(); 211 APSInt OtherVal = ConvertedOther.getValue(); 212 bool Overflowed = false; 213 214 APSInt Result; 215 if (CommonFXSema.isSaturated()) { 216 Result = CommonFXSema.isSigned() ? ThisVal.ssub_sat(OtherVal) 217 : ThisVal.usub_sat(OtherVal); 218 } else { 219 Result = ThisVal.isSigned() ? ThisVal.ssub_ov(OtherVal, Overflowed) 220 : ThisVal.usub_ov(OtherVal, Overflowed); 221 } 222 223 if (Overflow) 224 *Overflow = Overflowed; 225 226 return APFixedPoint(Result, CommonFXSema); 227 } 228 229 APFixedPoint APFixedPoint::mul(const APFixedPoint &Other, 230 bool *Overflow) const { 231 auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 232 APFixedPoint ConvertedThis = convert(CommonFXSema); 233 APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 234 APSInt ThisVal = ConvertedThis.getValue(); 235 APSInt OtherVal = ConvertedOther.getValue(); 236 bool Overflowed = false; 237 238 // Widen the LHS and RHS so we can perform a full multiplication. 239 unsigned Wide = CommonFXSema.getWidth() * 2; 240 if (CommonFXSema.isSigned()) { 241 ThisVal = ThisVal.sext(Wide); 242 OtherVal = OtherVal.sext(Wide); 243 } else { 244 ThisVal = ThisVal.zext(Wide); 245 OtherVal = OtherVal.zext(Wide); 246 } 247 248 // Perform the full multiplication and downscale to get the same scale. 249 // 250 // Note that the right shifts here perform an implicit downwards rounding. 251 // This rounding could discard bits that would technically place the result 252 // outside the representable range. We interpret the spec as allowing us to 253 // perform the rounding step first, avoiding the overflow case that would 254 // arise. 255 APSInt Result; 256 if (CommonFXSema.isSigned()) 257 Result = ThisVal.smul_ov(OtherVal, Overflowed) 258 .relativeAShl(CommonFXSema.getLsbWeight()); 259 else 260 Result = ThisVal.umul_ov(OtherVal, Overflowed) 261 .relativeLShl(CommonFXSema.getLsbWeight()); 262 assert(!Overflowed && "Full multiplication cannot overflow!"); 263 Result.setIsSigned(CommonFXSema.isSigned()); 264 265 // If our result lies outside of the representative range of the common 266 // semantic, we either have overflow or saturation. 267 APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() 268 .extOrTrunc(Wide); 269 APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() 270 .extOrTrunc(Wide); 271 if (CommonFXSema.isSaturated()) { 272 if (Result < Min) 273 Result = Min; 274 else if (Result > Max) 275 Result = Max; 276 } else 277 Overflowed = Result < Min || Result > Max; 278 279 if (Overflow) 280 *Overflow = Overflowed; 281 282 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), 283 CommonFXSema); 284 } 285 286 APFixedPoint APFixedPoint::div(const APFixedPoint &Other, 287 bool *Overflow) const { 288 auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 289 APFixedPoint ConvertedThis = convert(CommonFXSema); 290 APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 291 APSInt ThisVal = ConvertedThis.getValue(); 292 APSInt OtherVal = ConvertedOther.getValue(); 293 bool Overflowed = false; 294 295 // Widen the LHS and RHS so we can perform a full division. 296 // Also make sure that there will be enough space for the shift below to not 297 // overflow 298 unsigned Wide = 299 CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0); 300 if (CommonFXSema.isSigned()) { 301 ThisVal = ThisVal.sext(Wide); 302 OtherVal = OtherVal.sext(Wide); 303 } else { 304 ThisVal = ThisVal.zext(Wide); 305 OtherVal = OtherVal.zext(Wide); 306 } 307 308 // Upscale to compensate for the loss of precision from division, and 309 // perform the full division. 310 if (CommonFXSema.getLsbWeight() < 0) 311 ThisVal = ThisVal.shl(-CommonFXSema.getLsbWeight()); 312 else if (CommonFXSema.getLsbWeight() > 0) 313 OtherVal = OtherVal.shl(CommonFXSema.getLsbWeight()); 314 APSInt Result; 315 if (CommonFXSema.isSigned()) { 316 APInt Rem; 317 APInt::sdivrem(ThisVal, OtherVal, Result, Rem); 318 // If the quotient is negative and the remainder is nonzero, round 319 // towards negative infinity by subtracting epsilon from the result. 320 if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero()) 321 Result = Result - 1; 322 } else 323 Result = ThisVal.udiv(OtherVal); 324 Result.setIsSigned(CommonFXSema.isSigned()); 325 326 // If our result lies outside of the representative range of the common 327 // semantic, we either have overflow or saturation. 328 APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() 329 .extOrTrunc(Wide); 330 APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() 331 .extOrTrunc(Wide); 332 if (CommonFXSema.isSaturated()) { 333 if (Result < Min) 334 Result = Min; 335 else if (Result > Max) 336 Result = Max; 337 } else 338 Overflowed = Result < Min || Result > Max; 339 340 if (Overflow) 341 *Overflow = Overflowed; 342 343 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), 344 CommonFXSema); 345 } 346 347 APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const { 348 APSInt ThisVal = Val; 349 bool Overflowed = false; 350 351 // Widen the LHS. 352 unsigned Wide = Sema.getWidth() * 2; 353 if (Sema.isSigned()) 354 ThisVal = ThisVal.sext(Wide); 355 else 356 ThisVal = ThisVal.zext(Wide); 357 358 // Clamp the shift amount at the original width, and perform the shift. 359 Amt = std::min(Amt, ThisVal.getBitWidth()); 360 APSInt Result = ThisVal << Amt; 361 Result.setIsSigned(Sema.isSigned()); 362 363 // If our result lies outside of the representative range of the 364 // semantic, we either have overflow or saturation. 365 APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide); 366 APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide); 367 if (Sema.isSaturated()) { 368 if (Result < Min) 369 Result = Min; 370 else if (Result > Max) 371 Result = Max; 372 } else 373 Overflowed = Result < Min || Result > Max; 374 375 if (Overflow) 376 *Overflow = Overflowed; 377 378 return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema); 379 } 380 381 void APFixedPoint::toString(SmallVectorImpl<char> &Str) const { 382 APSInt Val = getValue(); 383 int Lsb = getLsbWeight(); 384 int OrigWidth = getWidth(); 385 386 if (Lsb >= 0) { 387 APSInt IntPart = Val; 388 IntPart = IntPart.extend(IntPart.getBitWidth() + Lsb); 389 IntPart <<= Lsb; 390 IntPart.toString(Str, /*Radix=*/10); 391 Str.push_back('.'); 392 Str.push_back('0'); 393 return; 394 } 395 396 if (Val.isSigned() && Val.isNegative()) { 397 Val = -Val; 398 Val.setIsUnsigned(true); 399 Str.push_back('-'); 400 } 401 402 int Scale = -getLsbWeight(); 403 APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0); 404 405 // Add 4 digits to hold the value after multiplying 10 (the radix) 406 unsigned Width = std::max(OrigWidth, Scale) + 4; 407 APInt FractPart = Val.zextOrTrunc(Scale).zext(Width); 408 APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width); 409 APInt RadixInt = APInt(Width, 10); 410 411 IntPart.toString(Str, /*Radix=*/10); 412 Str.push_back('.'); 413 do { 414 (FractPart * RadixInt) 415 .lshr(Scale) 416 .toString(Str, /*Radix=*/10, Val.isSigned()); 417 FractPart = (FractPart * RadixInt) & FractPartMask; 418 } while (FractPart != 0); 419 } 420 421 void APFixedPoint::print(raw_ostream &OS) const { 422 OS << "APFixedPoint(" << toString() << ", {"; 423 Sema.print(OS); 424 OS << "})"; 425 } 426 LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); } 427 428 APFixedPoint APFixedPoint::negate(bool *Overflow) const { 429 if (!isSaturated()) { 430 if (Overflow) 431 *Overflow = 432 (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue()); 433 return APFixedPoint(-Val, Sema); 434 } 435 436 // We never overflow for saturation 437 if (Overflow) 438 *Overflow = false; 439 440 if (isSigned()) 441 return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema); 442 else 443 return APFixedPoint(Sema); 444 } 445 446 APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign, 447 bool *Overflow) const { 448 APSInt Result = getIntPart(); 449 unsigned SrcWidth = getWidth(); 450 451 APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign); 452 APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign); 453 454 if (SrcWidth < DstWidth) { 455 Result = Result.extend(DstWidth); 456 } else if (SrcWidth > DstWidth) { 457 DstMin = DstMin.extend(SrcWidth); 458 DstMax = DstMax.extend(SrcWidth); 459 } 460 461 if (Overflow) { 462 if (Result.isSigned() && !DstSign) { 463 *Overflow = Result.isNegative() || Result.ugt(DstMax); 464 } else if (Result.isUnsigned() && DstSign) { 465 *Overflow = Result.ugt(DstMax); 466 } else { 467 *Overflow = Result < DstMin || Result > DstMax; 468 } 469 } 470 471 Result.setIsSigned(DstSign); 472 return Result.extOrTrunc(DstWidth); 473 } 474 475 const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) { 476 if (S == &APFloat::BFloat()) 477 return &APFloat::IEEEdouble(); 478 else if (S == &APFloat::IEEEhalf()) 479 return &APFloat::IEEEsingle(); 480 else if (S == &APFloat::IEEEsingle()) 481 return &APFloat::IEEEdouble(); 482 else if (S == &APFloat::IEEEdouble()) 483 return &APFloat::IEEEquad(); 484 llvm_unreachable("Could not promote float type!"); 485 } 486 487 APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const { 488 // For some operations, rounding mode has an effect on the result, while 489 // other operations are lossless and should never result in rounding. 490 // To signify which these operations are, we define two rounding modes here. 491 APFloat::roundingMode RM = APFloat::rmNearestTiesToEven; 492 APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; 493 494 // Make sure that we are operating in a type that works with this fixed-point 495 // semantic. 496 const fltSemantics *OpSema = &FloatSema; 497 while (!Sema.fitsInFloatSemantics(*OpSema)) 498 OpSema = promoteFloatSemantics(OpSema); 499 500 // Convert the fixed point value bits as an integer. If the floating point 501 // value does not have the required precision, we will round according to the 502 // given mode. 503 APFloat Flt(*OpSema); 504 APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM); 505 506 // If we cared about checking for precision loss, we could look at this 507 // status. 508 (void)S; 509 510 // Scale down the integer value in the float to match the correct scaling 511 // factor. 512 APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight())); 513 bool Ignored; 514 ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 515 Flt.multiply(ScaleFactor, LosslessRM); 516 517 if (OpSema != &FloatSema) 518 Flt.convert(FloatSema, RM, &Ignored); 519 520 return Flt; 521 } 522 523 APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value, 524 const FixedPointSemantics &DstFXSema, 525 bool *Overflow) { 526 FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics( 527 Value.getBitWidth(), Value.isSigned()); 528 return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow); 529 } 530 531 APFixedPoint 532 APFixedPoint::getFromFloatValue(const APFloat &Value, 533 const FixedPointSemantics &DstFXSema, 534 bool *Overflow) { 535 // For some operations, rounding mode has an effect on the result, while 536 // other operations are lossless and should never result in rounding. 537 // To signify which these operations are, we define two rounding modes here, 538 // even though they are the same mode. 539 APFloat::roundingMode RM = APFloat::rmTowardZero; 540 APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; 541 542 const fltSemantics &FloatSema = Value.getSemantics(); 543 544 if (Value.isNaN()) { 545 // Handle NaN immediately. 546 if (Overflow) 547 *Overflow = true; 548 return APFixedPoint(DstFXSema); 549 } 550 551 // Make sure that we are operating in a type that works with this fixed-point 552 // semantic. 553 const fltSemantics *OpSema = &FloatSema; 554 while (!DstFXSema.fitsInFloatSemantics(*OpSema)) 555 OpSema = promoteFloatSemantics(OpSema); 556 557 APFloat Val = Value; 558 559 bool Ignored; 560 if (&FloatSema != OpSema) 561 Val.convert(*OpSema, LosslessRM, &Ignored); 562 563 // Scale up the float so that the 'fractional' part of the mantissa ends up in 564 // the integer range instead. Rounding mode is irrelevant here. 565 // It is fine if this overflows to infinity even for saturating types, 566 // since we will use floating point comparisons to check for saturation. 567 APFloat ScaleFactor(std::pow(2, -DstFXSema.getLsbWeight())); 568 ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 569 Val.multiply(ScaleFactor, LosslessRM); 570 571 // Convert to the integral representation of the value. This rounding mode 572 // is significant. 573 APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned()); 574 Val.convertToInteger(Res, RM, &Ignored); 575 576 // Round the integral value and scale back. This makes the 577 // overflow calculations below work properly. If we do not round here, 578 // we risk checking for overflow with a value that is outside the 579 // representable range of the fixed-point semantic even though no overflow 580 // would occur had we rounded first. 581 ScaleFactor = APFloat(std::pow(2, DstFXSema.getLsbWeight())); 582 ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 583 Val.roundToIntegral(RM); 584 Val.multiply(ScaleFactor, LosslessRM); 585 586 // Check for overflow/saturation by checking if the floating point value 587 // is outside the range representable by the fixed-point value. 588 APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema); 589 APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema); 590 bool Overflowed = false; 591 if (DstFXSema.isSaturated()) { 592 if (Val > FloatMax) 593 Res = getMax(DstFXSema).getValue(); 594 else if (Val < FloatMin) 595 Res = getMin(DstFXSema).getValue(); 596 } else 597 Overflowed = Val > FloatMax || Val < FloatMin; 598 599 if (Overflow) 600 *Overflow = Overflowed; 601 602 return APFixedPoint(Res, DstFXSema); 603 } 604 605 } // namespace llvm 606