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