Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:02

0001 //===- APFixedPoint.h - Fixed point constant handling -----------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// Defines the fixed point number interface.
0011 /// This is a class for abstracting various operations performed on fixed point
0012 /// types.
0013 ///
0014 //===----------------------------------------------------------------------===//
0015 
0016 #ifndef LLVM_ADT_APFIXEDPOINT_H
0017 #define LLVM_ADT_APFIXEDPOINT_H
0018 
0019 #include "llvm/ADT/APSInt.h"
0020 #include "llvm/ADT/Hashing.h"
0021 #include "llvm/ADT/SmallString.h"
0022 #include "llvm/Support/raw_ostream.h"
0023 
0024 namespace llvm {
0025 
0026 class APFloat;
0027 struct fltSemantics;
0028 
0029 /// The fixed point semantics work similarly to fltSemantics. The width
0030 /// specifies the whole bit width of the underlying scaled integer (with padding
0031 /// if any). The scale represents the number of fractional bits in this type.
0032 /// When HasUnsignedPadding is true and this type is unsigned, the first bit
0033 /// in the value this represents is treated as padding.
0034 class FixedPointSemantics {
0035 public:
0036   static constexpr unsigned WidthBitWidth = 16;
0037   static constexpr unsigned LsbWeightBitWidth = 13;
0038   /// Used to differentiate between constructors with Width and Lsb from the
0039   /// default Width and scale
0040   struct Lsb {
0041     int LsbWeight;
0042   };
0043   FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned,
0044                       bool IsSaturated, bool HasUnsignedPadding)
0045       : FixedPointSemantics(Width, Lsb{-static_cast<int>(Scale)}, IsSigned,
0046                             IsSaturated, HasUnsignedPadding) {}
0047   FixedPointSemantics(unsigned Width, Lsb Weight, bool IsSigned,
0048                       bool IsSaturated, bool HasUnsignedPadding)
0049       : Width(Width), LsbWeight(Weight.LsbWeight), IsSigned(IsSigned),
0050         IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) {
0051     assert(isUInt<WidthBitWidth>(Width) && isInt<LsbWeightBitWidth>(Weight.LsbWeight));
0052     assert(!(IsSigned && HasUnsignedPadding) &&
0053            "Cannot have unsigned padding on a signed type.");
0054   }
0055 
0056   /// Check if the Semantic follow the requirements of an older more limited
0057   /// version of this class
0058   bool isValidLegacySema() const {
0059     return LsbWeight <= 0 && static_cast<int>(Width) >= -LsbWeight;
0060   }
0061   unsigned getWidth() const { return Width; }
0062   unsigned getScale() const { assert(isValidLegacySema()); return -LsbWeight; }
0063   int getLsbWeight() const { return LsbWeight; }
0064   int getMsbWeight() const {
0065     return LsbWeight + Width - 1 /*Both lsb and msb are both part of width*/;
0066   }
0067   bool isSigned() const { return IsSigned; }
0068   bool isSaturated() const { return IsSaturated; }
0069   bool hasUnsignedPadding() const { return HasUnsignedPadding; }
0070 
0071   void setSaturated(bool Saturated) { IsSaturated = Saturated; }
0072 
0073   /// return true if the first bit doesn't have a strictly positive weight
0074   bool hasSignOrPaddingBit() const { return IsSigned || HasUnsignedPadding; }
0075 
0076   /// Return the number of integral bits represented by these semantics. These
0077   /// are separate from the fractional bits and do not include the sign or
0078   /// padding bit.
0079   unsigned getIntegralBits() const {
0080     return std::max(getMsbWeight() + 1 - hasSignOrPaddingBit(), 0);
0081   }
0082 
0083   /// Return the FixedPointSemantics that allows for calculating the full
0084   /// precision semantic that can precisely represent the precision and ranges
0085   /// of both input values. This does not compute the resulting semantics for a
0086   /// given binary operation.
0087   FixedPointSemantics
0088   getCommonSemantics(const FixedPointSemantics &Other) const;
0089 
0090   /// Print semantics for debug purposes
0091   void print(llvm::raw_ostream& OS) const;
0092 
0093   /// Returns true if this fixed-point semantic with its value bits interpreted
0094   /// as an integer can fit in the given floating point semantic without
0095   /// overflowing to infinity.
0096   /// For example, a signed 8-bit fixed-point semantic has a maximum and
0097   /// minimum integer representation of 127 and -128, respectively. If both of
0098   /// these values can be represented (possibly inexactly) in the floating
0099   /// point semantic without overflowing, this returns true.
0100   bool fitsInFloatSemantics(const fltSemantics &FloatSema) const;
0101 
0102   /// Return the FixedPointSemantics for an integer type.
0103   static FixedPointSemantics GetIntegerSemantics(unsigned Width,
0104                                                  bool IsSigned) {
0105     return FixedPointSemantics(Width, /*Scale=*/0, IsSigned,
0106                                /*IsSaturated=*/false,
0107                                /*HasUnsignedPadding=*/false);
0108   }
0109 
0110   bool operator==(FixedPointSemantics Other) const {
0111     return Width == Other.Width && LsbWeight == Other.LsbWeight &&
0112            IsSigned == Other.IsSigned && IsSaturated == Other.IsSaturated &&
0113            HasUnsignedPadding == Other.HasUnsignedPadding;
0114   }
0115   bool operator!=(FixedPointSemantics Other) const { return !(*this == Other); }
0116 
0117   /// Convert the semantics to a 32-bit unsigned integer.
0118   /// The result is dependent on the host endianness and not stable across LLVM
0119   /// versions. See getFromOpaqueInt() to convert it back to a
0120   /// FixedPointSemantics object.
0121   uint32_t toOpaqueInt() const;
0122   /// Create a FixedPointSemantics object from an integer created via
0123   /// toOpaqueInt().
0124   static FixedPointSemantics getFromOpaqueInt(uint32_t);
0125 
0126 private:
0127   unsigned Width          : WidthBitWidth;
0128   signed int LsbWeight    : LsbWeightBitWidth;
0129   unsigned IsSigned       : 1;
0130   unsigned IsSaturated    : 1;
0131   unsigned HasUnsignedPadding : 1;
0132 };
0133 
0134 static_assert(sizeof(FixedPointSemantics) == 4, "");
0135 
0136 inline hash_code hash_value(const FixedPointSemantics &Val) {
0137   return hash_value(bit_cast<uint32_t>(Val));
0138 }
0139 
0140 template <> struct DenseMapInfo<FixedPointSemantics> {
0141   static inline FixedPointSemantics getEmptyKey() {
0142     return FixedPointSemantics(0, 0, false, false, false);
0143   }
0144 
0145   static inline FixedPointSemantics getTombstoneKey() {
0146     return FixedPointSemantics(0, 1, false, false, false);
0147   }
0148 
0149   static unsigned getHashValue(const FixedPointSemantics &Val) {
0150     return hash_value(Val);
0151   }
0152 
0153   static bool isEqual(const char &LHS, const char &RHS) { return LHS == RHS; }
0154 };
0155 
0156 /// The APFixedPoint class works similarly to APInt/APSInt in that it is a
0157 /// functional replacement for a scaled integer. It supports a wide range of
0158 /// semantics including the one used by fixed point types proposed in ISO/IEC
0159 /// JTC1 SC22 WG14 N1169. The class carries the value and semantics of
0160 /// a fixed point, and provides different operations that would normally be
0161 /// performed on fixed point types.
0162 class APFixedPoint {
0163 public:
0164   APFixedPoint(const APInt &Val, const FixedPointSemantics &Sema)
0165       : Val(Val, !Sema.isSigned()), Sema(Sema) {
0166     assert(Val.getBitWidth() == Sema.getWidth() &&
0167            "The value should have a bit width that matches the Sema width");
0168   }
0169 
0170   APFixedPoint(uint64_t Val, const FixedPointSemantics &Sema)
0171       : APFixedPoint(APInt(Sema.getWidth(), Val, Sema.isSigned(),
0172                            /*implicitTrunc=*/true),
0173                      Sema) {}
0174 
0175   // Zero initialization.
0176   APFixedPoint(const FixedPointSemantics &Sema) : APFixedPoint(0, Sema) {}
0177 
0178   APSInt getValue() const { return APSInt(Val, !Sema.isSigned()); }
0179   inline unsigned getWidth() const { return Sema.getWidth(); }
0180   inline unsigned getScale() const { return Sema.getScale(); }
0181   int getLsbWeight() const { return Sema.getLsbWeight(); }
0182   int getMsbWeight() const { return Sema.getMsbWeight(); }
0183   inline bool isSaturated() const { return Sema.isSaturated(); }
0184   inline bool isSigned() const { return Sema.isSigned(); }
0185   inline bool hasPadding() const { return Sema.hasUnsignedPadding(); }
0186   FixedPointSemantics getSemantics() const { return Sema; }
0187 
0188   bool getBoolValue() const { return Val.getBoolValue(); }
0189 
0190   // Convert this number to match the semantics provided. If the overflow
0191   // parameter is provided, set this value to true or false to indicate if this
0192   // operation results in an overflow.
0193   APFixedPoint convert(const FixedPointSemantics &DstSema,
0194                        bool *Overflow = nullptr) const;
0195 
0196   // Perform binary operations on a fixed point type. The resulting fixed point
0197   // value will be in the common, full precision semantics that can represent
0198   // the precision and ranges of both input values. See convert() for an
0199   // explanation of the Overflow parameter.
0200   APFixedPoint add(const APFixedPoint &Other, bool *Overflow = nullptr) const;
0201   APFixedPoint sub(const APFixedPoint &Other, bool *Overflow = nullptr) const;
0202   APFixedPoint mul(const APFixedPoint &Other, bool *Overflow = nullptr) const;
0203   APFixedPoint div(const APFixedPoint &Other, bool *Overflow = nullptr) const;
0204 
0205   // Perform shift operations on a fixed point type. Unlike the other binary
0206   // operations, the resulting fixed point value will be in the original
0207   // semantic.
0208   APFixedPoint shl(unsigned Amt, bool *Overflow = nullptr) const;
0209   APFixedPoint shr(unsigned Amt, bool *Overflow = nullptr) const {
0210     // Right shift cannot overflow.
0211     if (Overflow)
0212       *Overflow = false;
0213     return APFixedPoint(Val >> Amt, Sema);
0214   }
0215 
0216   /// Perform a unary negation (-X) on this fixed point type, taking into
0217   /// account saturation if applicable.
0218   APFixedPoint negate(bool *Overflow = nullptr) const;
0219 
0220   /// Return the integral part of this fixed point number, rounded towards
0221   /// zero. (-2.5k -> -2)
0222   APSInt getIntPart() const {
0223     if (getMsbWeight() < 0)
0224       return APSInt(APInt::getZero(getWidth()), Val.isUnsigned());
0225     APSInt ExtVal =
0226         (getLsbWeight() > 0) ? Val.extend(getWidth() + getLsbWeight()) : Val;
0227     if (Val < 0 && Val != -Val) // Cover the case when we have the min val
0228       return -((-ExtVal).relativeShl(getLsbWeight()));
0229     return ExtVal.relativeShl(getLsbWeight());
0230   }
0231 
0232   /// Return the integral part of this fixed point number, rounded towards
0233   /// zero. The value is stored into an APSInt with the provided width and sign.
0234   /// If the overflow parameter is provided, and the integral value is not able
0235   /// to be fully stored in the provided width and sign, the overflow parameter
0236   /// is set to true.
0237   APSInt convertToInt(unsigned DstWidth, bool DstSign,
0238                       bool *Overflow = nullptr) const;
0239 
0240   /// Convert this fixed point number to a floating point value with the
0241   /// provided semantics.
0242   APFloat convertToFloat(const fltSemantics &FloatSema) const;
0243 
0244   void toString(SmallVectorImpl<char> &Str) const;
0245   std::string toString() const {
0246     SmallString<40> S;
0247     toString(S);
0248     return std::string(S);
0249   }
0250 
0251   void print(raw_ostream &) const;
0252   void dump() const;
0253 
0254   // If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1.
0255   int compare(const APFixedPoint &Other) const;
0256   bool operator==(const APFixedPoint &Other) const {
0257     return compare(Other) == 0;
0258   }
0259   bool operator!=(const APFixedPoint &Other) const {
0260     return compare(Other) != 0;
0261   }
0262   bool operator>(const APFixedPoint &Other) const { return compare(Other) > 0; }
0263   bool operator<(const APFixedPoint &Other) const { return compare(Other) < 0; }
0264   bool operator>=(const APFixedPoint &Other) const {
0265     return compare(Other) >= 0;
0266   }
0267   bool operator<=(const APFixedPoint &Other) const {
0268     return compare(Other) <= 0;
0269   }
0270 
0271   static APFixedPoint getMax(const FixedPointSemantics &Sema);
0272   static APFixedPoint getMin(const FixedPointSemantics &Sema);
0273   static APFixedPoint getEpsilon(const FixedPointSemantics &Sema);
0274 
0275   /// Given a floating point semantic, return the next floating point semantic
0276   /// with a larger exponent and larger or equal mantissa.
0277   static const fltSemantics *promoteFloatSemantics(const fltSemantics *S);
0278 
0279   /// Create an APFixedPoint with a value equal to that of the provided integer,
0280   /// and in the same semantics as the provided target semantics. If the value
0281   /// is not able to fit in the specified fixed point semantics, and the
0282   /// overflow parameter is provided, it is set to true.
0283   static APFixedPoint getFromIntValue(const APSInt &Value,
0284                                       const FixedPointSemantics &DstFXSema,
0285                                       bool *Overflow = nullptr);
0286 
0287   /// Create an APFixedPoint with a value equal to that of the provided
0288   /// floating point value, in the provided target semantics. If the value is
0289   /// not able to fit in the specified fixed point semantics and the overflow
0290   /// parameter is specified, it is set to true.
0291   /// For NaN, the Overflow flag is always set. For +inf and -inf, if the
0292   /// semantic is saturating, the value saturates. Otherwise, the Overflow flag
0293   /// is set.
0294   static APFixedPoint getFromFloatValue(const APFloat &Value,
0295                                         const FixedPointSemantics &DstFXSema,
0296                                         bool *Overflow = nullptr);
0297 
0298 private:
0299   APSInt Val;
0300   FixedPointSemantics Sema;
0301 };
0302 
0303 inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) {
0304   OS << FX.toString();
0305   return OS;
0306 }
0307 
0308 inline hash_code hash_value(const APFixedPoint &Val) {
0309   return hash_combine(Val.getSemantics(), Val.getValue());
0310 }
0311 
0312 template <> struct DenseMapInfo<APFixedPoint> {
0313   static inline APFixedPoint getEmptyKey() {
0314     return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getEmptyKey());
0315   }
0316 
0317   static inline APFixedPoint getTombstoneKey() {
0318     return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getTombstoneKey());
0319   }
0320 
0321   static unsigned getHashValue(const APFixedPoint &Val) {
0322     return hash_value(Val);
0323   }
0324 
0325   static bool isEqual(const APFixedPoint &LHS, const APFixedPoint &RHS) {
0326     return LHS.getSemantics() == RHS.getSemantics() &&
0327            LHS.getValue() == RHS.getValue();
0328   }
0329 };
0330 
0331 } // namespace llvm
0332 
0333 #endif