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