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