xref: /llvm-project/llvm/include/llvm/ADT/APFixedPoint.h (revision 255a99c29f9fa1a89b03a85a3a73d6f44d03c6c1)
11a995a0aSBevin Hansson //===- APFixedPoint.h - Fixed point constant handling -----------*- C++ -*-===//
21a995a0aSBevin Hansson //
31a995a0aSBevin Hansson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41a995a0aSBevin Hansson // See https://llvm.org/LICENSE.txt for license information.
51a995a0aSBevin Hansson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61a995a0aSBevin Hansson //
71a995a0aSBevin Hansson //===----------------------------------------------------------------------===//
8c95df64cSShivam Gupta ///
91a995a0aSBevin Hansson /// \file
101a995a0aSBevin Hansson /// Defines the fixed point number interface.
111a995a0aSBevin Hansson /// This is a class for abstracting various operations performed on fixed point
121a995a0aSBevin Hansson /// types.
13c95df64cSShivam Gupta ///
141a995a0aSBevin Hansson //===----------------------------------------------------------------------===//
151a995a0aSBevin Hansson 
161a995a0aSBevin Hansson #ifndef LLVM_ADT_APFIXEDPOINT_H
171a995a0aSBevin Hansson #define LLVM_ADT_APFIXEDPOINT_H
181a995a0aSBevin Hansson 
191a995a0aSBevin Hansson #include "llvm/ADT/APSInt.h"
20a73db7f1SFangrui Song #include "llvm/ADT/Hashing.h"
211a995a0aSBevin Hansson #include "llvm/ADT/SmallString.h"
221a995a0aSBevin Hansson #include "llvm/Support/raw_ostream.h"
231a995a0aSBevin Hansson 
241a995a0aSBevin Hansson namespace llvm {
251a995a0aSBevin Hansson 
26dd3014f3SBevin Hansson class APFloat;
27dd3014f3SBevin Hansson struct fltSemantics;
28dd3014f3SBevin Hansson 
291a995a0aSBevin Hansson /// The fixed point semantics work similarly to fltSemantics. The width
301a995a0aSBevin Hansson /// specifies the whole bit width of the underlying scaled integer (with padding
311a995a0aSBevin Hansson /// if any). The scale represents the number of fractional bits in this type.
321a995a0aSBevin Hansson /// When HasUnsignedPadding is true and this type is unsigned, the first bit
331a995a0aSBevin Hansson /// in the value this represents is treated as padding.
341a995a0aSBevin Hansson class FixedPointSemantics {
351a995a0aSBevin Hansson public:
361654b22aSTyker   static constexpr unsigned WidthBitWidth = 16;
371654b22aSTyker   static constexpr unsigned LsbWeightBitWidth = 13;
381654b22aSTyker   /// Used to differentiate between constructors with Width and Lsb from the
391654b22aSTyker   /// default Width and scale
401654b22aSTyker   struct Lsb {
411654b22aSTyker     int LsbWeight;
421654b22aSTyker   };
431a995a0aSBevin Hansson   FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned,
441a995a0aSBevin Hansson                       bool IsSaturated, bool HasUnsignedPadding)
451654b22aSTyker       : FixedPointSemantics(Width, Lsb{-static_cast<int>(Scale)}, IsSigned,
461654b22aSTyker                             IsSaturated, HasUnsignedPadding) {}
471654b22aSTyker   FixedPointSemantics(unsigned Width, Lsb Weight, bool IsSigned,
481654b22aSTyker                       bool IsSaturated, bool HasUnsignedPadding)
491654b22aSTyker       : Width(Width), LsbWeight(Weight.LsbWeight), IsSigned(IsSigned),
501a995a0aSBevin Hansson         IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) {
511654b22aSTyker     assert(isUInt<WidthBitWidth>(Width) && isInt<LsbWeightBitWidth>(Weight.LsbWeight));
521a995a0aSBevin Hansson     assert(!(IsSigned && HasUnsignedPadding) &&
531a995a0aSBevin Hansson            "Cannot have unsigned padding on a signed type.");
541a995a0aSBevin Hansson   }
551a995a0aSBevin Hansson 
561654b22aSTyker   /// Check if the Semantic follow the requirements of an older more limited
571654b22aSTyker   /// version of this class
581654b22aSTyker   bool isValidLegacySema() const {
595922b920SAaron Ballman     return LsbWeight <= 0 && static_cast<int>(Width) >= -LsbWeight;
601654b22aSTyker   }
611a995a0aSBevin Hansson   unsigned getWidth() const { return Width; }
621654b22aSTyker   unsigned getScale() const { assert(isValidLegacySema()); return -LsbWeight; }
631654b22aSTyker   int getLsbWeight() const { return LsbWeight; }
641654b22aSTyker   int getMsbWeight() const {
651654b22aSTyker     return LsbWeight + Width - 1 /*Both lsb and msb are both part of width*/;
661654b22aSTyker   }
671a995a0aSBevin Hansson   bool isSigned() const { return IsSigned; }
681a995a0aSBevin Hansson   bool isSaturated() const { return IsSaturated; }
691a995a0aSBevin Hansson   bool hasUnsignedPadding() const { return HasUnsignedPadding; }
701a995a0aSBevin Hansson 
711a995a0aSBevin Hansson   void setSaturated(bool Saturated) { IsSaturated = Saturated; }
721a995a0aSBevin Hansson 
731654b22aSTyker   /// return true if the first bit doesn't have a strictly positive weight
741654b22aSTyker   bool hasSignOrPaddingBit() const { return IsSigned || HasUnsignedPadding; }
751654b22aSTyker 
761a995a0aSBevin Hansson   /// Return the number of integral bits represented by these semantics. These
771a995a0aSBevin Hansson   /// are separate from the fractional bits and do not include the sign or
781a995a0aSBevin Hansson   /// padding bit.
791a995a0aSBevin Hansson   unsigned getIntegralBits() const {
801654b22aSTyker     return std::max(getMsbWeight() + 1 - hasSignOrPaddingBit(), 0);
811a995a0aSBevin Hansson   }
821a995a0aSBevin Hansson 
831a995a0aSBevin Hansson   /// Return the FixedPointSemantics that allows for calculating the full
841a995a0aSBevin Hansson   /// precision semantic that can precisely represent the precision and ranges
851a995a0aSBevin Hansson   /// of both input values. This does not compute the resulting semantics for a
861a995a0aSBevin Hansson   /// given binary operation.
871a995a0aSBevin Hansson   FixedPointSemantics
881a995a0aSBevin Hansson   getCommonSemantics(const FixedPointSemantics &Other) const;
891a995a0aSBevin Hansson 
901654b22aSTyker   /// Print semantics for debug purposes
911654b22aSTyker   void print(llvm::raw_ostream& OS) const;
921654b22aSTyker 
93dd3014f3SBevin Hansson   /// Returns true if this fixed-point semantic with its value bits interpreted
94dd3014f3SBevin Hansson   /// as an integer can fit in the given floating point semantic without
95dd3014f3SBevin Hansson   /// overflowing to infinity.
96dd3014f3SBevin Hansson   /// For example, a signed 8-bit fixed-point semantic has a maximum and
97dd3014f3SBevin Hansson   /// minimum integer representation of 127 and -128, respectively. If both of
98dd3014f3SBevin Hansson   /// these values can be represented (possibly inexactly) in the floating
99dd3014f3SBevin Hansson   /// point semantic without overflowing, this returns true.
100dd3014f3SBevin Hansson   bool fitsInFloatSemantics(const fltSemantics &FloatSema) const;
101dd3014f3SBevin Hansson 
1021a995a0aSBevin Hansson   /// Return the FixedPointSemantics for an integer type.
1031a995a0aSBevin Hansson   static FixedPointSemantics GetIntegerSemantics(unsigned Width,
1041a995a0aSBevin Hansson                                                  bool IsSigned) {
1051a995a0aSBevin Hansson     return FixedPointSemantics(Width, /*Scale=*/0, IsSigned,
1061a995a0aSBevin Hansson                                /*IsSaturated=*/false,
1071a995a0aSBevin Hansson                                /*HasUnsignedPadding=*/false);
1081a995a0aSBevin Hansson   }
1091a995a0aSBevin Hansson 
1101654b22aSTyker   bool operator==(FixedPointSemantics Other) const {
1111654b22aSTyker     return Width == Other.Width && LsbWeight == Other.LsbWeight &&
1121654b22aSTyker            IsSigned == Other.IsSigned && IsSaturated == Other.IsSaturated &&
1131654b22aSTyker            HasUnsignedPadding == Other.HasUnsignedPadding;
1141654b22aSTyker   }
1151654b22aSTyker   bool operator!=(FixedPointSemantics Other) const { return !(*this == Other); }
1161654b22aSTyker 
117a579782aSTimm Baeder   /// Convert the semantics to a 32-bit unsigned integer.
118a579782aSTimm Baeder   /// The result is dependent on the host endianness and not stable across LLVM
119a579782aSTimm Baeder   /// versions. See getFromOpaqueInt() to convert it back to a
120a579782aSTimm Baeder   /// FixedPointSemantics object.
121a579782aSTimm Baeder   uint32_t toOpaqueInt() const;
122a579782aSTimm Baeder   /// Create a FixedPointSemantics object from an integer created via
123a579782aSTimm Baeder   /// toOpaqueInt().
124a579782aSTimm Baeder   static FixedPointSemantics getFromOpaqueInt(uint32_t);
125a579782aSTimm Baeder 
1261a995a0aSBevin Hansson private:
1271654b22aSTyker   unsigned Width          : WidthBitWidth;
1281654b22aSTyker   signed int LsbWeight    : LsbWeightBitWidth;
1291a995a0aSBevin Hansson   unsigned IsSigned       : 1;
1301a995a0aSBevin Hansson   unsigned IsSaturated    : 1;
1311a995a0aSBevin Hansson   unsigned HasUnsignedPadding : 1;
1321a995a0aSBevin Hansson };
1331a995a0aSBevin Hansson 
1341654b22aSTyker static_assert(sizeof(FixedPointSemantics) == 4, "");
1351654b22aSTyker 
1361654b22aSTyker inline hash_code hash_value(const FixedPointSemantics &Val) {
1371654b22aSTyker   return hash_value(bit_cast<uint32_t>(Val));
1381654b22aSTyker }
1391654b22aSTyker 
1401654b22aSTyker template <> struct DenseMapInfo<FixedPointSemantics> {
1411654b22aSTyker   static inline FixedPointSemantics getEmptyKey() {
1421654b22aSTyker     return FixedPointSemantics(0, 0, false, false, false);
1431654b22aSTyker   }
1441654b22aSTyker 
1451654b22aSTyker   static inline FixedPointSemantics getTombstoneKey() {
1461654b22aSTyker     return FixedPointSemantics(0, 1, false, false, false);
1471654b22aSTyker   }
1481654b22aSTyker 
1491654b22aSTyker   static unsigned getHashValue(const FixedPointSemantics &Val) {
1501654b22aSTyker     return hash_value(Val);
1511654b22aSTyker   }
1521654b22aSTyker 
1531654b22aSTyker   static bool isEqual(const char &LHS, const char &RHS) { return LHS == RHS; }
1541654b22aSTyker };
1551654b22aSTyker 
1561a995a0aSBevin Hansson /// The APFixedPoint class works similarly to APInt/APSInt in that it is a
1571654b22aSTyker /// functional replacement for a scaled integer. It supports a wide range of
1581654b22aSTyker /// semantics including the one used by fixed point types proposed in ISO/IEC
1591654b22aSTyker /// JTC1 SC22 WG14 N1169. The class carries the value and semantics of
1601654b22aSTyker /// a fixed point, and provides different operations that would normally be
1611654b22aSTyker /// performed on fixed point types.
1621a995a0aSBevin Hansson class APFixedPoint {
1631a995a0aSBevin Hansson public:
1641a995a0aSBevin Hansson   APFixedPoint(const APInt &Val, const FixedPointSemantics &Sema)
1651a995a0aSBevin Hansson       : Val(Val, !Sema.isSigned()), Sema(Sema) {
1661a995a0aSBevin Hansson     assert(Val.getBitWidth() == Sema.getWidth() &&
1671a995a0aSBevin Hansson            "The value should have a bit width that matches the Sema width");
1681a995a0aSBevin Hansson   }
1691a995a0aSBevin Hansson 
1701a995a0aSBevin Hansson   APFixedPoint(uint64_t Val, const FixedPointSemantics &Sema)
171*255a99c2SNikita Popov       : APFixedPoint(APInt(Sema.getWidth(), Val, Sema.isSigned(),
172*255a99c2SNikita Popov                            /*implicitTrunc=*/true),
173*255a99c2SNikita Popov                      Sema) {}
1741a995a0aSBevin Hansson 
1751a995a0aSBevin Hansson   // Zero initialization.
1761a995a0aSBevin Hansson   APFixedPoint(const FixedPointSemantics &Sema) : APFixedPoint(0, Sema) {}
1771a995a0aSBevin Hansson 
1781a995a0aSBevin Hansson   APSInt getValue() const { return APSInt(Val, !Sema.isSigned()); }
1791a995a0aSBevin Hansson   inline unsigned getWidth() const { return Sema.getWidth(); }
1801a995a0aSBevin Hansson   inline unsigned getScale() const { return Sema.getScale(); }
1811654b22aSTyker   int getLsbWeight() const { return Sema.getLsbWeight(); }
1821654b22aSTyker   int getMsbWeight() const { return Sema.getMsbWeight(); }
1831a995a0aSBevin Hansson   inline bool isSaturated() const { return Sema.isSaturated(); }
1841a995a0aSBevin Hansson   inline bool isSigned() const { return Sema.isSigned(); }
1851a995a0aSBevin Hansson   inline bool hasPadding() const { return Sema.hasUnsignedPadding(); }
1861a995a0aSBevin Hansson   FixedPointSemantics getSemantics() const { return Sema; }
1871a995a0aSBevin Hansson 
1881a995a0aSBevin Hansson   bool getBoolValue() const { return Val.getBoolValue(); }
1891a995a0aSBevin Hansson 
1901a995a0aSBevin Hansson   // Convert this number to match the semantics provided. If the overflow
1911a995a0aSBevin Hansson   // parameter is provided, set this value to true or false to indicate if this
1921a995a0aSBevin Hansson   // operation results in an overflow.
1931a995a0aSBevin Hansson   APFixedPoint convert(const FixedPointSemantics &DstSema,
1941a995a0aSBevin Hansson                        bool *Overflow = nullptr) const;
1951a995a0aSBevin Hansson 
1961a995a0aSBevin Hansson   // Perform binary operations on a fixed point type. The resulting fixed point
1971a995a0aSBevin Hansson   // value will be in the common, full precision semantics that can represent
1981a995a0aSBevin Hansson   // the precision and ranges of both input values. See convert() for an
1991a995a0aSBevin Hansson   // explanation of the Overflow parameter.
2001a995a0aSBevin Hansson   APFixedPoint add(const APFixedPoint &Other, bool *Overflow = nullptr) const;
2011a995a0aSBevin Hansson   APFixedPoint sub(const APFixedPoint &Other, bool *Overflow = nullptr) const;
2021a995a0aSBevin Hansson   APFixedPoint mul(const APFixedPoint &Other, bool *Overflow = nullptr) const;
2031a995a0aSBevin Hansson   APFixedPoint div(const APFixedPoint &Other, bool *Overflow = nullptr) const;
2041a995a0aSBevin Hansson 
2051a995a0aSBevin Hansson   // Perform shift operations on a fixed point type. Unlike the other binary
2061a995a0aSBevin Hansson   // operations, the resulting fixed point value will be in the original
2071a995a0aSBevin Hansson   // semantic.
2081a995a0aSBevin Hansson   APFixedPoint shl(unsigned Amt, bool *Overflow = nullptr) const;
2091a995a0aSBevin Hansson   APFixedPoint shr(unsigned Amt, bool *Overflow = nullptr) const {
2101a995a0aSBevin Hansson     // Right shift cannot overflow.
2111a995a0aSBevin Hansson     if (Overflow)
2121a995a0aSBevin Hansson       *Overflow = false;
2131a995a0aSBevin Hansson     return APFixedPoint(Val >> Amt, Sema);
2141a995a0aSBevin Hansson   }
2151a995a0aSBevin Hansson 
2161a995a0aSBevin Hansson   /// Perform a unary negation (-X) on this fixed point type, taking into
2171a995a0aSBevin Hansson   /// account saturation if applicable.
2181a995a0aSBevin Hansson   APFixedPoint negate(bool *Overflow = nullptr) const;
2191a995a0aSBevin Hansson 
2201a995a0aSBevin Hansson   /// Return the integral part of this fixed point number, rounded towards
2211a995a0aSBevin Hansson   /// zero. (-2.5k -> -2)
2221a995a0aSBevin Hansson   APSInt getIntPart() const {
2231654b22aSTyker     if (getMsbWeight() < 0)
2241654b22aSTyker       return APSInt(APInt::getZero(getWidth()), Val.isUnsigned());
2251654b22aSTyker     APSInt ExtVal =
2261654b22aSTyker         (getLsbWeight() > 0) ? Val.extend(getWidth() + getLsbWeight()) : Val;
2271a995a0aSBevin Hansson     if (Val < 0 && Val != -Val) // Cover the case when we have the min val
2282c7b7ecaSTyker       return -((-ExtVal).relativeShl(getLsbWeight()));
2291654b22aSTyker     return ExtVal.relativeShl(getLsbWeight());
2301a995a0aSBevin Hansson   }
2311a995a0aSBevin Hansson 
2321a995a0aSBevin Hansson   /// Return the integral part of this fixed point number, rounded towards
2331a995a0aSBevin Hansson   /// zero. The value is stored into an APSInt with the provided width and sign.
2341a995a0aSBevin Hansson   /// If the overflow parameter is provided, and the integral value is not able
2351a995a0aSBevin Hansson   /// to be fully stored in the provided width and sign, the overflow parameter
2361a995a0aSBevin Hansson   /// is set to true.
2371a995a0aSBevin Hansson   APSInt convertToInt(unsigned DstWidth, bool DstSign,
2381a995a0aSBevin Hansson                       bool *Overflow = nullptr) const;
2391a995a0aSBevin Hansson 
240dd3014f3SBevin Hansson   /// Convert this fixed point number to a floating point value with the
241dd3014f3SBevin Hansson   /// provided semantics.
242dd3014f3SBevin Hansson   APFloat convertToFloat(const fltSemantics &FloatSema) const;
243dd3014f3SBevin Hansson 
2441a995a0aSBevin Hansson   void toString(SmallVectorImpl<char> &Str) const;
2451a995a0aSBevin Hansson   std::string toString() const {
2461a995a0aSBevin Hansson     SmallString<40> S;
2471a995a0aSBevin Hansson     toString(S);
248b7a66d0fSKazu Hirata     return std::string(S);
2491a995a0aSBevin Hansson   }
2501a995a0aSBevin Hansson 
2511654b22aSTyker   void print(raw_ostream &) const;
2521654b22aSTyker   void dump() const;
2531654b22aSTyker 
2541a995a0aSBevin Hansson   // If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1.
2551a995a0aSBevin Hansson   int compare(const APFixedPoint &Other) const;
2561a995a0aSBevin Hansson   bool operator==(const APFixedPoint &Other) const {
2571a995a0aSBevin Hansson     return compare(Other) == 0;
2581a995a0aSBevin Hansson   }
2591a995a0aSBevin Hansson   bool operator!=(const APFixedPoint &Other) const {
2601a995a0aSBevin Hansson     return compare(Other) != 0;
2611a995a0aSBevin Hansson   }
2621a995a0aSBevin Hansson   bool operator>(const APFixedPoint &Other) const { return compare(Other) > 0; }
2631a995a0aSBevin Hansson   bool operator<(const APFixedPoint &Other) const { return compare(Other) < 0; }
2641a995a0aSBevin Hansson   bool operator>=(const APFixedPoint &Other) const {
2651a995a0aSBevin Hansson     return compare(Other) >= 0;
2661a995a0aSBevin Hansson   }
2671a995a0aSBevin Hansson   bool operator<=(const APFixedPoint &Other) const {
2681a995a0aSBevin Hansson     return compare(Other) <= 0;
2691a995a0aSBevin Hansson   }
2701a995a0aSBevin Hansson 
2711a995a0aSBevin Hansson   static APFixedPoint getMax(const FixedPointSemantics &Sema);
2721a995a0aSBevin Hansson   static APFixedPoint getMin(const FixedPointSemantics &Sema);
273ad49657aSPiJoules   static APFixedPoint getEpsilon(const FixedPointSemantics &Sema);
2741a995a0aSBevin Hansson 
275dd3014f3SBevin Hansson   /// Given a floating point semantic, return the next floating point semantic
276dd3014f3SBevin Hansson   /// with a larger exponent and larger or equal mantissa.
277dd3014f3SBevin Hansson   static const fltSemantics *promoteFloatSemantics(const fltSemantics *S);
278dd3014f3SBevin Hansson 
2791a995a0aSBevin Hansson   /// Create an APFixedPoint with a value equal to that of the provided integer,
2801a995a0aSBevin Hansson   /// and in the same semantics as the provided target semantics. If the value
2811a995a0aSBevin Hansson   /// is not able to fit in the specified fixed point semantics, and the
2821a995a0aSBevin Hansson   /// overflow parameter is provided, it is set to true.
2831a995a0aSBevin Hansson   static APFixedPoint getFromIntValue(const APSInt &Value,
2841a995a0aSBevin Hansson                                       const FixedPointSemantics &DstFXSema,
2851a995a0aSBevin Hansson                                       bool *Overflow = nullptr);
2861a995a0aSBevin Hansson 
287dd3014f3SBevin Hansson   /// Create an APFixedPoint with a value equal to that of the provided
288dd3014f3SBevin Hansson   /// floating point value, in the provided target semantics. If the value is
289dd3014f3SBevin Hansson   /// not able to fit in the specified fixed point semantics and the overflow
290dd3014f3SBevin Hansson   /// parameter is specified, it is set to true.
291dd3014f3SBevin Hansson   /// For NaN, the Overflow flag is always set. For +inf and -inf, if the
292dd3014f3SBevin Hansson   /// semantic is saturating, the value saturates. Otherwise, the Overflow flag
293dd3014f3SBevin Hansson   /// is set.
294dd3014f3SBevin Hansson   static APFixedPoint getFromFloatValue(const APFloat &Value,
295dd3014f3SBevin Hansson                                         const FixedPointSemantics &DstFXSema,
296dd3014f3SBevin Hansson                                         bool *Overflow = nullptr);
297dd3014f3SBevin Hansson 
2981a995a0aSBevin Hansson private:
2991a995a0aSBevin Hansson   APSInt Val;
3001a995a0aSBevin Hansson   FixedPointSemantics Sema;
3011a995a0aSBevin Hansson };
3021a995a0aSBevin Hansson 
3031a995a0aSBevin Hansson inline raw_ostream &operator<<(raw_ostream &OS, const APFixedPoint &FX) {
3041a995a0aSBevin Hansson   OS << FX.toString();
3051a995a0aSBevin Hansson   return OS;
3061a995a0aSBevin Hansson }
3071a995a0aSBevin Hansson 
3081654b22aSTyker inline hash_code hash_value(const APFixedPoint &Val) {
3091654b22aSTyker   return hash_combine(Val.getSemantics(), Val.getValue());
3101654b22aSTyker }
3111654b22aSTyker 
3121654b22aSTyker template <> struct DenseMapInfo<APFixedPoint> {
3131654b22aSTyker   static inline APFixedPoint getEmptyKey() {
3141654b22aSTyker     return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getEmptyKey());
3151654b22aSTyker   }
3161654b22aSTyker 
3171654b22aSTyker   static inline APFixedPoint getTombstoneKey() {
3181654b22aSTyker     return APFixedPoint(DenseMapInfo<FixedPointSemantics>::getTombstoneKey());
3191654b22aSTyker   }
3201654b22aSTyker 
3211654b22aSTyker   static unsigned getHashValue(const APFixedPoint &Val) {
3221654b22aSTyker     return hash_value(Val);
3231654b22aSTyker   }
3241654b22aSTyker 
3251654b22aSTyker   static bool isEqual(const APFixedPoint &LHS, const APFixedPoint &RHS) {
3261654b22aSTyker     return LHS.getSemantics() == RHS.getSemantics() &&
3271654b22aSTyker            LHS.getValue() == RHS.getValue();
3281654b22aSTyker   }
3291654b22aSTyker };
3301654b22aSTyker 
3311a995a0aSBevin Hansson } // namespace llvm
3321a995a0aSBevin Hansson 
3331a995a0aSBevin Hansson #endif
334