Home | History | Annotate | Line # | Download | only in Interp
Integral.h revision 1.1.1.1.4.1
      1 //===--- Integral.h - Wrapper for numeric types for the VM ------*- 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 // Defines the VM types and helpers operating on types.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H
     14 #define LLVM_CLANG_AST_INTERP_INTEGRAL_H
     15 
     16 #include "clang/AST/ComparisonCategories.h"
     17 #include "clang/AST/APValue.h"
     18 #include "llvm/ADT/APSInt.h"
     19 #include "llvm/Support/MathExtras.h"
     20 #include "llvm/Support/raw_ostream.h"
     21 #include <cstddef>
     22 #include <cstdint>
     23 
     24 namespace clang {
     25 namespace interp {
     26 
     27 using APInt = llvm::APInt;
     28 using APSInt = llvm::APSInt;
     29 
     30 /// Helper to compare two comparable types.
     31 template <typename T>
     32 ComparisonCategoryResult Compare(const T &X, const T &Y) {
     33   if (X < Y)
     34     return ComparisonCategoryResult::Less;
     35   if (X > Y)
     36     return ComparisonCategoryResult::Greater;
     37   return ComparisonCategoryResult::Equal;
     38 }
     39 
     40 // Helper structure to select the representation.
     41 template <unsigned Bits, bool Signed> struct Repr;
     42 template <> struct Repr<8, false> { using Type = uint8_t; };
     43 template <> struct Repr<16, false> { using Type = uint16_t; };
     44 template <> struct Repr<32, false> { using Type = uint32_t; };
     45 template <> struct Repr<64, false> { using Type = uint64_t; };
     46 template <> struct Repr<8, true> { using Type = int8_t; };
     47 template <> struct Repr<16, true> { using Type = int16_t; };
     48 template <> struct Repr<32, true> { using Type = int32_t; };
     49 template <> struct Repr<64, true> { using Type = int64_t; };
     50 
     51 /// Wrapper around numeric types.
     52 ///
     53 /// These wrappers are required to shared an interface between APSint and
     54 /// builtin primitive numeral types, while optimising for storage and
     55 /// allowing methods operating on primitive type to compile to fast code.
     56 template <unsigned Bits, bool Signed> class Integral {
     57 private:
     58   template <unsigned OtherBits, bool OtherSigned> friend class Integral;
     59 
     60   // The primitive representing the integral.
     61   using T = typename Repr<Bits, Signed>::Type;
     62   T V;
     63 
     64   /// Primitive representing limits.
     65   static const auto Min = std::numeric_limits<T>::min();
     66   static const auto Max = std::numeric_limits<T>::max();
     67 
     68   /// Construct an integral from anything that is convertible to storage.
     69   template <typename T> explicit Integral(T V) : V(V) {}
     70 
     71 public:
     72   /// Zero-initializes an integral.
     73   Integral() : V(0) {}
     74 
     75   /// Constructs an integral from another integral.
     76   template <unsigned SrcBits, bool SrcSign>
     77   explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
     78 
     79   /// Construct an integral from a value based on signedness.
     80   explicit Integral(const APSInt &V)
     81       : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
     82 
     83   bool operator<(Integral RHS) const { return V < RHS.V; }
     84   bool operator>(Integral RHS) const { return V > RHS.V; }
     85   bool operator<=(Integral RHS) const { return V <= RHS.V; }
     86   bool operator>=(Integral RHS) const { return V >= RHS.V; }
     87   bool operator==(Integral RHS) const { return V == RHS.V; }
     88   bool operator!=(Integral RHS) const { return V != RHS.V; }
     89 
     90   bool operator>(unsigned RHS) const {
     91     return V >= 0 && static_cast<unsigned>(V) > RHS;
     92   }
     93 
     94   Integral operator-() const { return Integral(-V); }
     95   Integral operator~() const { return Integral(~V); }
     96 
     97   template <unsigned DstBits, bool DstSign>
     98   explicit operator Integral<DstBits, DstSign>() const {
     99     return Integral<DstBits, DstSign>(V);
    100   }
    101 
    102   explicit operator unsigned() const { return V; }
    103   explicit operator int64_t() const { return V; }
    104   explicit operator uint64_t() const { return V; }
    105 
    106   APSInt toAPSInt() const {
    107     return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
    108   }
    109   APSInt toAPSInt(unsigned NumBits) const {
    110     if (Signed)
    111       return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
    112     else
    113       return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
    114   }
    115   APValue toAPValue() const { return APValue(toAPSInt()); }
    116 
    117   Integral<Bits, false> toUnsigned() const {
    118     return Integral<Bits, false>(*this);
    119   }
    120 
    121   constexpr static unsigned bitWidth() { return Bits; }
    122 
    123   bool isZero() const { return !V; }
    124 
    125   bool isMin() const { return *this == min(bitWidth()); }
    126 
    127   bool isMinusOne() const { return Signed && V == T(-1); }
    128 
    129   constexpr static bool isSigned() { return Signed; }
    130 
    131   bool isNegative() const { return V < T(0); }
    132   bool isPositive() const { return !isNegative(); }
    133 
    134   ComparisonCategoryResult compare(const Integral &RHS) const {
    135     return Compare(V, RHS.V);
    136   }
    137 
    138   unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); }
    139 
    140   Integral truncate(unsigned TruncBits) const {
    141     if (TruncBits >= Bits)
    142       return *this;
    143     const T BitMask = (T(1) << T(TruncBits)) - 1;
    144     const T SignBit = T(1) << (TruncBits - 1);
    145     const T ExtMask = ~BitMask;
    146     return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
    147   }
    148 
    149   void print(llvm::raw_ostream &OS) const { OS << V; }
    150 
    151   static Integral min(unsigned NumBits) {
    152     return Integral(Min);
    153   }
    154   static Integral max(unsigned NumBits) {
    155     return Integral(Max);
    156   }
    157 
    158   template <typename T>
    159   static std::enable_if_t<std::is_integral<T>::value, Integral> from(T Value) {
    160     return Integral(Value);
    161   }
    162 
    163   template <unsigned SrcBits, bool SrcSign>
    164   static std::enable_if_t<SrcBits != 0, Integral>
    165   from(Integral<SrcBits, SrcSign> Value) {
    166     return Integral(Value.V);
    167   }
    168 
    169   template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
    170     if (SrcSign)
    171       return Integral(Value.V.getSExtValue());
    172     else
    173       return Integral(Value.V.getZExtValue());
    174   }
    175 
    176   static Integral zero() { return from(0); }
    177 
    178   template <typename T> static Integral from(T Value, unsigned NumBits) {
    179     return Integral(Value);
    180   }
    181 
    182   static bool inRange(int64_t Value, unsigned NumBits) {
    183     return CheckRange<T, Min, Max>(Value);
    184   }
    185 
    186   static bool increment(Integral A, Integral *R) {
    187     return add(A, Integral(T(1)), A.bitWidth(), R);
    188   }
    189 
    190   static bool decrement(Integral A, Integral *R) {
    191     return sub(A, Integral(T(1)), A.bitWidth(), R);
    192   }
    193 
    194   static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
    195     return CheckAddUB(A.V, B.V, R->V);
    196   }
    197 
    198   static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
    199     return CheckSubUB(A.V, B.V, R->V);
    200   }
    201 
    202   static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
    203     return CheckMulUB(A.V, B.V, R->V);
    204   }
    205 
    206 private:
    207   template <typename T>
    208   static std::enable_if_t<std::is_signed<T>::value, bool> CheckAddUB(T A, T B,
    209                                                                      T &R) {
    210     return llvm::AddOverflow<T>(A, B, R);
    211   }
    212 
    213   template <typename T>
    214   static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckAddUB(T A, T B,
    215                                                                        T &R) {
    216     R = A + B;
    217     return false;
    218   }
    219 
    220   template <typename T>
    221   static std::enable_if_t<std::is_signed<T>::value, bool> CheckSubUB(T A, T B,
    222                                                                      T &R) {
    223     return llvm::SubOverflow<T>(A, B, R);
    224   }
    225 
    226   template <typename T>
    227   static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckSubUB(T A, T B,
    228                                                                        T &R) {
    229     R = A - B;
    230     return false;
    231   }
    232 
    233   template <typename T>
    234   static std::enable_if_t<std::is_signed<T>::value, bool> CheckMulUB(T A, T B,
    235                                                                      T &R) {
    236     return llvm::MulOverflow<T>(A, B, R);
    237   }
    238 
    239   template <typename T>
    240   static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckMulUB(T A, T B,
    241                                                                        T &R) {
    242     R = A * B;
    243     return false;
    244   }
    245 
    246   template <typename T, T Min, T Max>
    247   static std::enable_if_t<std::is_signed<T>::value, bool>
    248   CheckRange(int64_t V) {
    249     return Min <= V && V <= Max;
    250   }
    251 
    252   template <typename T, T Min, T Max>
    253   static std::enable_if_t<std::is_unsigned<T>::value, bool>
    254   CheckRange(int64_t V) {
    255     return V >= 0 && static_cast<uint64_t>(V) <= Max;
    256   }
    257 };
    258 
    259 template <unsigned Bits, bool Signed>
    260 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
    261   I.print(OS);
    262   return OS;
    263 }
    264 
    265 } // namespace interp
    266 } // namespace clang
    267 
    268 #endif
    269