630 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// 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 19namespace llvm {20 21void 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 32uint32_t FixedPointSemantics::toOpaqueInt() const {33 return llvm::bit_cast<uint32_t>(*this);34}35 36FixedPointSemantics 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 42APFixedPoint 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 sign60 if (!(Masked == Mask || Masked == 0)) {61 // Found overflow in the bits above the sign62 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, we69 // clamp to zero.70 if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) {71 // Found negative overflow for unsigned result72 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 83int 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 && OtherSigned118 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 129APFixedPoint 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 137APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {138 auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());139 return APFixedPoint(Val, Sema);140}141 142APFixedPoint APFixedPoint::getEpsilon(const FixedPointSemantics &Sema) {143 APSInt Val(Sema.getWidth(), !Sema.isSigned());144 Val.setBit(/*BitPosition=*/0);145 return APFixedPoint(Val, Sema);146}147 148bool FixedPointSemantics::fitsInFloatSemantics(149 const fltSemantics &FloatSema) const {150 // A fixed point semantic fits in a floating point semantic if the maximum151 // and minimum values as integers of the fixed point semantic can fit in the152 // floating point semantic.153 154 // If these values do not fit, then a floating point rescaling of the true155 // maximum/minimum value will not fit either, so the floating point semantic156 // 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 171FixedPointSemantics 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 is188 // unsigned and has unsigned padding, we only need to add the extra padding189 // 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 197APFixedPoint 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 221APFixedPoint 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 245APFixedPoint 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 result268 // outside the representable range. We interpret the spec as allowing us to269 // perform the rounding step first, avoiding the overflow case that would270 // arise.271 APSInt Result;272 if (CommonFXSema.isSigned())273 Result = ThisVal.smul_ov(OtherVal, Overflowed)274 .relativeAShl(CommonFXSema.getLsbWeight());275 else276 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 common282 // 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 303APFixedPoint 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 not314 // overflow315 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, and326 // 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, round336 // 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 common345 // 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 366APFixedPoint 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 else375 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 the383 // 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 401void 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 441void 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)448LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); }449#endif450 451APFixedPoint 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 saturation460 if (Overflow)461 *Overflow = false;462 463 if (isSigned())464 return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);465 else466 return APFixedPoint(Sema);467}468 469APSInt 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 498const 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 510APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const {511 // For some operations, rounding mode has an effect on the result, while512 // 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-point518 // 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 point524 // value does not have the required precision, we will round according to the525 // 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 this530 // status.531 (void)S;532 533 // Scale down the integer value in the float to match the correct scaling534 // 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 546APFixedPoint 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 554APFixedPoint555APFixedPoint::getFromFloatValue(const APFloat &Value,556 const FixedPointSemantics &DstFXSema,557 bool *Overflow) {558 // For some operations, rounding mode has an effect on the result, while559 // 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-point575 // 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 in587 // 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 mode595 // 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 the600 // overflow calculations below work properly. If we do not round here,601 // we risk checking for overflow with a value that is outside the602 // representable range of the fixed-point semantic even though no overflow603 // 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 value610 // 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 llvm630