1 //===- APFixedPoint.h - 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 fixed point number interface. 11 /// This is a class for abstracting various operations performed on fixed point 12 /// types. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_ADT_APFIXEDPOINT_H 17 #define LLVM_ADT_APFIXEDPOINT_H 18 19 #include "llvm/ADT/APSInt.h" 20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/Support/raw_ostream.h" 22 23 namespace llvm { 24 25 class APFloat; 26 struct fltSemantics; 27 28 /// The fixed point semantics work similarly to fltSemantics. The width 29 /// specifies the whole bit width of the underlying scaled integer (with padding 30 /// if any). The scale represents the number of fractional bits in this type. 31 /// When HasUnsignedPadding is true and this type is unsigned, the first bit 32 /// in the value this represents is treated as padding. 33 class FixedPointSemantics { 34 public: FixedPointSemantics(unsigned Width,unsigned Scale,bool IsSigned,bool IsSaturated,bool HasUnsignedPadding)35 FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned, 36 bool IsSaturated, bool HasUnsignedPadding) 37 : Width(Width), Scale(Scale), IsSigned(IsSigned), 38 IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) { 39 assert(Width >= Scale && "Not enough room for the scale"); 40 assert(!(IsSigned && HasUnsignedPadding) && 41 "Cannot have unsigned padding on a signed type."); 42 } 43 getWidth()44 unsigned getWidth() const { return Width; } getScale()45 unsigned getScale() const { return Scale; } isSigned()46 bool isSigned() const { return IsSigned; } isSaturated()47 bool isSaturated() const { return IsSaturated; } hasUnsignedPadding()48 bool hasUnsignedPadding() const { return HasUnsignedPadding; } 49 setSaturated(bool Saturated)50 void setSaturated(bool Saturated) { IsSaturated = Saturated; } 51 52 /// Return the number of integral bits represented by these semantics. These 53 /// are separate from the fractional bits and do not include the sign or 54 /// padding bit. getIntegralBits()55 unsigned getIntegralBits() const { 56 if (IsSigned || (!IsSigned && HasUnsignedPadding)) 57 return Width - Scale - 1; 58 else 59 return Width - Scale; 60 } 61 62 /// Return the FixedPointSemantics that allows for calculating the full 63 /// precision semantic that can precisely represent the precision and ranges 64 /// of both input values. This does not compute the resulting semantics for a 65 /// given binary operation. 66 FixedPointSemantics 67 getCommonSemantics(const FixedPointSemantics &Other) const; 68 69 /// Returns true if this fixed-point semantic with its value bits interpreted 70 /// as an integer can fit in the given floating point semantic without 71 /// overflowing to infinity. 72 /// For example, a signed 8-bit fixed-point semantic has a maximum and 73 /// minimum integer representation of 127 and -128, respectively. If both of 74 /// these values can be represented (possibly inexactly) in the floating 75 /// point semantic without overflowing, this returns true. 76 bool fitsInFloatSemantics(const fltSemantics &FloatSema) const; 77 78 /// Return the FixedPointSemantics for an integer type. GetIntegerSemantics(unsigned Width,bool IsSigned)79 static FixedPointSemantics GetIntegerSemantics(unsigned Width, 80 bool IsSigned) { 81 return FixedPointSemantics(Width, /*Scale=*/0, IsSigned, 82 /*IsSaturated=*/false, 83 /*HasUnsignedPadding=*/false); 84 } 85 86 private: 87 unsigned Width : 16; 88 unsigned Scale : 13; 89 unsigned IsSigned : 1; 90 unsigned IsSaturated : 1; 91 unsigned HasUnsignedPadding : 1; 92 }; 93 94 /// The APFixedPoint class works similarly to APInt/APSInt in that it is a 95 /// functional replacement for a scaled integer. It is meant to replicate the 96 /// fixed point types proposed in ISO/IEC JTC1 SC22 WG14 N1169. The class carries 97 /// info about the fixed point type's width, sign, scale, and saturation, and 98 /// provides different operations that would normally be performed on fixed point 99 /// types. 100 class APFixedPoint { 101 public: APFixedPoint(const APInt & Val,const FixedPointSemantics & Sema)102 APFixedPoint(const APInt &Val, const FixedPointSemantics &Sema) 103 : Val(Val, !Sema.isSigned()), Sema(Sema) { 104 assert(Val.getBitWidth() == Sema.getWidth() && 105 "The value should have a bit width that matches the Sema width"); 106 } 107 APFixedPoint(uint64_t Val,const FixedPointSemantics & Sema)108 APFixedPoint(uint64_t Val, const FixedPointSemantics &Sema) 109 : APFixedPoint(APInt(Sema.getWidth(), Val, Sema.isSigned()), Sema) {} 110 111 // Zero initialization. APFixedPoint(const FixedPointSemantics & Sema)112 APFixedPoint(const FixedPointSemantics &Sema) : APFixedPoint(0, Sema) {} 113 getValue()114 APSInt getValue() const { return APSInt(Val, !Sema.isSigned()); } getWidth()115 inline unsigned getWidth() const { return Sema.getWidth(); } getScale()116 inline unsigned getScale() const { return Sema.getScale(); } isSaturated()117 inline bool isSaturated() const { return Sema.isSaturated(); } isSigned()118 inline bool isSigned() const { return Sema.isSigned(); } hasPadding()119 inline bool hasPadding() const { return Sema.hasUnsignedPadding(); } getSemantics()120 FixedPointSemantics getSemantics() const { return Sema; } 121 getBoolValue()122 bool getBoolValue() const { return Val.getBoolValue(); } 123 124 // Convert this number to match the semantics provided. If the overflow 125 // parameter is provided, set this value to true or false to indicate if this 126 // operation results in an overflow. 127 APFixedPoint convert(const FixedPointSemantics &DstSema, 128 bool *Overflow = nullptr) const; 129 130 // Perform binary operations on a fixed point type. The resulting fixed point 131 // value will be in the common, full precision semantics that can represent 132 // the precision and ranges of both input values. See convert() for an 133 // explanation of the Overflow parameter. 134 APFixedPoint add(const APFixedPoint &Other, bool *Overflow = nullptr) const; 135 APFixedPoint sub(const APFixedPoint &Other, bool *Overflow = nullptr) const; 136 APFixedPoint mul(const APFixedPoint &Other, bool *Overflow = nullptr) const; 137 APFixedPoint div(const APFixedPoint &Other, bool *Overflow = nullptr) const; 138 139 // Perform shift operations on a fixed point type. Unlike the other binary 140 // operations, the resulting fixed point value will be in the original 141 // semantic. 142 APFixedPoint shl(unsigned Amt, bool *Overflow = nullptr) const; 143 APFixedPoint shr(unsigned Amt, bool *Overflow = nullptr) const { 144 // Right shift cannot overflow. 145 if (Overflow) 146 *Overflow = false; 147 return APFixedPoint(Val >> Amt, Sema); 148 } 149 150 /// Perform a unary negation (-X) on this fixed point type, taking into 151 /// account saturation if applicable. 152 APFixedPoint negate(bool *Overflow = nullptr) const; 153 154 /// Return the integral part of this fixed point number, rounded towards 155 /// zero. (-2.5k -> -2) getIntPart()156 APSInt getIntPart() const { 157 if (Val < 0 && Val != -Val) // Cover the case when we have the min val 158 return -(-Val >> getScale()); 159 else 160 return Val >> getScale(); 161 } 162 163 /// Return the integral part of this fixed point number, rounded towards 164 /// zero. The value is stored into an APSInt with the provided width and sign. 165 /// If the overflow parameter is provided, and the integral value is not able 166 /// to be fully stored in the provided width and sign, the overflow parameter 167 /// is set to true. 168 APSInt convertToInt(unsigned DstWidth, bool DstSign, 169 bool *Overflow = nullptr) const; 170 171 /// Convert this fixed point number to a floating point value with the 172 /// provided semantics. 173 APFloat convertToFloat(const fltSemantics &FloatSema) const; 174 175 void toString(SmallVectorImpl<char> &Str) const; toString()176 std::string toString() const { 177 SmallString<40> S; 178 toString(S); 179 return std::string(S.str()); 180 } 181 182 // If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1. 183 int compare(const APFixedPoint &Other) const; 184 bool operator==(const APFixedPoint &Other) const { 185 return compare(Other) == 0; 186 } 187 bool operator!=(const APFixedPoint &Other) const { 188 return compare(Other) != 0; 189 } 190 bool operator>(const APFixedPoint &Other) const { return compare(Other) > 0; } 191 bool operator<(const APFixedPoint &Other) const { return compare(Other) < 0; } 192 bool operator>=(const APFixedPoint &Other) const { 193 return compare(Other) >= 0; 194 } 195 bool operator<=(const APFixedPoint &Other) const { 196 return compare(Other) <= 0; 197 } 198 199 static APFixedPoint getMax(const FixedPointSemantics &Sema); 200 static APFixedPoint getMin(const FixedPointSemantics &Sema); 201 202 /// Given a floating point semantic, return the next floating point semantic 203 /// with a larger exponent and larger or equal mantissa. 204 static const fltSemantics *promoteFloatSemantics(const fltSemantics *S); 205 206 /// Create an APFixedPoint with a value equal to that of the provided integer, 207 /// and in the same semantics as the provided target semantics. If the value 208 /// is not able to fit in the specified fixed point semantics, and the 209 /// overflow parameter is provided, it is set to true. 210 static APFixedPoint getFromIntValue(const APSInt &Value, 211 const FixedPointSemantics &DstFXSema, 212 bool *Overflow = nullptr); 213 214 /// Create an APFixedPoint with a value equal to that of the provided 215 /// floating point value, in the provided target semantics. If the value is 216 /// not able to fit in the specified fixed point semantics and the overflow 217 /// parameter is specified, it is set to true. 218 /// For NaN, the Overflow flag is always set. For +inf and -inf, if the 219 /// semantic is saturating, the value saturates. Otherwise, the Overflow flag 220 /// is set. 221 static APFixedPoint getFromFloatValue(const APFloat &Value, 222 const FixedPointSemantics &DstFXSema, 223 bool *Overflow = nullptr); 224 225 private: 226 APSInt Val; 227 FixedPointSemantics Sema; 228 }; 229 230 inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) { 231 OS << FX.toString(); 232 return OS; 233 } 234 235 } // namespace llvm 236 237 #endif 238