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