Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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/DenseMapInfo.h"
  21. #include "llvm/ADT/Hashing.h"
  22. #include "llvm/ADT/SmallString.h"
  23. #include "llvm/Support/raw_ostream.h"
  24.  
  25. namespace llvm {
  26.  
  27. class APFloat;
  28. struct fltSemantics;
  29.  
  30. /// The fixed point semantics work similarly to fltSemantics. The width
  31. /// specifies the whole bit width of the underlying scaled integer (with padding
  32. /// if any). The scale represents the number of fractional bits in this type.
  33. /// When HasUnsignedPadding is true and this type is unsigned, the first bit
  34. /// in the value this represents is treated as padding.
  35. class FixedPointSemantics {
  36. public:
  37.   static constexpr unsigned WidthBitWidth = 16;
  38.   static constexpr unsigned LsbWeightBitWidth = 13;
  39.   /// Used to differentiate between constructors with Width and Lsb from the
  40.   /// default Width and scale
  41.   struct Lsb {
  42.     int LsbWeight;
  43.   };
  44.   FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned,
  45.                       bool IsSaturated, bool HasUnsignedPadding)
  46.       : FixedPointSemantics(Width, Lsb{-static_cast<int>(Scale)}, IsSigned,
  47.                             IsSaturated, HasUnsignedPadding) {}
  48.   FixedPointSemantics(unsigned Width, Lsb Weight, bool IsSigned,
  49.                       bool IsSaturated, bool HasUnsignedPadding)
  50.       : Width(Width), LsbWeight(Weight.LsbWeight), IsSigned(IsSigned),
  51.         IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) {
  52.     assert(isUInt<WidthBitWidth>(Width) && isInt<LsbWeightBitWidth>(Weight.LsbWeight));
  53.     assert(!(IsSigned && HasUnsignedPadding) &&
  54.            "Cannot have unsigned padding on a signed type.");
  55.   }
  56.  
  57.   /// Check if the Semantic follow the requirements of an older more limited
  58.   /// version of this class
  59.   bool isValidLegacySema() const {
  60.     return LsbWeight <= 0 && static_cast<int>(Width) >= -LsbWeight;
  61.   }
  62.   unsigned getWidth() const { return Width; }
  63.   unsigned getScale() const { assert(isValidLegacySema()); return -LsbWeight; }
  64.   int getLsbWeight() const { return LsbWeight; }
  65.   int getMsbWeight() const {
  66.     return LsbWeight + Width - 1 /*Both lsb and msb are both part of width*/;
  67.   }
  68.   bool isSigned() const { return IsSigned; }
  69.   bool isSaturated() const { return IsSaturated; }
  70.   bool hasUnsignedPadding() const { return HasUnsignedPadding; }
  71.  
  72.   void setSaturated(bool Saturated) { IsSaturated = Saturated; }
  73.  
  74.   /// return true if the first bit doesn't have a strictly positive weight
  75.   bool hasSignOrPaddingBit() const { return IsSigned || HasUnsignedPadding; }
  76.  
  77.   /// Return the number of integral bits represented by these semantics. These
  78.   /// are separate from the fractional bits and do not include the sign or
  79.   /// padding bit.
  80.   unsigned getIntegralBits() const {
  81.     return std::max(getMsbWeight() + 1 - hasSignOrPaddingBit(), 0);
  82.   }
  83.  
  84.   /// Return the FixedPointSemantics that allows for calculating the full
  85.   /// precision semantic that can precisely represent the precision and ranges
  86.   /// of both input values. This does not compute the resulting semantics for a
  87.   /// given binary operation.
  88.   FixedPointSemantics
  89.   getCommonSemantics(const FixedPointSemantics &Other) const;
  90.  
  91.   /// Print semantics for debug purposes
  92.   void print(llvm::raw_ostream& OS) const;
  93.  
  94.   /// Returns true if this fixed-point semantic with its value bits interpreted
  95.   /// as an integer can fit in the given floating point semantic without
  96.   /// overflowing to infinity.
  97.   /// For example, a signed 8-bit fixed-point semantic has a maximum and
  98.   /// minimum integer representation of 127 and -128, respectively. If both of
  99.   /// these values can be represented (possibly inexactly) in the floating
  100.   /// point semantic without overflowing, this returns true.
  101.   bool fitsInFloatSemantics(const fltSemantics &FloatSema) const;
  102.  
  103.   /// Return the FixedPointSemantics for an integer type.
  104.   static FixedPointSemantics GetIntegerSemantics(unsigned Width,
  105.                                                  bool IsSigned) {
  106.     return FixedPointSemantics(Width, /*Scale=*/0, IsSigned,
  107.                                /*IsSaturated=*/false,
  108.                                /*HasUnsignedPadding=*/false);
  109.   }
  110.  
  111.   bool operator==(FixedPointSemantics Other) const {
  112.     return Width == Other.Width && LsbWeight == Other.LsbWeight &&
  113.            IsSigned == Other.IsSigned && IsSaturated == Other.IsSaturated &&
  114.            HasUnsignedPadding == Other.HasUnsignedPadding;
  115.   }
  116.   bool operator!=(FixedPointSemantics Other) const { return !(*this == Other); }
  117.  
  118. private:
  119.   unsigned Width          : WidthBitWidth;
  120.   signed int LsbWeight    : LsbWeightBitWidth;
  121.   unsigned IsSigned       : 1;
  122.   unsigned IsSaturated    : 1;
  123.   unsigned HasUnsignedPadding : 1;
  124. };
  125.  
  126. static_assert(sizeof(FixedPointSemantics) == 4, "");
  127.  
  128. inline hash_code hash_value(const FixedPointSemantics &Val) {
  129.   return hash_value(bit_cast<uint32_t>(Val));
  130. }
  131.  
  132. template <> struct DenseMapInfo<FixedPointSemantics> {
  133.   static inline FixedPointSemantics getEmptyKey() {
  134.     return FixedPointSemantics(0, 0, false, false, false);
  135.   }
  136.  
  137.   static inline FixedPointSemantics getTombstoneKey() {
  138.     return FixedPointSemantics(0, 1, false, false, false);
  139.   }
  140.  
  141.   static unsigned getHashValue(const FixedPointSemantics &Val) {
  142.     return hash_value(Val);
  143.   }
  144.  
  145.   static bool isEqual(const char &LHS, const char &RHS) { return LHS == RHS; }
  146. };
  147.  
  148. /// The APFixedPoint class works similarly to APInt/APSInt in that it is a
  149. /// functional replacement for a scaled integer. It supports a wide range of
  150. /// semantics including the one used by fixed point types proposed in ISO/IEC
  151. /// JTC1 SC22 WG14 N1169. The class carries the value and semantics of
  152. /// a fixed point, and provides different operations that would normally be
  153. /// performed on fixed point types.
  154. class APFixedPoint {
  155. public:
  156.   APFixedPoint(const APInt &Val, const FixedPointSemantics &Sema)
  157.       : Val(Val, !Sema.isSigned()), Sema(Sema) {
  158.     assert(Val.getBitWidth() == Sema.getWidth() &&
  159.            "The value should have a bit width that matches the Sema width");
  160.   }
  161.  
  162.   APFixedPoint(uint64_t Val, const FixedPointSemantics &Sema)
  163.       : APFixedPoint(APInt(Sema.getWidth(), Val, Sema.isSigned()), Sema) {}
  164.  
  165.   // Zero initialization.
  166.   APFixedPoint(const FixedPointSemantics &Sema) : APFixedPoint(0, Sema) {}
  167.  
  168.   APSInt getValue() const { return APSInt(Val, !Sema.isSigned()); }
  169.   inline unsigned getWidth() const { return Sema.getWidth(); }
  170.   inline unsigned getScale() const { return Sema.getScale(); }
  171.   int getLsbWeight() const { return Sema.getLsbWeight(); }
  172.   int getMsbWeight() const { return Sema.getMsbWeight(); }
  173.   inline bool isSaturated() const { return Sema.isSaturated(); }
  174.   inline bool isSigned() const { return Sema.isSigned(); }
  175.   inline bool hasPadding() const { return Sema.hasUnsignedPadding(); }
  176.   FixedPointSemantics getSemantics() const { return Sema; }
  177.  
  178.   bool getBoolValue() const { return Val.getBoolValue(); }
  179.  
  180.   // Convert this number to match the semantics provided. If the overflow
  181.   // parameter is provided, set this value to true or false to indicate if this
  182.   // operation results in an overflow.
  183.   APFixedPoint convert(const FixedPointSemantics &DstSema,
  184.                        bool *Overflow = nullptr) const;
  185.  
  186.   // Perform binary operations on a fixed point type. The resulting fixed point
  187.   // value will be in the common, full precision semantics that can represent
  188.   // the precision and ranges of both input values. See convert() for an
  189.   // explanation of the Overflow parameter.
  190.   APFixedPoint add(const APFixedPoint &Other, bool *Overflow = nullptr) const;
  191.   APFixedPoint sub(const APFixedPoint &Other, bool *Overflow = nullptr) const;
  192.   APFixedPoint mul(const APFixedPoint &Other, bool *Overflow = nullptr) const;
  193.   APFixedPoint div(const APFixedPoint &Other, bool *Overflow = nullptr) const;
  194.  
  195.   // Perform shift operations on a fixed point type. Unlike the other binary
  196.   // operations, the resulting fixed point value will be in the original
  197.   // semantic.
  198.   APFixedPoint shl(unsigned Amt, bool *Overflow = nullptr) const;
  199.   APFixedPoint shr(unsigned Amt, bool *Overflow = nullptr) const {
  200.     // Right shift cannot overflow.
  201.     if (Overflow)
  202.       *Overflow = false;
  203.     return APFixedPoint(Val >> Amt, Sema);
  204.   }
  205.  
  206.   /// Perform a unary negation (-X) on this fixed point type, taking into
  207.   /// account saturation if applicable.
  208.   APFixedPoint negate(bool *Overflow = nullptr) const;
  209.  
  210.   /// Return the integral part of this fixed point number, rounded towards
  211.   /// zero. (-2.5k -> -2)
  212.   APSInt getIntPart() const {
  213.     if (getMsbWeight() < 0)
  214.       return APSInt(APInt::getZero(getWidth()), Val.isUnsigned());
  215.     APSInt ExtVal =
  216.         (getLsbWeight() > 0) ? Val.extend(getWidth() + getLsbWeight()) : Val;
  217.     if (Val < 0 && Val != -Val) // Cover the case when we have the min val
  218.       return -((-ExtVal).relativeShl(getLsbWeight()));
  219.     return ExtVal.relativeShl(getLsbWeight());
  220.   }
  221.  
  222.   /// Return the integral part of this fixed point number, rounded towards
  223.   /// zero. The value is stored into an APSInt with the provided width and sign.
  224.   /// If the overflow parameter is provided, and the integral value is not able
  225.   /// to be fully stored in the provided width and sign, the overflow parameter
  226.   /// is set to true.
  227.   APSInt convertToInt(unsigned DstWidth, bool DstSign,
  228.                       bool *Overflow = nullptr) const;
  229.  
  230.   /// Convert this fixed point number to a floating point value with the
  231.   /// provided semantics.
  232.   APFloat convertToFloat(const fltSemantics &FloatSema) const;
  233.  
  234.   void toString(SmallVectorImpl<char> &Str) const;
  235.   std::string toString() const {
  236.     SmallString<40> S;
  237.     toString(S);
  238.     return std::string(S.str());
  239.   }
  240.  
  241.   void print(raw_ostream &) const;
  242.   void dump() const;
  243.  
  244.   // If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1.
  245.   int compare(const APFixedPoint &Other) const;
  246.   bool operator==(const APFixedPoint &Other) const {
  247.     return compare(Other) == 0;
  248.   }
  249.   bool operator!=(const APFixedPoint &Other) const {
  250.     return compare(Other) != 0;
  251.   }
  252.   bool operator>(const APFixedPoint &Other) const { return compare(Other) > 0; }
  253.   bool operator<(const APFixedPoint &Other) const { return compare(Other) < 0; }
  254.   bool operator>=(const APFixedPoint &Other) const {
  255.     return compare(Other) >= 0;
  256.   }
  257.   bool operator<=(const APFixedPoint &Other) const {
  258.     return compare(Other) <= 0;
  259.   }
  260.  
  261.   static APFixedPoint getMax(const FixedPointSemantics &Sema);
  262.   static APFixedPoint getMin(const FixedPointSemantics &Sema);
  263.  
  264.   /// Given a floating point semantic, return the next floating point semantic
  265.   /// with a larger exponent and larger or equal mantissa.
  266.   static const fltSemantics *promoteFloatSemantics(const fltSemantics *S);
  267.  
  268.   /// Create an APFixedPoint with a value equal to that of the provided integer,
  269.   /// and in the same semantics as the provided target semantics. If the value
  270.   /// is not able to fit in the specified fixed point semantics, and the
  271.   /// overflow parameter is provided, it is set to true.
  272.   static APFixedPoint getFromIntValue(const APSInt &Value,
  273.                                       const FixedPointSemantics &DstFXSema,
  274.                                       bool *Overflow = nullptr);
  275.  
  276.   /// Create an APFixedPoint with a value equal to that of the provided
  277.   /// floating point value, in the provided target semantics. If the value is
  278.   /// not able to fit in the specified fixed point semantics and the overflow
  279.   /// parameter is specified, it is set to true.
  280.   /// For NaN, the Overflow flag is always set. For +inf and -inf, if the
  281.   /// semantic is saturating, the value saturates. Otherwise, the Overflow flag
  282.   /// is set.
  283.   static APFixedPoint getFromFloatValue(const APFloat &Value,
  284.                                         const FixedPointSemantics &DstFXSema,
  285.                                         bool *Overflow = nullptr);
  286.  
  287. private:
  288.   APSInt Val;
  289.   FixedPointSemantics Sema;
  290. };
  291.  
  292. inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) {
  293.   OS << FX.toString();
  294.   return OS;
  295. }
  296.  
  297. inline hash_code hash_value(const APFixedPoint &Val) {
  298.   return hash_combine(Val.getSemantics(), Val.getValue());
  299. }
  300.  
  301. template <> struct DenseMapInfo<APFixedPoint> {
  302.   static inline APFixedPoint getEmptyKey() {
  303.     return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getEmptyKey());
  304.   }
  305.  
  306.   static inline APFixedPoint getTombstoneKey() {
  307.     return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getTombstoneKey());
  308.   }
  309.  
  310.   static unsigned getHashValue(const APFixedPoint &Val) {
  311.     return hash_value(Val);
  312.   }
  313.  
  314.   static bool isEqual(const APFixedPoint &LHS, const APFixedPoint &RHS) {
  315.     return LHS.getSemantics() == RHS.getSemantics() &&
  316.            LHS.getValue() == RHS.getValue();
  317.   }
  318. };
  319.  
  320. } // namespace llvm
  321.  
  322. #endif
  323.