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 2406c3fb27SDimitry Andric #include "Primitives.h" 2506c3fb27SDimitry Andric 26a7dea167SDimitry Andric namespace clang { 27a7dea167SDimitry Andric namespace interp { 28a7dea167SDimitry Andric 29a7dea167SDimitry Andric using APInt = llvm::APInt; 30a7dea167SDimitry Andric using APSInt = llvm::APSInt; 31a7dea167SDimitry Andric 325f757f3fSDimitry Andric template <bool Signed> class IntegralAP; 335f757f3fSDimitry Andric 34a7dea167SDimitry Andric // Helper structure to select the representation. 35a7dea167SDimitry Andric template <unsigned Bits, bool Signed> struct Repr; 36a7dea167SDimitry Andric template <> struct Repr<8, false> { using Type = uint8_t; }; 37a7dea167SDimitry Andric template <> struct Repr<16, false> { using Type = uint16_t; }; 38a7dea167SDimitry Andric template <> struct Repr<32, false> { using Type = uint32_t; }; 39a7dea167SDimitry Andric template <> struct Repr<64, false> { using Type = uint64_t; }; 40a7dea167SDimitry Andric template <> struct Repr<8, true> { using Type = int8_t; }; 41a7dea167SDimitry Andric template <> struct Repr<16, true> { using Type = int16_t; }; 42a7dea167SDimitry Andric template <> struct Repr<32, true> { using Type = int32_t; }; 43a7dea167SDimitry Andric template <> struct Repr<64, true> { using Type = int64_t; }; 44a7dea167SDimitry Andric 45a7dea167SDimitry Andric /// Wrapper around numeric types. 46a7dea167SDimitry Andric /// 47a7dea167SDimitry Andric /// These wrappers are required to shared an interface between APSint and 48a7dea167SDimitry Andric /// builtin primitive numeral types, while optimising for storage and 49a7dea167SDimitry Andric /// allowing methods operating on primitive type to compile to fast code. 50bdd1243dSDimitry Andric template <unsigned Bits, bool Signed> class Integral final { 51a7dea167SDimitry Andric private: 52a7dea167SDimitry Andric template <unsigned OtherBits, bool OtherSigned> friend class Integral; 53a7dea167SDimitry Andric 54a7dea167SDimitry Andric // The primitive representing the integral. 55bdd1243dSDimitry Andric using ReprT = typename Repr<Bits, Signed>::Type; 56bdd1243dSDimitry Andric ReprT V; 57a7dea167SDimitry Andric 58a7dea167SDimitry Andric /// Primitive representing limits. 59bdd1243dSDimitry Andric static const auto Min = std::numeric_limits<ReprT>::min(); 60bdd1243dSDimitry Andric static const auto Max = std::numeric_limits<ReprT>::max(); 61a7dea167SDimitry Andric 62a7dea167SDimitry Andric /// Construct an integral from anything that is convertible to storage. 63a7dea167SDimitry Andric template <typename T> explicit Integral(T V) : V(V) {} 64a7dea167SDimitry Andric 65a7dea167SDimitry Andric public: 665f757f3fSDimitry Andric using AsUnsigned = Integral<Bits, false>; 675f757f3fSDimitry Andric 68a7dea167SDimitry Andric /// Zero-initializes an integral. 69a7dea167SDimitry Andric Integral() : V(0) {} 70a7dea167SDimitry Andric 71a7dea167SDimitry Andric /// Constructs an integral from another integral. 72a7dea167SDimitry Andric template <unsigned SrcBits, bool SrcSign> 73a7dea167SDimitry Andric explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {} 74a7dea167SDimitry Andric 75a7dea167SDimitry Andric /// Construct an integral from a value based on signedness. 76a7dea167SDimitry Andric explicit Integral(const APSInt &V) 77a7dea167SDimitry Andric : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {} 78a7dea167SDimitry Andric 79a7dea167SDimitry Andric bool operator<(Integral RHS) const { return V < RHS.V; } 80a7dea167SDimitry Andric bool operator>(Integral RHS) const { return V > RHS.V; } 81a7dea167SDimitry Andric bool operator<=(Integral RHS) const { return V <= RHS.V; } 82a7dea167SDimitry Andric bool operator>=(Integral RHS) const { return V >= RHS.V; } 83a7dea167SDimitry Andric bool operator==(Integral RHS) const { return V == RHS.V; } 84a7dea167SDimitry Andric bool operator!=(Integral RHS) const { return V != RHS.V; } 85a7dea167SDimitry Andric 86a7dea167SDimitry Andric bool operator>(unsigned RHS) const { 87a7dea167SDimitry Andric return V >= 0 && static_cast<unsigned>(V) > RHS; 88a7dea167SDimitry Andric } 89a7dea167SDimitry Andric 90a7dea167SDimitry Andric Integral operator-() const { return Integral(-V); } 915f757f3fSDimitry Andric Integral operator-(const Integral &Other) const { 925f757f3fSDimitry Andric return Integral(V - Other.V); 935f757f3fSDimitry Andric } 94a7dea167SDimitry Andric Integral operator~() const { return Integral(~V); } 95a7dea167SDimitry Andric 96a7dea167SDimitry Andric template <unsigned DstBits, bool DstSign> 97a7dea167SDimitry Andric explicit operator Integral<DstBits, DstSign>() const { 98a7dea167SDimitry Andric return Integral<DstBits, DstSign>(V); 99a7dea167SDimitry Andric } 100a7dea167SDimitry Andric 101*0fca6ea1SDimitry Andric template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> 102*0fca6ea1SDimitry Andric explicit operator Ty() const { 103*0fca6ea1SDimitry Andric return V; 104*0fca6ea1SDimitry Andric } 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 { 110bdd1243dSDimitry Andric if constexpr (Signed) 111a7dea167SDimitry Andric return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed); 112a7dea167SDimitry Andric else 113a7dea167SDimitry Andric return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed); 114a7dea167SDimitry Andric } 115*0fca6ea1SDimitry Andric APValue toAPValue(const ASTContext &) 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 127bdd1243dSDimitry Andric bool isMinusOne() const { return Signed && V == ReprT(-1); } 128a7dea167SDimitry Andric 129a7dea167SDimitry Andric constexpr static bool isSigned() { return Signed; } 130a7dea167SDimitry Andric 131bdd1243dSDimitry Andric bool isNegative() const { return V < ReprT(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 1385f757f3fSDimitry Andric std::string toDiagnosticString(const ASTContext &Ctx) const { 1395f757f3fSDimitry Andric std::string NameStr; 1405f757f3fSDimitry Andric llvm::raw_string_ostream OS(NameStr); 1415f757f3fSDimitry Andric OS << V; 1425f757f3fSDimitry Andric return NameStr; 1435f757f3fSDimitry Andric } 1445f757f3fSDimitry Andric 145bdd1243dSDimitry Andric unsigned countLeadingZeros() const { 14606c3fb27SDimitry Andric if constexpr (!Signed) 14706c3fb27SDimitry Andric return llvm::countl_zero<ReprT>(V); 14806c3fb27SDimitry Andric llvm_unreachable("Don't call countLeadingZeros() on signed types."); 149bdd1243dSDimitry Andric } 150a7dea167SDimitry Andric 151a7dea167SDimitry Andric Integral truncate(unsigned TruncBits) const { 152a7dea167SDimitry Andric if (TruncBits >= Bits) 153a7dea167SDimitry Andric return *this; 154bdd1243dSDimitry Andric const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1; 155bdd1243dSDimitry Andric const ReprT SignBit = ReprT(1) << (TruncBits - 1); 156bdd1243dSDimitry Andric const ReprT ExtMask = ~BitMask; 157a7dea167SDimitry Andric return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0)); 158a7dea167SDimitry Andric } 159a7dea167SDimitry Andric 160a7dea167SDimitry Andric void print(llvm::raw_ostream &OS) const { OS << V; } 161a7dea167SDimitry Andric 162a7dea167SDimitry Andric static Integral min(unsigned NumBits) { 163a7dea167SDimitry Andric return Integral(Min); 164a7dea167SDimitry Andric } 165a7dea167SDimitry Andric static Integral max(unsigned NumBits) { 166a7dea167SDimitry Andric return Integral(Max); 167a7dea167SDimitry Andric } 168a7dea167SDimitry Andric 169bdd1243dSDimitry Andric template <typename ValT> static Integral from(ValT Value) { 170bdd1243dSDimitry Andric if constexpr (std::is_integral<ValT>::value) 171a7dea167SDimitry Andric return Integral(Value); 172bdd1243dSDimitry Andric else 173bdd1243dSDimitry Andric return Integral::from(static_cast<Integral::ReprT>(Value)); 174a7dea167SDimitry Andric } 175a7dea167SDimitry Andric 176a7dea167SDimitry Andric template <unsigned SrcBits, bool SrcSign> 1775ffd83dbSDimitry Andric static std::enable_if_t<SrcBits != 0, Integral> 178a7dea167SDimitry Andric from(Integral<SrcBits, SrcSign> Value) { 179a7dea167SDimitry Andric return Integral(Value.V); 180a7dea167SDimitry Andric } 181a7dea167SDimitry Andric 182a7dea167SDimitry Andric static Integral zero() { return from(0); } 183a7dea167SDimitry Andric 184a7dea167SDimitry Andric template <typename T> static Integral from(T Value, unsigned NumBits) { 185a7dea167SDimitry Andric return Integral(Value); 186a7dea167SDimitry Andric } 187a7dea167SDimitry Andric 188a7dea167SDimitry Andric static bool inRange(int64_t Value, unsigned NumBits) { 189bdd1243dSDimitry Andric return CheckRange<ReprT, Min, Max>(Value); 190a7dea167SDimitry Andric } 191a7dea167SDimitry Andric 192a7dea167SDimitry Andric static bool increment(Integral A, Integral *R) { 193bdd1243dSDimitry Andric return add(A, Integral(ReprT(1)), A.bitWidth(), R); 194a7dea167SDimitry Andric } 195a7dea167SDimitry Andric 196a7dea167SDimitry Andric static bool decrement(Integral A, Integral *R) { 197bdd1243dSDimitry Andric return sub(A, Integral(ReprT(1)), A.bitWidth(), R); 198a7dea167SDimitry Andric } 199a7dea167SDimitry Andric 200a7dea167SDimitry Andric static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) { 201a7dea167SDimitry Andric return CheckAddUB(A.V, B.V, R->V); 202a7dea167SDimitry Andric } 203a7dea167SDimitry Andric 204a7dea167SDimitry Andric static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) { 205a7dea167SDimitry Andric return CheckSubUB(A.V, B.V, R->V); 206a7dea167SDimitry Andric } 207a7dea167SDimitry Andric 208a7dea167SDimitry Andric static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) { 209a7dea167SDimitry Andric return CheckMulUB(A.V, B.V, R->V); 210a7dea167SDimitry Andric } 211a7dea167SDimitry Andric 212bdd1243dSDimitry Andric static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) { 213bdd1243dSDimitry Andric *R = Integral(A.V % B.V); 214bdd1243dSDimitry Andric return false; 215a7dea167SDimitry Andric } 216a7dea167SDimitry Andric 217bdd1243dSDimitry Andric static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) { 218bdd1243dSDimitry Andric *R = Integral(A.V / B.V); 219bdd1243dSDimitry Andric return false; 220bdd1243dSDimitry Andric } 221bdd1243dSDimitry Andric 222bdd1243dSDimitry Andric static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) { 223bdd1243dSDimitry Andric *R = Integral(A.V & B.V); 224bdd1243dSDimitry Andric return false; 225bdd1243dSDimitry Andric } 226bdd1243dSDimitry Andric 227bdd1243dSDimitry Andric static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) { 228bdd1243dSDimitry Andric *R = Integral(A.V | B.V); 229bdd1243dSDimitry Andric return false; 230bdd1243dSDimitry Andric } 231bdd1243dSDimitry Andric 232bdd1243dSDimitry Andric static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) { 233bdd1243dSDimitry Andric *R = Integral(A.V ^ B.V); 234bdd1243dSDimitry Andric return false; 235bdd1243dSDimitry Andric } 236bdd1243dSDimitry Andric 237bdd1243dSDimitry Andric static bool neg(Integral A, Integral *R) { 23806c3fb27SDimitry Andric if (Signed && A.isMin()) 23906c3fb27SDimitry Andric return true; 24006c3fb27SDimitry Andric 241bdd1243dSDimitry Andric *R = -A; 242bdd1243dSDimitry Andric return false; 243bdd1243dSDimitry Andric } 244bdd1243dSDimitry Andric 245bdd1243dSDimitry Andric static bool comp(Integral A, Integral *R) { 246bdd1243dSDimitry Andric *R = Integral(~A.V); 247bdd1243dSDimitry Andric return false; 248bdd1243dSDimitry Andric } 249bdd1243dSDimitry Andric 25006c3fb27SDimitry Andric template <unsigned RHSBits, bool RHSSign> 25106c3fb27SDimitry Andric static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B, 25206c3fb27SDimitry Andric unsigned OpBits, Integral *R) { 25306c3fb27SDimitry Andric *R = Integral::from(A.V << B.V, OpBits); 25406c3fb27SDimitry Andric } 25506c3fb27SDimitry Andric 25606c3fb27SDimitry Andric template <unsigned RHSBits, bool RHSSign> 25706c3fb27SDimitry Andric static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B, 25806c3fb27SDimitry Andric unsigned OpBits, Integral *R) { 25906c3fb27SDimitry Andric *R = Integral::from(A.V >> B.V, OpBits); 26006c3fb27SDimitry Andric } 26106c3fb27SDimitry Andric 262bdd1243dSDimitry Andric private: 263bdd1243dSDimitry Andric template <typename T> static bool CheckAddUB(T A, T B, T &R) { 264bdd1243dSDimitry Andric if constexpr (std::is_signed_v<T>) { 265bdd1243dSDimitry Andric return llvm::AddOverflow<T>(A, B, R); 266bdd1243dSDimitry Andric } else { 267a7dea167SDimitry Andric R = A + B; 268a7dea167SDimitry Andric return false; 269a7dea167SDimitry Andric } 270a7dea167SDimitry Andric } 271a7dea167SDimitry Andric 272bdd1243dSDimitry Andric template <typename T> static bool CheckSubUB(T A, T B, T &R) { 273bdd1243dSDimitry Andric if constexpr (std::is_signed_v<T>) { 274bdd1243dSDimitry Andric return llvm::SubOverflow<T>(A, B, R); 275bdd1243dSDimitry Andric } else { 276a7dea167SDimitry Andric R = A - B; 277a7dea167SDimitry Andric return false; 278a7dea167SDimitry Andric } 279a7dea167SDimitry Andric } 280a7dea167SDimitry Andric 281bdd1243dSDimitry Andric template <typename T> static bool CheckMulUB(T A, T B, T &R) { 282bdd1243dSDimitry Andric if constexpr (std::is_signed_v<T>) { 283bdd1243dSDimitry Andric return llvm::MulOverflow<T>(A, B, R); 284bdd1243dSDimitry Andric } else { 285a7dea167SDimitry Andric R = A * B; 286a7dea167SDimitry Andric return false; 287a7dea167SDimitry Andric } 288a7dea167SDimitry Andric } 289bdd1243dSDimitry Andric template <typename T, T Min, T Max> static bool CheckRange(int64_t V) { 290bdd1243dSDimitry Andric if constexpr (std::is_signed_v<T>) { 291bdd1243dSDimitry Andric return Min <= V && V <= Max; 292bdd1243dSDimitry Andric } else { 293a7dea167SDimitry Andric return V >= 0 && static_cast<uint64_t>(V) <= Max; 294a7dea167SDimitry Andric } 295bdd1243dSDimitry Andric } 296a7dea167SDimitry Andric }; 297a7dea167SDimitry Andric 298a7dea167SDimitry Andric template <unsigned Bits, bool Signed> 299a7dea167SDimitry Andric llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) { 300a7dea167SDimitry Andric I.print(OS); 301a7dea167SDimitry Andric return OS; 302a7dea167SDimitry Andric } 303a7dea167SDimitry Andric 304a7dea167SDimitry Andric } // namespace interp 305a7dea167SDimitry Andric } // namespace clang 306a7dea167SDimitry Andric 307a7dea167SDimitry Andric #endif 308