xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/AST/Interp/Integral.h (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Defines the VM types and helpers operating on types.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H
147330f729Sjoerg #define LLVM_CLANG_AST_INTERP_INTEGRAL_H
157330f729Sjoerg 
167330f729Sjoerg #include "clang/AST/ComparisonCategories.h"
177330f729Sjoerg #include "clang/AST/APValue.h"
187330f729Sjoerg #include "llvm/ADT/APSInt.h"
197330f729Sjoerg #include "llvm/Support/MathExtras.h"
207330f729Sjoerg #include "llvm/Support/raw_ostream.h"
217330f729Sjoerg #include <cstddef>
227330f729Sjoerg #include <cstdint>
237330f729Sjoerg 
247330f729Sjoerg namespace clang {
257330f729Sjoerg namespace interp {
267330f729Sjoerg 
277330f729Sjoerg using APInt = llvm::APInt;
287330f729Sjoerg using APSInt = llvm::APSInt;
297330f729Sjoerg 
307330f729Sjoerg /// Helper to compare two comparable types.
317330f729Sjoerg template <typename T>
Compare(const T & X,const T & Y)327330f729Sjoerg ComparisonCategoryResult Compare(const T &X, const T &Y) {
337330f729Sjoerg   if (X < Y)
347330f729Sjoerg     return ComparisonCategoryResult::Less;
357330f729Sjoerg   if (X > Y)
367330f729Sjoerg     return ComparisonCategoryResult::Greater;
377330f729Sjoerg   return ComparisonCategoryResult::Equal;
387330f729Sjoerg }
397330f729Sjoerg 
407330f729Sjoerg // Helper structure to select the representation.
417330f729Sjoerg template <unsigned Bits, bool Signed> struct Repr;
427330f729Sjoerg template <> struct Repr<8, false> { using Type = uint8_t; };
437330f729Sjoerg template <> struct Repr<16, false> { using Type = uint16_t; };
447330f729Sjoerg template <> struct Repr<32, false> { using Type = uint32_t; };
457330f729Sjoerg template <> struct Repr<64, false> { using Type = uint64_t; };
467330f729Sjoerg template <> struct Repr<8, true> { using Type = int8_t; };
477330f729Sjoerg template <> struct Repr<16, true> { using Type = int16_t; };
487330f729Sjoerg template <> struct Repr<32, true> { using Type = int32_t; };
497330f729Sjoerg template <> struct Repr<64, true> { using Type = int64_t; };
507330f729Sjoerg 
517330f729Sjoerg /// Wrapper around numeric types.
527330f729Sjoerg ///
537330f729Sjoerg /// These wrappers are required to shared an interface between APSint and
547330f729Sjoerg /// builtin primitive numeral types, while optimising for storage and
557330f729Sjoerg /// allowing methods operating on primitive type to compile to fast code.
567330f729Sjoerg template <unsigned Bits, bool Signed> class Integral {
577330f729Sjoerg private:
587330f729Sjoerg   template <unsigned OtherBits, bool OtherSigned> friend class Integral;
597330f729Sjoerg 
607330f729Sjoerg   // The primitive representing the integral.
617330f729Sjoerg   using T = typename Repr<Bits, Signed>::Type;
627330f729Sjoerg   T V;
637330f729Sjoerg 
647330f729Sjoerg   /// Primitive representing limits.
657330f729Sjoerg   static const auto Min = std::numeric_limits<T>::min();
667330f729Sjoerg   static const auto Max = std::numeric_limits<T>::max();
677330f729Sjoerg 
687330f729Sjoerg   /// Construct an integral from anything that is convertible to storage.
697330f729Sjoerg   template <typename T> explicit Integral(T V) : V(V) {}
707330f729Sjoerg 
717330f729Sjoerg public:
727330f729Sjoerg   /// Zero-initializes an integral.
737330f729Sjoerg   Integral() : V(0) {}
747330f729Sjoerg 
757330f729Sjoerg   /// Constructs an integral from another integral.
767330f729Sjoerg   template <unsigned SrcBits, bool SrcSign>
777330f729Sjoerg   explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
787330f729Sjoerg 
797330f729Sjoerg   /// Construct an integral from a value based on signedness.
807330f729Sjoerg   explicit Integral(const APSInt &V)
817330f729Sjoerg       : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
827330f729Sjoerg 
837330f729Sjoerg   bool operator<(Integral RHS) const { return V < RHS.V; }
847330f729Sjoerg   bool operator>(Integral RHS) const { return V > RHS.V; }
857330f729Sjoerg   bool operator<=(Integral RHS) const { return V <= RHS.V; }
867330f729Sjoerg   bool operator>=(Integral RHS) const { return V >= RHS.V; }
877330f729Sjoerg   bool operator==(Integral RHS) const { return V == RHS.V; }
887330f729Sjoerg   bool operator!=(Integral RHS) const { return V != RHS.V; }
897330f729Sjoerg 
907330f729Sjoerg   bool operator>(unsigned RHS) const {
917330f729Sjoerg     return V >= 0 && static_cast<unsigned>(V) > RHS;
927330f729Sjoerg   }
937330f729Sjoerg 
947330f729Sjoerg   Integral operator-() const { return Integral(-V); }
957330f729Sjoerg   Integral operator~() const { return Integral(~V); }
967330f729Sjoerg 
977330f729Sjoerg   template <unsigned DstBits, bool DstSign>
987330f729Sjoerg   explicit operator Integral<DstBits, DstSign>() const {
997330f729Sjoerg     return Integral<DstBits, DstSign>(V);
1007330f729Sjoerg   }
1017330f729Sjoerg 
1027330f729Sjoerg   explicit operator unsigned() const { return V; }
1037330f729Sjoerg   explicit operator int64_t() const { return V; }
1047330f729Sjoerg   explicit operator uint64_t() const { return V; }
1057330f729Sjoerg 
1067330f729Sjoerg   APSInt toAPSInt() const {
1077330f729Sjoerg     return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
1087330f729Sjoerg   }
1097330f729Sjoerg   APSInt toAPSInt(unsigned NumBits) const {
1107330f729Sjoerg     if (Signed)
1117330f729Sjoerg       return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
1127330f729Sjoerg     else
1137330f729Sjoerg       return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
1147330f729Sjoerg   }
1157330f729Sjoerg   APValue toAPValue() const { return APValue(toAPSInt()); }
1167330f729Sjoerg 
1177330f729Sjoerg   Integral<Bits, false> toUnsigned() const {
1187330f729Sjoerg     return Integral<Bits, false>(*this);
1197330f729Sjoerg   }
1207330f729Sjoerg 
1217330f729Sjoerg   constexpr static unsigned bitWidth() { return Bits; }
1227330f729Sjoerg 
1237330f729Sjoerg   bool isZero() const { return !V; }
1247330f729Sjoerg 
1257330f729Sjoerg   bool isMin() const { return *this == min(bitWidth()); }
1267330f729Sjoerg 
1277330f729Sjoerg   bool isMinusOne() const { return Signed && V == T(-1); }
1287330f729Sjoerg 
1297330f729Sjoerg   constexpr static bool isSigned() { return Signed; }
1307330f729Sjoerg 
1317330f729Sjoerg   bool isNegative() const { return V < T(0); }
1327330f729Sjoerg   bool isPositive() const { return !isNegative(); }
1337330f729Sjoerg 
1347330f729Sjoerg   ComparisonCategoryResult compare(const Integral &RHS) const {
1357330f729Sjoerg     return Compare(V, RHS.V);
1367330f729Sjoerg   }
1377330f729Sjoerg 
1387330f729Sjoerg   unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); }
1397330f729Sjoerg 
1407330f729Sjoerg   Integral truncate(unsigned TruncBits) const {
1417330f729Sjoerg     if (TruncBits >= Bits)
1427330f729Sjoerg       return *this;
1437330f729Sjoerg     const T BitMask = (T(1) << T(TruncBits)) - 1;
1447330f729Sjoerg     const T SignBit = T(1) << (TruncBits - 1);
1457330f729Sjoerg     const T ExtMask = ~BitMask;
1467330f729Sjoerg     return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
1477330f729Sjoerg   }
1487330f729Sjoerg 
1497330f729Sjoerg   void print(llvm::raw_ostream &OS) const { OS << V; }
1507330f729Sjoerg 
1517330f729Sjoerg   static Integral min(unsigned NumBits) {
1527330f729Sjoerg     return Integral(Min);
1537330f729Sjoerg   }
1547330f729Sjoerg   static Integral max(unsigned NumBits) {
1557330f729Sjoerg     return Integral(Max);
1567330f729Sjoerg   }
1577330f729Sjoerg 
1587330f729Sjoerg   template <typename T>
159*e038c9c4Sjoerg   static std::enable_if_t<std::is_integral<T>::value, Integral> from(T Value) {
1607330f729Sjoerg     return Integral(Value);
1617330f729Sjoerg   }
1627330f729Sjoerg 
1637330f729Sjoerg   template <unsigned SrcBits, bool SrcSign>
164*e038c9c4Sjoerg   static std::enable_if_t<SrcBits != 0, Integral>
1657330f729Sjoerg   from(Integral<SrcBits, SrcSign> Value) {
1667330f729Sjoerg     return Integral(Value.V);
1677330f729Sjoerg   }
1687330f729Sjoerg 
1697330f729Sjoerg   template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
1707330f729Sjoerg     if (SrcSign)
1717330f729Sjoerg       return Integral(Value.V.getSExtValue());
1727330f729Sjoerg     else
1737330f729Sjoerg       return Integral(Value.V.getZExtValue());
1747330f729Sjoerg   }
1757330f729Sjoerg 
1767330f729Sjoerg   static Integral zero() { return from(0); }
1777330f729Sjoerg 
1787330f729Sjoerg   template <typename T> static Integral from(T Value, unsigned NumBits) {
1797330f729Sjoerg     return Integral(Value);
1807330f729Sjoerg   }
1817330f729Sjoerg 
1827330f729Sjoerg   static bool inRange(int64_t Value, unsigned NumBits) {
1837330f729Sjoerg     return CheckRange<T, Min, Max>(Value);
1847330f729Sjoerg   }
1857330f729Sjoerg 
1867330f729Sjoerg   static bool increment(Integral A, Integral *R) {
1877330f729Sjoerg     return add(A, Integral(T(1)), A.bitWidth(), R);
1887330f729Sjoerg   }
1897330f729Sjoerg 
1907330f729Sjoerg   static bool decrement(Integral A, Integral *R) {
1917330f729Sjoerg     return sub(A, Integral(T(1)), A.bitWidth(), R);
1927330f729Sjoerg   }
1937330f729Sjoerg 
1947330f729Sjoerg   static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
1957330f729Sjoerg     return CheckAddUB(A.V, B.V, R->V);
1967330f729Sjoerg   }
1977330f729Sjoerg 
1987330f729Sjoerg   static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
1997330f729Sjoerg     return CheckSubUB(A.V, B.V, R->V);
2007330f729Sjoerg   }
2017330f729Sjoerg 
2027330f729Sjoerg   static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
2037330f729Sjoerg     return CheckMulUB(A.V, B.V, R->V);
2047330f729Sjoerg   }
2057330f729Sjoerg 
2067330f729Sjoerg private:
2077330f729Sjoerg   template <typename T>
208*e038c9c4Sjoerg   static std::enable_if_t<std::is_signed<T>::value, bool> CheckAddUB(T A, T B,
209*e038c9c4Sjoerg                                                                      T &R) {
2107330f729Sjoerg     return llvm::AddOverflow<T>(A, B, R);
2117330f729Sjoerg   }
2127330f729Sjoerg 
2137330f729Sjoerg   template <typename T>
214*e038c9c4Sjoerg   static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckAddUB(T A, T B,
215*e038c9c4Sjoerg                                                                        T &R) {
2167330f729Sjoerg     R = A + B;
2177330f729Sjoerg     return false;
2187330f729Sjoerg   }
2197330f729Sjoerg 
2207330f729Sjoerg   template <typename T>
221*e038c9c4Sjoerg   static std::enable_if_t<std::is_signed<T>::value, bool> CheckSubUB(T A, T B,
222*e038c9c4Sjoerg                                                                      T &R) {
2237330f729Sjoerg     return llvm::SubOverflow<T>(A, B, R);
2247330f729Sjoerg   }
2257330f729Sjoerg 
2267330f729Sjoerg   template <typename T>
227*e038c9c4Sjoerg   static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckSubUB(T A, T B,
228*e038c9c4Sjoerg                                                                        T &R) {
2297330f729Sjoerg     R = A - B;
2307330f729Sjoerg     return false;
2317330f729Sjoerg   }
2327330f729Sjoerg 
2337330f729Sjoerg   template <typename T>
234*e038c9c4Sjoerg   static std::enable_if_t<std::is_signed<T>::value, bool> CheckMulUB(T A, T B,
235*e038c9c4Sjoerg                                                                      T &R) {
2367330f729Sjoerg     return llvm::MulOverflow<T>(A, B, R);
2377330f729Sjoerg   }
2387330f729Sjoerg 
2397330f729Sjoerg   template <typename T>
240*e038c9c4Sjoerg   static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckMulUB(T A, T B,
241*e038c9c4Sjoerg                                                                        T &R) {
2427330f729Sjoerg     R = A * B;
2437330f729Sjoerg     return false;
2447330f729Sjoerg   }
2457330f729Sjoerg 
2467330f729Sjoerg   template <typename T, T Min, T Max>
247*e038c9c4Sjoerg   static std::enable_if_t<std::is_signed<T>::value, bool>
2487330f729Sjoerg   CheckRange(int64_t V) {
2497330f729Sjoerg     return Min <= V && V <= Max;
2507330f729Sjoerg   }
2517330f729Sjoerg 
2527330f729Sjoerg   template <typename T, T Min, T Max>
253*e038c9c4Sjoerg   static std::enable_if_t<std::is_unsigned<T>::value, bool>
2547330f729Sjoerg   CheckRange(int64_t V) {
2557330f729Sjoerg     return V >= 0 && static_cast<uint64_t>(V) <= Max;
2567330f729Sjoerg   }
2577330f729Sjoerg };
2587330f729Sjoerg 
2597330f729Sjoerg template <unsigned Bits, bool Signed>
2607330f729Sjoerg llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
2617330f729Sjoerg   I.print(OS);
2627330f729Sjoerg   return OS;
2637330f729Sjoerg }
2647330f729Sjoerg 
2657330f729Sjoerg } // namespace interp
2667330f729Sjoerg } // namespace clang
2677330f729Sjoerg 
2687330f729Sjoerg #endif
269