1e8d8bef9SDimitry Andric //===- APFixedPoint.cpp - Fixed point constant handling ---------*- C++ -*-===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric /// \file 10e8d8bef9SDimitry Andric /// Defines the implementation for the fixed point number interface. 11e8d8bef9SDimitry Andric // 12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13e8d8bef9SDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/ADT/APFixedPoint.h" 15e8d8bef9SDimitry Andric #include "llvm/ADT/APFloat.h" 16e8d8bef9SDimitry Andric 17bdd1243dSDimitry Andric #include <cmath> 18bdd1243dSDimitry Andric 19e8d8bef9SDimitry Andric namespace llvm { 20e8d8bef9SDimitry Andric 21bdd1243dSDimitry Andric void FixedPointSemantics::print(llvm::raw_ostream &OS) const { 22bdd1243dSDimitry Andric OS << "width=" << getWidth() << ", "; 23bdd1243dSDimitry Andric if (isValidLegacySema()) 24bdd1243dSDimitry Andric OS << "scale=" << getScale() << ", "; 25bdd1243dSDimitry Andric OS << "msb=" << getMsbWeight() << ", "; 26bdd1243dSDimitry Andric OS << "lsb=" << getLsbWeight() << ", "; 27bdd1243dSDimitry Andric OS << "IsSigned=" << IsSigned << ", "; 28bdd1243dSDimitry Andric OS << "HasUnsignedPadding=" << HasUnsignedPadding << ", "; 29bdd1243dSDimitry Andric OS << "IsSaturated=" << IsSaturated; 30bdd1243dSDimitry Andric } 31bdd1243dSDimitry Andric 32e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema, 33e8d8bef9SDimitry Andric bool *Overflow) const { 34e8d8bef9SDimitry Andric APSInt NewVal = Val; 35bdd1243dSDimitry Andric int RelativeUpscale = getLsbWeight() - DstSema.getLsbWeight(); 36e8d8bef9SDimitry Andric if (Overflow) 37e8d8bef9SDimitry Andric *Overflow = false; 38e8d8bef9SDimitry Andric 39bdd1243dSDimitry Andric if (RelativeUpscale > 0) 40bdd1243dSDimitry Andric NewVal = NewVal.extend(NewVal.getBitWidth() + RelativeUpscale); 41bdd1243dSDimitry Andric NewVal = NewVal.relativeShl(RelativeUpscale); 42e8d8bef9SDimitry Andric 43e8d8bef9SDimitry Andric auto Mask = APInt::getBitsSetFrom( 44e8d8bef9SDimitry Andric NewVal.getBitWidth(), 45bdd1243dSDimitry Andric std::min(DstSema.getIntegralBits() - DstSema.getLsbWeight(), 46bdd1243dSDimitry Andric NewVal.getBitWidth())); 47e8d8bef9SDimitry Andric APInt Masked(NewVal & Mask); 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric // Change in the bits above the sign 50e8d8bef9SDimitry Andric if (!(Masked == Mask || Masked == 0)) { 51e8d8bef9SDimitry Andric // Found overflow in the bits above the sign 52e8d8bef9SDimitry Andric if (DstSema.isSaturated()) 53e8d8bef9SDimitry Andric NewVal = NewVal.isNegative() ? Mask : ~Mask; 54e8d8bef9SDimitry Andric else if (Overflow) 55e8d8bef9SDimitry Andric *Overflow = true; 56e8d8bef9SDimitry Andric } 57e8d8bef9SDimitry Andric 58e8d8bef9SDimitry Andric // If the dst semantics are unsigned, but our value is signed and negative, we 59e8d8bef9SDimitry Andric // clamp to zero. 60e8d8bef9SDimitry Andric if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) { 61e8d8bef9SDimitry Andric // Found negative overflow for unsigned result 62e8d8bef9SDimitry Andric if (DstSema.isSaturated()) 63e8d8bef9SDimitry Andric NewVal = 0; 64e8d8bef9SDimitry Andric else if (Overflow) 65e8d8bef9SDimitry Andric *Overflow = true; 66e8d8bef9SDimitry Andric } 67e8d8bef9SDimitry Andric 68bdd1243dSDimitry Andric NewVal = NewVal.extOrTrunc(DstSema.getWidth()); 69e8d8bef9SDimitry Andric NewVal.setIsSigned(DstSema.isSigned()); 70e8d8bef9SDimitry Andric return APFixedPoint(NewVal, DstSema); 71e8d8bef9SDimitry Andric } 72e8d8bef9SDimitry Andric 73e8d8bef9SDimitry Andric int APFixedPoint::compare(const APFixedPoint &Other) const { 74e8d8bef9SDimitry Andric APSInt ThisVal = getValue(); 75e8d8bef9SDimitry Andric APSInt OtherVal = Other.getValue(); 76e8d8bef9SDimitry Andric bool ThisSigned = Val.isSigned(); 77e8d8bef9SDimitry Andric bool OtherSigned = OtherVal.isSigned(); 78e8d8bef9SDimitry Andric 79bdd1243dSDimitry Andric int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight()); 80bdd1243dSDimitry Andric int CommonMsb = std::max(getMsbWeight(), Other.getMsbWeight()); 81bdd1243dSDimitry Andric unsigned CommonWidth = CommonMsb - CommonLsb + 1; 82e8d8bef9SDimitry Andric 83e8d8bef9SDimitry Andric ThisVal = ThisVal.extOrTrunc(CommonWidth); 84e8d8bef9SDimitry Andric OtherVal = OtherVal.extOrTrunc(CommonWidth); 85e8d8bef9SDimitry Andric 86bdd1243dSDimitry Andric ThisVal = ThisVal.shl(getLsbWeight() - CommonLsb); 87bdd1243dSDimitry Andric OtherVal = OtherVal.shl(Other.getLsbWeight() - CommonLsb); 88e8d8bef9SDimitry Andric 89e8d8bef9SDimitry Andric if (ThisSigned && OtherSigned) { 90e8d8bef9SDimitry Andric if (ThisVal.sgt(OtherVal)) 91e8d8bef9SDimitry Andric return 1; 92e8d8bef9SDimitry Andric else if (ThisVal.slt(OtherVal)) 93e8d8bef9SDimitry Andric return -1; 94e8d8bef9SDimitry Andric } else if (!ThisSigned && !OtherSigned) { 95e8d8bef9SDimitry Andric if (ThisVal.ugt(OtherVal)) 96e8d8bef9SDimitry Andric return 1; 97e8d8bef9SDimitry Andric else if (ThisVal.ult(OtherVal)) 98e8d8bef9SDimitry Andric return -1; 99e8d8bef9SDimitry Andric } else if (ThisSigned && !OtherSigned) { 100e8d8bef9SDimitry Andric if (ThisVal.isSignBitSet()) 101e8d8bef9SDimitry Andric return -1; 102e8d8bef9SDimitry Andric else if (ThisVal.ugt(OtherVal)) 103e8d8bef9SDimitry Andric return 1; 104e8d8bef9SDimitry Andric else if (ThisVal.ult(OtherVal)) 105e8d8bef9SDimitry Andric return -1; 106e8d8bef9SDimitry Andric } else { 107e8d8bef9SDimitry Andric // !ThisSigned && OtherSigned 108e8d8bef9SDimitry Andric if (OtherVal.isSignBitSet()) 109e8d8bef9SDimitry Andric return 1; 110e8d8bef9SDimitry Andric else if (ThisVal.ugt(OtherVal)) 111e8d8bef9SDimitry Andric return 1; 112e8d8bef9SDimitry Andric else if (ThisVal.ult(OtherVal)) 113e8d8bef9SDimitry Andric return -1; 114e8d8bef9SDimitry Andric } 115e8d8bef9SDimitry Andric 116e8d8bef9SDimitry Andric return 0; 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric 119e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) { 120e8d8bef9SDimitry Andric bool IsUnsigned = !Sema.isSigned(); 121e8d8bef9SDimitry Andric auto Val = APSInt::getMaxValue(Sema.getWidth(), IsUnsigned); 122e8d8bef9SDimitry Andric if (IsUnsigned && Sema.hasUnsignedPadding()) 123e8d8bef9SDimitry Andric Val = Val.lshr(1); 124e8d8bef9SDimitry Andric return APFixedPoint(Val, Sema); 125e8d8bef9SDimitry Andric } 126e8d8bef9SDimitry Andric 127e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) { 128e8d8bef9SDimitry Andric auto Val = APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()); 129e8d8bef9SDimitry Andric return APFixedPoint(Val, Sema); 130e8d8bef9SDimitry Andric } 131e8d8bef9SDimitry Andric 132*0fca6ea1SDimitry Andric APFixedPoint APFixedPoint::getEpsilon(const FixedPointSemantics &Sema) { 133*0fca6ea1SDimitry Andric APSInt Val(Sema.getWidth(), !Sema.isSigned()); 134*0fca6ea1SDimitry Andric Val.setBit(/*BitPosition=*/0); 135*0fca6ea1SDimitry Andric return APFixedPoint(Val, Sema); 136*0fca6ea1SDimitry Andric } 137*0fca6ea1SDimitry Andric 138e8d8bef9SDimitry Andric bool FixedPointSemantics::fitsInFloatSemantics( 139e8d8bef9SDimitry Andric const fltSemantics &FloatSema) const { 140e8d8bef9SDimitry Andric // A fixed point semantic fits in a floating point semantic if the maximum 141e8d8bef9SDimitry Andric // and minimum values as integers of the fixed point semantic can fit in the 142e8d8bef9SDimitry Andric // floating point semantic. 143e8d8bef9SDimitry Andric 144e8d8bef9SDimitry Andric // If these values do not fit, then a floating point rescaling of the true 145e8d8bef9SDimitry Andric // maximum/minimum value will not fit either, so the floating point semantic 146e8d8bef9SDimitry Andric // cannot be used to perform such a rescaling. 147e8d8bef9SDimitry Andric 148e8d8bef9SDimitry Andric APSInt MaxInt = APFixedPoint::getMax(*this).getValue(); 149e8d8bef9SDimitry Andric APFloat F(FloatSema); 150e8d8bef9SDimitry Andric APFloat::opStatus Status = F.convertFromAPInt(MaxInt, MaxInt.isSigned(), 151e8d8bef9SDimitry Andric APFloat::rmNearestTiesToAway); 152e8d8bef9SDimitry Andric if ((Status & APFloat::opOverflow) || !isSigned()) 153e8d8bef9SDimitry Andric return !(Status & APFloat::opOverflow); 154e8d8bef9SDimitry Andric 155e8d8bef9SDimitry Andric APSInt MinInt = APFixedPoint::getMin(*this).getValue(); 156e8d8bef9SDimitry Andric Status = F.convertFromAPInt(MinInt, MinInt.isSigned(), 157e8d8bef9SDimitry Andric APFloat::rmNearestTiesToAway); 158e8d8bef9SDimitry Andric return !(Status & APFloat::opOverflow); 159e8d8bef9SDimitry Andric } 160e8d8bef9SDimitry Andric 161e8d8bef9SDimitry Andric FixedPointSemantics FixedPointSemantics::getCommonSemantics( 162e8d8bef9SDimitry Andric const FixedPointSemantics &Other) const { 163bdd1243dSDimitry Andric int CommonLsb = std::min(getLsbWeight(), Other.getLsbWeight()); 164bdd1243dSDimitry Andric int CommonMSb = std::max(getMsbWeight() - hasSignOrPaddingBit(), 165bdd1243dSDimitry Andric Other.getMsbWeight() - Other.hasSignOrPaddingBit()); 166bdd1243dSDimitry Andric unsigned CommonWidth = CommonMSb - CommonLsb + 1; 167e8d8bef9SDimitry Andric 168e8d8bef9SDimitry Andric bool ResultIsSigned = isSigned() || Other.isSigned(); 169e8d8bef9SDimitry Andric bool ResultIsSaturated = isSaturated() || Other.isSaturated(); 170e8d8bef9SDimitry Andric bool ResultHasUnsignedPadding = false; 171e8d8bef9SDimitry Andric if (!ResultIsSigned) { 172e8d8bef9SDimitry Andric // Both are unsigned. 173e8d8bef9SDimitry Andric ResultHasUnsignedPadding = hasUnsignedPadding() && 174e8d8bef9SDimitry Andric Other.hasUnsignedPadding() && !ResultIsSaturated; 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric 177e8d8bef9SDimitry Andric // If the result is signed, add an extra bit for the sign. Otherwise, if it is 178e8d8bef9SDimitry Andric // unsigned and has unsigned padding, we only need to add the extra padding 179e8d8bef9SDimitry Andric // bit back if we are not saturating. 180e8d8bef9SDimitry Andric if (ResultIsSigned || ResultHasUnsignedPadding) 181e8d8bef9SDimitry Andric CommonWidth++; 182e8d8bef9SDimitry Andric 183bdd1243dSDimitry Andric return FixedPointSemantics(CommonWidth, Lsb{CommonLsb}, ResultIsSigned, 184e8d8bef9SDimitry Andric ResultIsSaturated, ResultHasUnsignedPadding); 185e8d8bef9SDimitry Andric } 186e8d8bef9SDimitry Andric 187e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::add(const APFixedPoint &Other, 188e8d8bef9SDimitry Andric bool *Overflow) const { 189e8d8bef9SDimitry Andric auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 190e8d8bef9SDimitry Andric APFixedPoint ConvertedThis = convert(CommonFXSema); 191e8d8bef9SDimitry Andric APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 192e8d8bef9SDimitry Andric APSInt ThisVal = ConvertedThis.getValue(); 193e8d8bef9SDimitry Andric APSInt OtherVal = ConvertedOther.getValue(); 194e8d8bef9SDimitry Andric bool Overflowed = false; 195e8d8bef9SDimitry Andric 196e8d8bef9SDimitry Andric APSInt Result; 197e8d8bef9SDimitry Andric if (CommonFXSema.isSaturated()) { 198e8d8bef9SDimitry Andric Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal) 199e8d8bef9SDimitry Andric : ThisVal.uadd_sat(OtherVal); 200e8d8bef9SDimitry Andric } else { 201e8d8bef9SDimitry Andric Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed) 202e8d8bef9SDimitry Andric : ThisVal.uadd_ov(OtherVal, Overflowed); 203e8d8bef9SDimitry Andric } 204e8d8bef9SDimitry Andric 205e8d8bef9SDimitry Andric if (Overflow) 206e8d8bef9SDimitry Andric *Overflow = Overflowed; 207e8d8bef9SDimitry Andric 208e8d8bef9SDimitry Andric return APFixedPoint(Result, CommonFXSema); 209e8d8bef9SDimitry Andric } 210e8d8bef9SDimitry Andric 211e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::sub(const APFixedPoint &Other, 212e8d8bef9SDimitry Andric bool *Overflow) const { 213e8d8bef9SDimitry Andric auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 214e8d8bef9SDimitry Andric APFixedPoint ConvertedThis = convert(CommonFXSema); 215e8d8bef9SDimitry Andric APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 216e8d8bef9SDimitry Andric APSInt ThisVal = ConvertedThis.getValue(); 217e8d8bef9SDimitry Andric APSInt OtherVal = ConvertedOther.getValue(); 218e8d8bef9SDimitry Andric bool Overflowed = false; 219e8d8bef9SDimitry Andric 220e8d8bef9SDimitry Andric APSInt Result; 221e8d8bef9SDimitry Andric if (CommonFXSema.isSaturated()) { 222e8d8bef9SDimitry Andric Result = CommonFXSema.isSigned() ? ThisVal.ssub_sat(OtherVal) 223e8d8bef9SDimitry Andric : ThisVal.usub_sat(OtherVal); 224e8d8bef9SDimitry Andric } else { 225e8d8bef9SDimitry Andric Result = ThisVal.isSigned() ? ThisVal.ssub_ov(OtherVal, Overflowed) 226e8d8bef9SDimitry Andric : ThisVal.usub_ov(OtherVal, Overflowed); 227e8d8bef9SDimitry Andric } 228e8d8bef9SDimitry Andric 229e8d8bef9SDimitry Andric if (Overflow) 230e8d8bef9SDimitry Andric *Overflow = Overflowed; 231e8d8bef9SDimitry Andric 232e8d8bef9SDimitry Andric return APFixedPoint(Result, CommonFXSema); 233e8d8bef9SDimitry Andric } 234e8d8bef9SDimitry Andric 235e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::mul(const APFixedPoint &Other, 236e8d8bef9SDimitry Andric bool *Overflow) const { 237e8d8bef9SDimitry Andric auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 238e8d8bef9SDimitry Andric APFixedPoint ConvertedThis = convert(CommonFXSema); 239e8d8bef9SDimitry Andric APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 240e8d8bef9SDimitry Andric APSInt ThisVal = ConvertedThis.getValue(); 241e8d8bef9SDimitry Andric APSInt OtherVal = ConvertedOther.getValue(); 242e8d8bef9SDimitry Andric bool Overflowed = false; 243e8d8bef9SDimitry Andric 244e8d8bef9SDimitry Andric // Widen the LHS and RHS so we can perform a full multiplication. 245e8d8bef9SDimitry Andric unsigned Wide = CommonFXSema.getWidth() * 2; 246e8d8bef9SDimitry Andric if (CommonFXSema.isSigned()) { 24781ad6265SDimitry Andric ThisVal = ThisVal.sext(Wide); 24881ad6265SDimitry Andric OtherVal = OtherVal.sext(Wide); 249e8d8bef9SDimitry Andric } else { 25081ad6265SDimitry Andric ThisVal = ThisVal.zext(Wide); 25181ad6265SDimitry Andric OtherVal = OtherVal.zext(Wide); 252e8d8bef9SDimitry Andric } 253e8d8bef9SDimitry Andric 254e8d8bef9SDimitry Andric // Perform the full multiplication and downscale to get the same scale. 255e8d8bef9SDimitry Andric // 256e8d8bef9SDimitry Andric // Note that the right shifts here perform an implicit downwards rounding. 257e8d8bef9SDimitry Andric // This rounding could discard bits that would technically place the result 258e8d8bef9SDimitry Andric // outside the representable range. We interpret the spec as allowing us to 259e8d8bef9SDimitry Andric // perform the rounding step first, avoiding the overflow case that would 260e8d8bef9SDimitry Andric // arise. 261e8d8bef9SDimitry Andric APSInt Result; 262e8d8bef9SDimitry Andric if (CommonFXSema.isSigned()) 263e8d8bef9SDimitry Andric Result = ThisVal.smul_ov(OtherVal, Overflowed) 264bdd1243dSDimitry Andric .relativeAShl(CommonFXSema.getLsbWeight()); 265e8d8bef9SDimitry Andric else 266e8d8bef9SDimitry Andric Result = ThisVal.umul_ov(OtherVal, Overflowed) 267bdd1243dSDimitry Andric .relativeLShl(CommonFXSema.getLsbWeight()); 268e8d8bef9SDimitry Andric assert(!Overflowed && "Full multiplication cannot overflow!"); 269e8d8bef9SDimitry Andric Result.setIsSigned(CommonFXSema.isSigned()); 270e8d8bef9SDimitry Andric 271e8d8bef9SDimitry Andric // If our result lies outside of the representative range of the common 272e8d8bef9SDimitry Andric // semantic, we either have overflow or saturation. 273e8d8bef9SDimitry Andric APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() 274e8d8bef9SDimitry Andric .extOrTrunc(Wide); 275e8d8bef9SDimitry Andric APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() 276e8d8bef9SDimitry Andric .extOrTrunc(Wide); 277e8d8bef9SDimitry Andric if (CommonFXSema.isSaturated()) { 278e8d8bef9SDimitry Andric if (Result < Min) 279e8d8bef9SDimitry Andric Result = Min; 280e8d8bef9SDimitry Andric else if (Result > Max) 281e8d8bef9SDimitry Andric Result = Max; 282e8d8bef9SDimitry Andric } else 283e8d8bef9SDimitry Andric Overflowed = Result < Min || Result > Max; 284e8d8bef9SDimitry Andric 285e8d8bef9SDimitry Andric if (Overflow) 286e8d8bef9SDimitry Andric *Overflow = Overflowed; 287e8d8bef9SDimitry Andric 288e8d8bef9SDimitry Andric return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), 289e8d8bef9SDimitry Andric CommonFXSema); 290e8d8bef9SDimitry Andric } 291e8d8bef9SDimitry Andric 292e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::div(const APFixedPoint &Other, 293e8d8bef9SDimitry Andric bool *Overflow) const { 294e8d8bef9SDimitry Andric auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); 295e8d8bef9SDimitry Andric APFixedPoint ConvertedThis = convert(CommonFXSema); 296e8d8bef9SDimitry Andric APFixedPoint ConvertedOther = Other.convert(CommonFXSema); 297e8d8bef9SDimitry Andric APSInt ThisVal = ConvertedThis.getValue(); 298e8d8bef9SDimitry Andric APSInt OtherVal = ConvertedOther.getValue(); 299e8d8bef9SDimitry Andric bool Overflowed = false; 300e8d8bef9SDimitry Andric 301e8d8bef9SDimitry Andric // Widen the LHS and RHS so we can perform a full division. 302bdd1243dSDimitry Andric // Also make sure that there will be enough space for the shift below to not 303bdd1243dSDimitry Andric // overflow 304bdd1243dSDimitry Andric unsigned Wide = 305bdd1243dSDimitry Andric CommonFXSema.getWidth() * 2 + std::max(-CommonFXSema.getMsbWeight(), 0); 306e8d8bef9SDimitry Andric if (CommonFXSema.isSigned()) { 30781ad6265SDimitry Andric ThisVal = ThisVal.sext(Wide); 30881ad6265SDimitry Andric OtherVal = OtherVal.sext(Wide); 309e8d8bef9SDimitry Andric } else { 31081ad6265SDimitry Andric ThisVal = ThisVal.zext(Wide); 31181ad6265SDimitry Andric OtherVal = OtherVal.zext(Wide); 312e8d8bef9SDimitry Andric } 313e8d8bef9SDimitry Andric 314e8d8bef9SDimitry Andric // Upscale to compensate for the loss of precision from division, and 315e8d8bef9SDimitry Andric // perform the full division. 316bdd1243dSDimitry Andric if (CommonFXSema.getLsbWeight() < 0) 317bdd1243dSDimitry Andric ThisVal = ThisVal.shl(-CommonFXSema.getLsbWeight()); 318bdd1243dSDimitry Andric else if (CommonFXSema.getLsbWeight() > 0) 319bdd1243dSDimitry Andric OtherVal = OtherVal.shl(CommonFXSema.getLsbWeight()); 320e8d8bef9SDimitry Andric APSInt Result; 321e8d8bef9SDimitry Andric if (CommonFXSema.isSigned()) { 322e8d8bef9SDimitry Andric APInt Rem; 323e8d8bef9SDimitry Andric APInt::sdivrem(ThisVal, OtherVal, Result, Rem); 324e8d8bef9SDimitry Andric // If the quotient is negative and the remainder is nonzero, round 325e8d8bef9SDimitry Andric // towards negative infinity by subtracting epsilon from the result. 326349cc55cSDimitry Andric if (ThisVal.isNegative() != OtherVal.isNegative() && !Rem.isZero()) 327e8d8bef9SDimitry Andric Result = Result - 1; 328e8d8bef9SDimitry Andric } else 329e8d8bef9SDimitry Andric Result = ThisVal.udiv(OtherVal); 330e8d8bef9SDimitry Andric Result.setIsSigned(CommonFXSema.isSigned()); 331e8d8bef9SDimitry Andric 332e8d8bef9SDimitry Andric // If our result lies outside of the representative range of the common 333e8d8bef9SDimitry Andric // semantic, we either have overflow or saturation. 334e8d8bef9SDimitry Andric APSInt Max = APFixedPoint::getMax(CommonFXSema).getValue() 335e8d8bef9SDimitry Andric .extOrTrunc(Wide); 336e8d8bef9SDimitry Andric APSInt Min = APFixedPoint::getMin(CommonFXSema).getValue() 337e8d8bef9SDimitry Andric .extOrTrunc(Wide); 338e8d8bef9SDimitry Andric if (CommonFXSema.isSaturated()) { 339e8d8bef9SDimitry Andric if (Result < Min) 340e8d8bef9SDimitry Andric Result = Min; 341e8d8bef9SDimitry Andric else if (Result > Max) 342e8d8bef9SDimitry Andric Result = Max; 343e8d8bef9SDimitry Andric } else 344e8d8bef9SDimitry Andric Overflowed = Result < Min || Result > Max; 345e8d8bef9SDimitry Andric 346e8d8bef9SDimitry Andric if (Overflow) 347e8d8bef9SDimitry Andric *Overflow = Overflowed; 348e8d8bef9SDimitry Andric 349e8d8bef9SDimitry Andric return APFixedPoint(Result.sextOrTrunc(CommonFXSema.getWidth()), 350e8d8bef9SDimitry Andric CommonFXSema); 351e8d8bef9SDimitry Andric } 352e8d8bef9SDimitry Andric 353e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::shl(unsigned Amt, bool *Overflow) const { 354e8d8bef9SDimitry Andric APSInt ThisVal = Val; 355e8d8bef9SDimitry Andric bool Overflowed = false; 356e8d8bef9SDimitry Andric 357e8d8bef9SDimitry Andric // Widen the LHS. 358e8d8bef9SDimitry Andric unsigned Wide = Sema.getWidth() * 2; 359e8d8bef9SDimitry Andric if (Sema.isSigned()) 36081ad6265SDimitry Andric ThisVal = ThisVal.sext(Wide); 361e8d8bef9SDimitry Andric else 36281ad6265SDimitry Andric ThisVal = ThisVal.zext(Wide); 363e8d8bef9SDimitry Andric 364e8d8bef9SDimitry Andric // Clamp the shift amount at the original width, and perform the shift. 365e8d8bef9SDimitry Andric Amt = std::min(Amt, ThisVal.getBitWidth()); 366e8d8bef9SDimitry Andric APSInt Result = ThisVal << Amt; 367e8d8bef9SDimitry Andric Result.setIsSigned(Sema.isSigned()); 368e8d8bef9SDimitry Andric 369e8d8bef9SDimitry Andric // If our result lies outside of the representative range of the 370e8d8bef9SDimitry Andric // semantic, we either have overflow or saturation. 371e8d8bef9SDimitry Andric APSInt Max = APFixedPoint::getMax(Sema).getValue().extOrTrunc(Wide); 372e8d8bef9SDimitry Andric APSInt Min = APFixedPoint::getMin(Sema).getValue().extOrTrunc(Wide); 373e8d8bef9SDimitry Andric if (Sema.isSaturated()) { 374e8d8bef9SDimitry Andric if (Result < Min) 375e8d8bef9SDimitry Andric Result = Min; 376e8d8bef9SDimitry Andric else if (Result > Max) 377e8d8bef9SDimitry Andric Result = Max; 378e8d8bef9SDimitry Andric } else 379e8d8bef9SDimitry Andric Overflowed = Result < Min || Result > Max; 380e8d8bef9SDimitry Andric 381e8d8bef9SDimitry Andric if (Overflow) 382e8d8bef9SDimitry Andric *Overflow = Overflowed; 383e8d8bef9SDimitry Andric 384e8d8bef9SDimitry Andric return APFixedPoint(Result.sextOrTrunc(Sema.getWidth()), Sema); 385e8d8bef9SDimitry Andric } 386e8d8bef9SDimitry Andric 387e8d8bef9SDimitry Andric void APFixedPoint::toString(SmallVectorImpl<char> &Str) const { 388e8d8bef9SDimitry Andric APSInt Val = getValue(); 389bdd1243dSDimitry Andric int Lsb = getLsbWeight(); 390bdd1243dSDimitry Andric int OrigWidth = getWidth(); 391e8d8bef9SDimitry Andric 392bdd1243dSDimitry Andric if (Lsb >= 0) { 393bdd1243dSDimitry Andric APSInt IntPart = Val; 394bdd1243dSDimitry Andric IntPart = IntPart.extend(IntPart.getBitWidth() + Lsb); 395bdd1243dSDimitry Andric IntPart <<= Lsb; 396bdd1243dSDimitry Andric IntPart.toString(Str, /*Radix=*/10); 397bdd1243dSDimitry Andric Str.push_back('.'); 398bdd1243dSDimitry Andric Str.push_back('0'); 399bdd1243dSDimitry Andric return; 400bdd1243dSDimitry Andric } 401bdd1243dSDimitry Andric 402bdd1243dSDimitry Andric if (Val.isSigned() && Val.isNegative()) { 403e8d8bef9SDimitry Andric Val = -Val; 404bdd1243dSDimitry Andric Val.setIsUnsigned(true); 405e8d8bef9SDimitry Andric Str.push_back('-'); 406e8d8bef9SDimitry Andric } 407e8d8bef9SDimitry Andric 408bdd1243dSDimitry Andric int Scale = -getLsbWeight(); 409bdd1243dSDimitry Andric APSInt IntPart = (OrigWidth > Scale) ? (Val >> Scale) : APSInt::get(0); 410e8d8bef9SDimitry Andric 411e8d8bef9SDimitry Andric // Add 4 digits to hold the value after multiplying 10 (the radix) 412bdd1243dSDimitry Andric unsigned Width = std::max(OrigWidth, Scale) + 4; 413e8d8bef9SDimitry Andric APInt FractPart = Val.zextOrTrunc(Scale).zext(Width); 414349cc55cSDimitry Andric APInt FractPartMask = APInt::getAllOnes(Scale).zext(Width); 415e8d8bef9SDimitry Andric APInt RadixInt = APInt(Width, 10); 416e8d8bef9SDimitry Andric 417e8d8bef9SDimitry Andric IntPart.toString(Str, /*Radix=*/10); 418e8d8bef9SDimitry Andric Str.push_back('.'); 419e8d8bef9SDimitry Andric do { 420e8d8bef9SDimitry Andric (FractPart * RadixInt) 421e8d8bef9SDimitry Andric .lshr(Scale) 422e8d8bef9SDimitry Andric .toString(Str, /*Radix=*/10, Val.isSigned()); 423e8d8bef9SDimitry Andric FractPart = (FractPart * RadixInt) & FractPartMask; 424e8d8bef9SDimitry Andric } while (FractPart != 0); 425e8d8bef9SDimitry Andric } 426e8d8bef9SDimitry Andric 427bdd1243dSDimitry Andric void APFixedPoint::print(raw_ostream &OS) const { 428bdd1243dSDimitry Andric OS << "APFixedPoint(" << toString() << ", {"; 429bdd1243dSDimitry Andric Sema.print(OS); 430bdd1243dSDimitry Andric OS << "})"; 431bdd1243dSDimitry Andric } 432bdd1243dSDimitry Andric LLVM_DUMP_METHOD void APFixedPoint::dump() const { print(llvm::errs()); } 433bdd1243dSDimitry Andric 434e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::negate(bool *Overflow) const { 435e8d8bef9SDimitry Andric if (!isSaturated()) { 436e8d8bef9SDimitry Andric if (Overflow) 437e8d8bef9SDimitry Andric *Overflow = 438e8d8bef9SDimitry Andric (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue()); 439e8d8bef9SDimitry Andric return APFixedPoint(-Val, Sema); 440e8d8bef9SDimitry Andric } 441e8d8bef9SDimitry Andric 442e8d8bef9SDimitry Andric // We never overflow for saturation 443e8d8bef9SDimitry Andric if (Overflow) 444e8d8bef9SDimitry Andric *Overflow = false; 445e8d8bef9SDimitry Andric 446e8d8bef9SDimitry Andric if (isSigned()) 447e8d8bef9SDimitry Andric return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema); 448e8d8bef9SDimitry Andric else 449e8d8bef9SDimitry Andric return APFixedPoint(Sema); 450e8d8bef9SDimitry Andric } 451e8d8bef9SDimitry Andric 452e8d8bef9SDimitry Andric APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign, 453e8d8bef9SDimitry Andric bool *Overflow) const { 454e8d8bef9SDimitry Andric APSInt Result = getIntPart(); 455e8d8bef9SDimitry Andric unsigned SrcWidth = getWidth(); 456e8d8bef9SDimitry Andric 457e8d8bef9SDimitry Andric APSInt DstMin = APSInt::getMinValue(DstWidth, !DstSign); 458e8d8bef9SDimitry Andric APSInt DstMax = APSInt::getMaxValue(DstWidth, !DstSign); 459e8d8bef9SDimitry Andric 460e8d8bef9SDimitry Andric if (SrcWidth < DstWidth) { 461e8d8bef9SDimitry Andric Result = Result.extend(DstWidth); 462e8d8bef9SDimitry Andric } else if (SrcWidth > DstWidth) { 463e8d8bef9SDimitry Andric DstMin = DstMin.extend(SrcWidth); 464e8d8bef9SDimitry Andric DstMax = DstMax.extend(SrcWidth); 465e8d8bef9SDimitry Andric } 466e8d8bef9SDimitry Andric 467e8d8bef9SDimitry Andric if (Overflow) { 468e8d8bef9SDimitry Andric if (Result.isSigned() && !DstSign) { 469e8d8bef9SDimitry Andric *Overflow = Result.isNegative() || Result.ugt(DstMax); 470e8d8bef9SDimitry Andric } else if (Result.isUnsigned() && DstSign) { 471e8d8bef9SDimitry Andric *Overflow = Result.ugt(DstMax); 472e8d8bef9SDimitry Andric } else { 473e8d8bef9SDimitry Andric *Overflow = Result < DstMin || Result > DstMax; 474e8d8bef9SDimitry Andric } 475e8d8bef9SDimitry Andric } 476e8d8bef9SDimitry Andric 477e8d8bef9SDimitry Andric Result.setIsSigned(DstSign); 478e8d8bef9SDimitry Andric return Result.extOrTrunc(DstWidth); 479e8d8bef9SDimitry Andric } 480e8d8bef9SDimitry Andric 481e8d8bef9SDimitry Andric const fltSemantics *APFixedPoint::promoteFloatSemantics(const fltSemantics *S) { 482e8d8bef9SDimitry Andric if (S == &APFloat::BFloat()) 483e8d8bef9SDimitry Andric return &APFloat::IEEEdouble(); 484e8d8bef9SDimitry Andric else if (S == &APFloat::IEEEhalf()) 485e8d8bef9SDimitry Andric return &APFloat::IEEEsingle(); 486e8d8bef9SDimitry Andric else if (S == &APFloat::IEEEsingle()) 487e8d8bef9SDimitry Andric return &APFloat::IEEEdouble(); 488e8d8bef9SDimitry Andric else if (S == &APFloat::IEEEdouble()) 489e8d8bef9SDimitry Andric return &APFloat::IEEEquad(); 490e8d8bef9SDimitry Andric llvm_unreachable("Could not promote float type!"); 491e8d8bef9SDimitry Andric } 492e8d8bef9SDimitry Andric 493e8d8bef9SDimitry Andric APFloat APFixedPoint::convertToFloat(const fltSemantics &FloatSema) const { 494e8d8bef9SDimitry Andric // For some operations, rounding mode has an effect on the result, while 495e8d8bef9SDimitry Andric // other operations are lossless and should never result in rounding. 496e8d8bef9SDimitry Andric // To signify which these operations are, we define two rounding modes here. 497e8d8bef9SDimitry Andric APFloat::roundingMode RM = APFloat::rmNearestTiesToEven; 498e8d8bef9SDimitry Andric APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; 499e8d8bef9SDimitry Andric 500e8d8bef9SDimitry Andric // Make sure that we are operating in a type that works with this fixed-point 501e8d8bef9SDimitry Andric // semantic. 502e8d8bef9SDimitry Andric const fltSemantics *OpSema = &FloatSema; 503e8d8bef9SDimitry Andric while (!Sema.fitsInFloatSemantics(*OpSema)) 504e8d8bef9SDimitry Andric OpSema = promoteFloatSemantics(OpSema); 505e8d8bef9SDimitry Andric 506e8d8bef9SDimitry Andric // Convert the fixed point value bits as an integer. If the floating point 507e8d8bef9SDimitry Andric // value does not have the required precision, we will round according to the 508e8d8bef9SDimitry Andric // given mode. 509e8d8bef9SDimitry Andric APFloat Flt(*OpSema); 510e8d8bef9SDimitry Andric APFloat::opStatus S = Flt.convertFromAPInt(Val, Sema.isSigned(), RM); 511e8d8bef9SDimitry Andric 512e8d8bef9SDimitry Andric // If we cared about checking for precision loss, we could look at this 513e8d8bef9SDimitry Andric // status. 514e8d8bef9SDimitry Andric (void)S; 515e8d8bef9SDimitry Andric 516e8d8bef9SDimitry Andric // Scale down the integer value in the float to match the correct scaling 517e8d8bef9SDimitry Andric // factor. 518bdd1243dSDimitry Andric APFloat ScaleFactor(std::pow(2, Sema.getLsbWeight())); 519e8d8bef9SDimitry Andric bool Ignored; 520e8d8bef9SDimitry Andric ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 521e8d8bef9SDimitry Andric Flt.multiply(ScaleFactor, LosslessRM); 522e8d8bef9SDimitry Andric 523e8d8bef9SDimitry Andric if (OpSema != &FloatSema) 524e8d8bef9SDimitry Andric Flt.convert(FloatSema, RM, &Ignored); 525e8d8bef9SDimitry Andric 526e8d8bef9SDimitry Andric return Flt; 527e8d8bef9SDimitry Andric } 528e8d8bef9SDimitry Andric 529e8d8bef9SDimitry Andric APFixedPoint APFixedPoint::getFromIntValue(const APSInt &Value, 530e8d8bef9SDimitry Andric const FixedPointSemantics &DstFXSema, 531e8d8bef9SDimitry Andric bool *Overflow) { 532e8d8bef9SDimitry Andric FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics( 533e8d8bef9SDimitry Andric Value.getBitWidth(), Value.isSigned()); 534e8d8bef9SDimitry Andric return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow); 535e8d8bef9SDimitry Andric } 536e8d8bef9SDimitry Andric 537e8d8bef9SDimitry Andric APFixedPoint 538e8d8bef9SDimitry Andric APFixedPoint::getFromFloatValue(const APFloat &Value, 539e8d8bef9SDimitry Andric const FixedPointSemantics &DstFXSema, 540e8d8bef9SDimitry Andric bool *Overflow) { 541e8d8bef9SDimitry Andric // For some operations, rounding mode has an effect on the result, while 542e8d8bef9SDimitry Andric // other operations are lossless and should never result in rounding. 543e8d8bef9SDimitry Andric // To signify which these operations are, we define two rounding modes here, 544e8d8bef9SDimitry Andric // even though they are the same mode. 545e8d8bef9SDimitry Andric APFloat::roundingMode RM = APFloat::rmTowardZero; 546e8d8bef9SDimitry Andric APFloat::roundingMode LosslessRM = APFloat::rmTowardZero; 547e8d8bef9SDimitry Andric 548e8d8bef9SDimitry Andric const fltSemantics &FloatSema = Value.getSemantics(); 549e8d8bef9SDimitry Andric 550e8d8bef9SDimitry Andric if (Value.isNaN()) { 551e8d8bef9SDimitry Andric // Handle NaN immediately. 552e8d8bef9SDimitry Andric if (Overflow) 553e8d8bef9SDimitry Andric *Overflow = true; 554e8d8bef9SDimitry Andric return APFixedPoint(DstFXSema); 555e8d8bef9SDimitry Andric } 556e8d8bef9SDimitry Andric 557e8d8bef9SDimitry Andric // Make sure that we are operating in a type that works with this fixed-point 558e8d8bef9SDimitry Andric // semantic. 559e8d8bef9SDimitry Andric const fltSemantics *OpSema = &FloatSema; 560e8d8bef9SDimitry Andric while (!DstFXSema.fitsInFloatSemantics(*OpSema)) 561e8d8bef9SDimitry Andric OpSema = promoteFloatSemantics(OpSema); 562e8d8bef9SDimitry Andric 563e8d8bef9SDimitry Andric APFloat Val = Value; 564e8d8bef9SDimitry Andric 565e8d8bef9SDimitry Andric bool Ignored; 566e8d8bef9SDimitry Andric if (&FloatSema != OpSema) 567e8d8bef9SDimitry Andric Val.convert(*OpSema, LosslessRM, &Ignored); 568e8d8bef9SDimitry Andric 569e8d8bef9SDimitry Andric // Scale up the float so that the 'fractional' part of the mantissa ends up in 570e8d8bef9SDimitry Andric // the integer range instead. Rounding mode is irrelevant here. 571e8d8bef9SDimitry Andric // It is fine if this overflows to infinity even for saturating types, 572e8d8bef9SDimitry Andric // since we will use floating point comparisons to check for saturation. 573bdd1243dSDimitry Andric APFloat ScaleFactor(std::pow(2, -DstFXSema.getLsbWeight())); 574e8d8bef9SDimitry Andric ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 575e8d8bef9SDimitry Andric Val.multiply(ScaleFactor, LosslessRM); 576e8d8bef9SDimitry Andric 577e8d8bef9SDimitry Andric // Convert to the integral representation of the value. This rounding mode 578e8d8bef9SDimitry Andric // is significant. 579e8d8bef9SDimitry Andric APSInt Res(DstFXSema.getWidth(), !DstFXSema.isSigned()); 580e8d8bef9SDimitry Andric Val.convertToInteger(Res, RM, &Ignored); 581e8d8bef9SDimitry Andric 582e8d8bef9SDimitry Andric // Round the integral value and scale back. This makes the 583e8d8bef9SDimitry Andric // overflow calculations below work properly. If we do not round here, 584e8d8bef9SDimitry Andric // we risk checking for overflow with a value that is outside the 585e8d8bef9SDimitry Andric // representable range of the fixed-point semantic even though no overflow 586e8d8bef9SDimitry Andric // would occur had we rounded first. 587bdd1243dSDimitry Andric ScaleFactor = APFloat(std::pow(2, DstFXSema.getLsbWeight())); 588e8d8bef9SDimitry Andric ScaleFactor.convert(*OpSema, LosslessRM, &Ignored); 589e8d8bef9SDimitry Andric Val.roundToIntegral(RM); 590e8d8bef9SDimitry Andric Val.multiply(ScaleFactor, LosslessRM); 591e8d8bef9SDimitry Andric 592e8d8bef9SDimitry Andric // Check for overflow/saturation by checking if the floating point value 593e8d8bef9SDimitry Andric // is outside the range representable by the fixed-point value. 594e8d8bef9SDimitry Andric APFloat FloatMax = getMax(DstFXSema).convertToFloat(*OpSema); 595e8d8bef9SDimitry Andric APFloat FloatMin = getMin(DstFXSema).convertToFloat(*OpSema); 596e8d8bef9SDimitry Andric bool Overflowed = false; 597e8d8bef9SDimitry Andric if (DstFXSema.isSaturated()) { 598e8d8bef9SDimitry Andric if (Val > FloatMax) 599e8d8bef9SDimitry Andric Res = getMax(DstFXSema).getValue(); 600e8d8bef9SDimitry Andric else if (Val < FloatMin) 601e8d8bef9SDimitry Andric Res = getMin(DstFXSema).getValue(); 602e8d8bef9SDimitry Andric } else 603e8d8bef9SDimitry Andric Overflowed = Val > FloatMax || Val < FloatMin; 604e8d8bef9SDimitry Andric 605e8d8bef9SDimitry Andric if (Overflow) 606e8d8bef9SDimitry Andric *Overflow = Overflowed; 607e8d8bef9SDimitry Andric 608e8d8bef9SDimitry Andric return APFixedPoint(Res, DstFXSema); 609e8d8bef9SDimitry Andric } 610e8d8bef9SDimitry Andric 611e8d8bef9SDimitry Andric } // namespace llvm 612