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 uint32_t FixedPointSemantics::toOpaqueInt() const { 33 return llvm::bit_cast<uint32_t>(*this); 34 } 35 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; 40 } 41 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; 48 49 if (RelativeUpscale > 0) 50 NewVal = NewVal.extend(NewVal.getBitWidth() + RelativeUpscale); 51 NewVal = NewVal.relativeShl(RelativeUpscale); 52 53 auto Mask = APInt::getBitsSetFrom( 54 NewVal.getBitWidth(), 55 std::min(DstSema.getIntegralBits() - DstSema.getLsbWeight(), 56 NewVal.getBitWidth())); 57 APInt Masked(NewVal & Mask); 58 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; 66 } 67 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; 76 } 77 78 NewVal = NewVal.extOrTrunc(DstSema.getWidth()); 79 NewVal.setIsSigned(DstSema.isSigned()); 80 return APFixedPoint(NewVal, DstSema); 81 } 82 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(); 88 89 int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight()); 90 int CommonMsb = std::max(getMsbWeight(), Other.getMsbWeight()); 91 unsigned CommonWidth = CommonMsb - CommonLsb + 1; 92 93 ThisVal = ThisVal.extOrTrunc(CommonWidth); 94 OtherVal = OtherVal.extOrTrunc(CommonWidth); 95 96 ThisVal = ThisVal.shl(getLsbWeight() - CommonLsb); 97 OtherVal = OtherVal.shl(Other.getLsbWeight() - CommonLsb); 98 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; 124 } 125 126 return 0; 127 } 128 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); 135 } 136 137 APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) { 138 auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()); 139 return APFixedPoint(Val, Sema); 140 } 141 142 APFixedPoint APFixedPoint::getEpsilon(const FixedPointSemantics &Sema) { 143 APSInt Val(Sema.getWidth(), !Sema.isSigned()); 144 Val.setBit(/*BitPosition=*/0); 145 return APFixedPoint(Val, Sema); 146 } 147 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. 153 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. 157 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); 164 165 APSInt MinInt = APFixedPoint::getMin(*this).getValue(); 166 Status = F.convertFromAPInt(MinInt, MinInt.isSigned(), 167 APFloat::rmNearestTiesToAway); 168 return !(Status & APFloat::opOverflow); 169 } 170 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; 177 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; 185 } 186 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++; 192 193 return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned, 194 ResultIsSaturated, ResultHasUnsignedPadding); 195 } 196 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; 205 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); 213 } 214 215 if (Overflow) 216 *Overflow = Overflowed; 217 218 return APFixedPoint(Result, CommonFXSema); 219 } 220 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; 229 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); 237 } 238 239 if (Overflow) 240 *Overflow = Overflowed; 241 242 return APFixedPoint(Result, CommonFXSema); 243 } 244 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; 253 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); 262 } 263 264 // Perform the full multiplication and downscale to get the same scale. 265 // 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()); 280 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; 294 } 295 296 if (Overflow) 297 *Overflow = Overflowed; 298 299 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), 300 CommonFXSema); 301 } 302 303 APFixedPoint APFixedPoint::div(const APFixedPoint &Other, 304 bool *Overflow) const { 305 auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 306 APFixedPoint ConvertedThis = convert(CommonFXSema); 307 APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 308 APSInt ThisVal = ConvertedThis.getValue(); 309 APSInt OtherVal = ConvertedOther.getValue(); 310 bool Overflowed = false; 311 312 // Widen the LHS and RHS so we can perform a full division. 313 // Also make sure that there will be enough space for the shift below to not 314 // overflow 315 unsigned Wide = 316 CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0); 317 if (CommonFXSema.isSigned()) { 318 ThisVal = ThisVal.sext(Wide); 319 OtherVal = OtherVal.sext(Wide); 320 } else { 321 ThisVal = ThisVal.zext(Wide); 322 OtherVal = OtherVal.zext(Wide); 323 } 324 325 // Upscale to compensate for the loss of precision from division, and 326 // perform the full division. 327 if (CommonFXSema.getLsbWeight() < 0) 328 ThisVal = ThisVal.shl(-CommonFXSema.getLsbWeight()); 329 else if (CommonFXSema.getLsbWeight() > 0) 330 OtherVal = OtherVal.shl(CommonFXSema.getLsbWeight()); 331 APSInt Result; 332 if (CommonFXSema.isSigned()) { 333 APInt Rem; 334 APInt::sdivrem(ThisVal, OtherVal, Result, Rem); 335 // If the quotient is negative and the remainder is nonzero, round 336 // towards negative infinity by subtracting epsilon from the result. 337 if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero()) 338 Result = Result - 1; 339 } else { 340 Result = ThisVal.udiv(OtherVal); 341 } 342 Result.setIsSigned(CommonFXSema.isSigned()); 343 344 // If our result lies outside of the representative range of the common 345 // semantic, we either have overflow or saturation. 346 APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() 347 .extOrTrunc(Wide); 348 APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() 349 .extOrTrunc(Wide); 350 if (CommonFXSema.isSaturated()) { 351 if (Result < Min) 352 Result = Min; 353 else if (Result > Max) 354 Result = Max; 355 } else { 356 Overflowed = Result < Min || Result > Max; 357 } 358 359 if (Overflow) 360 *Overflow = Overflowed; 361 362 return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), 363 CommonFXSema); 364 } 365 366 APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const { 367 APSInt ThisVal = Val; 368 bool Overflowed = false; 369 370 // Widen the LHS. 371 unsigned Wide = Sema.getWidth() * 2; 372 if (Sema.isSigned()) 373 ThisVal = ThisVal.sext(Wide); 374 else 375 ThisVal = ThisVal.zext(Wide); 376 377 // Clamp the shift amount at the original width, and perform the shift. 378 Amt = std::min(Amt, ThisVal.getBitWidth()); 379 APSInt Result = ThisVal << Amt; 380 Result.setIsSigned(Sema.isSigned()); 381 382 // If our result lies outside of the representative range of the 383 // semantic, we either have overflow or saturation. 384 APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide); 385 APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide); 386 if (Sema.isSaturated()) { 387 if (Result < Min) 388 Result = Min; 389 else if (Result > Max) 390 Result = Max; 391 } else { 392 Overflowed = Result < Min || Result > Max; 393 } 394 395 if (Overflow) 396 *Overflow = Overflowed; 397 398 return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema); 399 } 400 401 void APFixedPoint::toString(SmallVectorImpl<char> &Str) const { 402 APSInt Val = getValue(); 403 int Lsb = getLsbWeight(); 404 int OrigWidth = getWidth(); 405 406 if (Lsb >= 0) { 407 APSInt IntPart = Val; 408 IntPart = IntPart.extend(IntPart.getBitWidth() + Lsb); 409 IntPart <<= Lsb; 410 IntPart.toString(Str, /*Radix=*/10); 411 Str.push_back('.'); 412 Str.push_back('0'); 413 return; 414 } 415 416 if (Val.isSigned() && Val.isNegative()) { 417 Val = -Val; 418 Val.setIsUnsigned(true); 419 Str.push_back('-'); 420 } 421 422 int Scale = -getLsbWeight(); 423 APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0); 424 425 // Add 4 digits to hold the value after multiplying 10 (the radix) 426 unsigned Width = std::max(OrigWidth, Scale) + 4; 427 APInt FractPart = Val.zextOrTrunc(Scale).zext(Width); 428 APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width); 429 APInt RadixInt = APInt(Width, 10); 430 431 IntPart.toString(Str, /*Radix=*/10); 432 Str.push_back('.'); 433 do { 434 (FractPart * RadixInt) 435 .lshr(Scale) 436 .toString(Str, /*Radix=*/10, Val.isSigned()); 437 FractPart = (FractPart * RadixInt) & FractPartMask; 438 } while (FractPart != 0); 439 } 440 441 void APFixedPoint::print(raw_ostream &OS) const { 442 OS << "APFixedPoint(" << toString() << ", {"; 443 Sema.print(OS); 444 OS << "})"; 445 } 446 447 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 448 LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); } 449 #endif 450 451 APFixedPoint APFixedPoint::negate(bool *Overflow) const { 452 if (!isSaturated()) { 453 if (Overflow) 454 *Overflow = 455 (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue()); 456 return APFixedPoint(-Val, Sema); 457 } 458 459 // We never overflow for saturation 460 if (Overflow) 461 *Overflow = false; 462 463 if (isSigned()) 464 return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema); 465 else 466 return APFixedPoint(Sema); 467 } 468 469 APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign, 470 bool *Overflow) const { 471 APSInt Result = getIntPart(); 472 unsigned SrcWidth = getWidth(); 473 474 APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign); 475 APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign); 476 477 if (SrcWidth < DstWidth) { 478 Result = Result.extend(DstWidth); 479 } else if (SrcWidth > DstWidth) { 480 DstMin = DstMin.extend(SrcWidth); 481 DstMax = DstMax.extend(SrcWidth); 482 } 483 484 if (Overflow) { 485 if (Result.isSigned() && !DstSign) { 486 *Overflow = Result.isNegative() || Result.ugt(DstMax); 487 } else if (Result.isUnsigned() && DstSign) { 488 *Overflow = Result.ugt(DstMax); 489 } else { 490 *Overflow = Result < DstMin || Result > DstMax; 491 } 492 } 493 494 Result.setIsSigned(DstSign); 495 return Result.extOrTrunc(DstWidth); 496 } 497 498 const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) { 499 if (S == &APFloat::BFloat()) 500 return &APFloat::IEEEdouble(); 501 else if (S == &APFloat::IEEEhalf()) 502 return &APFloat::IEEEsingle(); 503 else if (S == &APFloat::IEEEsingle()) 504 return &APFloat::IEEEdouble(); 505 else if (S == &APFloat::IEEEdouble()) 506 return &APFloat::IEEEquad(); 507 llvm_unreachable("Could not promote float type!"); 508 } 509 510 APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const { 511 // For some operations, rounding mode has an effect on the result, while 512 // other operations are lossless and should never result in rounding. 513 // To signify which these operations are, we define two rounding modes here. 514 APFloat::roundingMode RM = APFloat::rmNearestTiesToEven; 515 APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; 516 517 // Make sure that we are operating in a type that works with this fixed-point 518 // semantic. 519 const fltSemantics *OpSema = &FloatSema; 520 while (!Sema.fitsInFloatSemantics(*OpSema)) 521 OpSema = promoteFloatSemantics(OpSema); 522 523 // Convert the fixed point value bits as an integer. If the floating point 524 // value does not have the required precision, we will round according to the 525 // given mode. 526 APFloat Flt(*OpSema); 527 APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM); 528 529 // If we cared about checking for precision loss, we could look at this 530 // status. 531 (void)S; 532 533 // Scale down the integer value in the float to match the correct scaling 534 // factor. 535 APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight())); 536 bool Ignored; 537 ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 538 Flt.multiply(ScaleFactor, LosslessRM); 539 540 if (OpSema != &FloatSema) 541 Flt.convert(FloatSema, RM, &Ignored); 542 543 return Flt; 544 } 545 546 APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value, 547 const FixedPointSemantics &DstFXSema, 548 bool *Overflow) { 549 FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics( 550 Value.getBitWidth(), Value.isSigned()); 551 return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow); 552 } 553 554 APFixedPoint 555 APFixedPoint::getFromFloatValue(const APFloat &Value, 556 const FixedPointSemantics &DstFXSema, 557 bool *Overflow) { 558 // For some operations, rounding mode has an effect on the result, while 559 // other operations are lossless and should never result in rounding. 560 // To signify which these operations are, we define two rounding modes here, 561 // even though they are the same mode. 562 APFloat::roundingMode RM = APFloat::rmTowardZero; 563 APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; 564 565 const fltSemantics &FloatSema = Value.getSemantics(); 566 567 if (Value.isNaN()) { 568 // Handle NaN immediately. 569 if (Overflow) 570 *Overflow = true; 571 return APFixedPoint(DstFXSema); 572 } 573 574 // Make sure that we are operating in a type that works with this fixed-point 575 // semantic. 576 const fltSemantics *OpSema = &FloatSema; 577 while (!DstFXSema.fitsInFloatSemantics(*OpSema)) 578 OpSema = promoteFloatSemantics(OpSema); 579 580 APFloat Val = Value; 581 582 bool Ignored; 583 if (&FloatSema != OpSema) 584 Val.convert(*OpSema, LosslessRM, &Ignored); 585 586 // Scale up the float so that the 'fractional' part of the mantissa ends up in 587 // the integer range instead. Rounding mode is irrelevant here. 588 // It is fine if this overflows to infinity even for saturating types, 589 // since we will use floating point comparisons to check for saturation. 590 APFloat ScaleFactor(std::pow(2, -DstFXSema.getLsbWeight())); 591 ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 592 Val.multiply(ScaleFactor, LosslessRM); 593 594 // Convert to the integral representation of the value. This rounding mode 595 // is significant. 596 APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned()); 597 Val.convertToInteger(Res, RM, &Ignored); 598 599 // Round the integral value and scale back. This makes the 600 // overflow calculations below work properly. If we do not round here, 601 // we risk checking for overflow with a value that is outside the 602 // representable range of the fixed-point semantic even though no overflow 603 // would occur had we rounded first. 604 ScaleFactor = APFloat(std::pow(2, DstFXSema.getLsbWeight())); 605 ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 606 Val.roundToIntegral(RM); 607 Val.multiply(ScaleFactor, LosslessRM); 608 609 // Check for overflow/saturation by checking if the floating point value 610 // is outside the range representable by the fixed-point value. 611 APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema); 612 APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema); 613 bool Overflowed = false; 614 if (DstFXSema.isSaturated()) { 615 if (Val > FloatMax) 616 Res = getMax(DstFXSema).getValue(); 617 else if (Val < FloatMin) 618 Res = getMin(DstFXSema).getValue(); 619 } else { 620 Overflowed = Val > FloatMax || Val < FloatMin; 621 } 622 623 if (Overflow) 624 *Overflow = Overflowed; 625 626 return APFixedPoint(Res, DstFXSema); 627 } 628 629 } // namespace llvm 630