1a07aba5dSTimm Baeder //===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder // 9a07aba5dSTimm Baeder // Defines the VM types and helpers operating on types. 10a07aba5dSTimm Baeder // 11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 12a07aba5dSTimm Baeder 13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H 14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_INTEGRAL_H 15a07aba5dSTimm Baeder 16a07aba5dSTimm Baeder #include "clang/AST/APValue.h" 17a07aba5dSTimm Baeder #include "clang/AST/ComparisonCategories.h" 18a07aba5dSTimm Baeder #include "llvm/ADT/APSInt.h" 19a07aba5dSTimm Baeder #include "llvm/Support/MathExtras.h" 20a07aba5dSTimm Baeder #include "llvm/Support/raw_ostream.h" 21a07aba5dSTimm Baeder #include <cstddef> 22a07aba5dSTimm Baeder #include <cstdint> 23a07aba5dSTimm Baeder 24a07aba5dSTimm Baeder #include "Primitives.h" 25a07aba5dSTimm Baeder 26a07aba5dSTimm Baeder namespace clang { 27a07aba5dSTimm Baeder namespace interp { 28a07aba5dSTimm Baeder 29a07aba5dSTimm Baeder using APInt = llvm::APInt; 30a07aba5dSTimm Baeder using APSInt = llvm::APSInt; 31a07aba5dSTimm Baeder 32a07aba5dSTimm Baeder template <bool Signed> class IntegralAP; 33a07aba5dSTimm Baeder 34a07aba5dSTimm Baeder // Helper structure to select the representation. 35a07aba5dSTimm Baeder template <unsigned Bits, bool Signed> struct Repr; 36a07aba5dSTimm Baeder template <> struct Repr<8, false> { 37a07aba5dSTimm Baeder using Type = uint8_t; 38a07aba5dSTimm Baeder }; 39a07aba5dSTimm Baeder template <> struct Repr<16, false> { 40a07aba5dSTimm Baeder using Type = uint16_t; 41a07aba5dSTimm Baeder }; 42a07aba5dSTimm Baeder template <> struct Repr<32, false> { 43a07aba5dSTimm Baeder using Type = uint32_t; 44a07aba5dSTimm Baeder }; 45a07aba5dSTimm Baeder template <> struct Repr<64, false> { 46a07aba5dSTimm Baeder using Type = uint64_t; 47a07aba5dSTimm Baeder }; 48a07aba5dSTimm Baeder template <> struct Repr<8, true> { 49a07aba5dSTimm Baeder using Type = int8_t; 50a07aba5dSTimm Baeder }; 51a07aba5dSTimm Baeder template <> struct Repr<16, true> { 52a07aba5dSTimm Baeder using Type = int16_t; 53a07aba5dSTimm Baeder }; 54a07aba5dSTimm Baeder template <> struct Repr<32, true> { 55a07aba5dSTimm Baeder using Type = int32_t; 56a07aba5dSTimm Baeder }; 57a07aba5dSTimm Baeder template <> struct Repr<64, true> { 58a07aba5dSTimm Baeder using Type = int64_t; 59a07aba5dSTimm Baeder }; 60a07aba5dSTimm Baeder 61a07aba5dSTimm Baeder /// Wrapper around numeric types. 62a07aba5dSTimm Baeder /// 63a07aba5dSTimm Baeder /// These wrappers are required to shared an interface between APSint and 64a07aba5dSTimm Baeder /// builtin primitive numeral types, while optimising for storage and 65a07aba5dSTimm Baeder /// allowing methods operating on primitive type to compile to fast code. 66a07aba5dSTimm Baeder template <unsigned Bits, bool Signed> class Integral final { 67a07aba5dSTimm Baeder private: 68a07aba5dSTimm Baeder template <unsigned OtherBits, bool OtherSigned> friend class Integral; 69a07aba5dSTimm Baeder 70a07aba5dSTimm Baeder // The primitive representing the integral. 71a07aba5dSTimm Baeder using ReprT = typename Repr<Bits, Signed>::Type; 72a07aba5dSTimm Baeder ReprT V; 73ef2a104cSTimm Baeder static_assert(std::is_trivially_copyable_v<ReprT>); 74a07aba5dSTimm Baeder 75a07aba5dSTimm Baeder /// Primitive representing limits. 76a07aba5dSTimm Baeder static const auto Min = std::numeric_limits<ReprT>::min(); 77a07aba5dSTimm Baeder static const auto Max = std::numeric_limits<ReprT>::max(); 78a07aba5dSTimm Baeder 79a07aba5dSTimm Baeder /// Construct an integral from anything that is convertible to storage. 80a07aba5dSTimm Baeder template <typename T> explicit Integral(T V) : V(V) {} 81a07aba5dSTimm Baeder 82a07aba5dSTimm Baeder public: 83a07aba5dSTimm Baeder using AsUnsigned = Integral<Bits, false>; 84a07aba5dSTimm Baeder 85a07aba5dSTimm Baeder /// Zero-initializes an integral. 86a07aba5dSTimm Baeder Integral() : V(0) {} 87a07aba5dSTimm Baeder 88a07aba5dSTimm Baeder /// Constructs an integral from another integral. 89a07aba5dSTimm Baeder template <unsigned SrcBits, bool SrcSign> 90a07aba5dSTimm Baeder explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {} 91a07aba5dSTimm Baeder 92a07aba5dSTimm Baeder /// Construct an integral from a value based on signedness. 93a07aba5dSTimm Baeder explicit Integral(const APSInt &V) 94a07aba5dSTimm Baeder : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {} 95a07aba5dSTimm Baeder 96a07aba5dSTimm Baeder bool operator<(Integral RHS) const { return V < RHS.V; } 97a07aba5dSTimm Baeder bool operator>(Integral RHS) const { return V > RHS.V; } 98a07aba5dSTimm Baeder bool operator<=(Integral RHS) const { return V <= RHS.V; } 99a07aba5dSTimm Baeder bool operator>=(Integral RHS) const { return V >= RHS.V; } 100a07aba5dSTimm Baeder bool operator==(Integral RHS) const { return V == RHS.V; } 101a07aba5dSTimm Baeder bool operator!=(Integral RHS) const { return V != RHS.V; } 102a07aba5dSTimm Baeder 103a07aba5dSTimm Baeder bool operator>(unsigned RHS) const { 104a07aba5dSTimm Baeder return V >= 0 && static_cast<unsigned>(V) > RHS; 105a07aba5dSTimm Baeder } 106a07aba5dSTimm Baeder 107a07aba5dSTimm Baeder Integral operator-() const { return Integral(-V); } 108a07aba5dSTimm Baeder Integral operator-(const Integral &Other) const { 109a07aba5dSTimm Baeder return Integral(V - Other.V); 110a07aba5dSTimm Baeder } 111a07aba5dSTimm Baeder Integral operator~() const { return Integral(~V); } 112a07aba5dSTimm Baeder 113a07aba5dSTimm Baeder template <unsigned DstBits, bool DstSign> 114a07aba5dSTimm Baeder explicit operator Integral<DstBits, DstSign>() const { 115a07aba5dSTimm Baeder return Integral<DstBits, DstSign>(V); 116a07aba5dSTimm Baeder } 117a07aba5dSTimm Baeder 118a07aba5dSTimm Baeder template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> 119a07aba5dSTimm Baeder explicit operator Ty() const { 120a07aba5dSTimm Baeder return V; 121a07aba5dSTimm Baeder } 122a07aba5dSTimm Baeder 123a07aba5dSTimm Baeder APSInt toAPSInt() const { 124a07aba5dSTimm Baeder return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed); 125a07aba5dSTimm Baeder } 126c1dcf75aSTimm Baeder APSInt toAPSInt(unsigned BitWidth) const { 127c1dcf75aSTimm Baeder return APSInt(toAPInt(BitWidth), !Signed); 128c1dcf75aSTimm Baeder } 1295b4071c7STimm Baeder APInt toAPInt(unsigned BitWidth) const { 130a07aba5dSTimm Baeder if constexpr (Signed) 1315b4071c7STimm Baeder return APInt(Bits, static_cast<uint64_t>(V), Signed) 1325b4071c7STimm Baeder .sextOrTrunc(BitWidth); 133a07aba5dSTimm Baeder else 1345b4071c7STimm Baeder return APInt(Bits, static_cast<uint64_t>(V), Signed) 1355b4071c7STimm Baeder .zextOrTrunc(BitWidth); 136a07aba5dSTimm Baeder } 137a07aba5dSTimm Baeder APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } 138a07aba5dSTimm Baeder 139a07aba5dSTimm Baeder Integral<Bits, false> toUnsigned() const { 140a07aba5dSTimm Baeder return Integral<Bits, false>(*this); 141a07aba5dSTimm Baeder } 142a07aba5dSTimm Baeder 143a07aba5dSTimm Baeder constexpr static unsigned bitWidth() { return Bits; } 144a07aba5dSTimm Baeder 145a07aba5dSTimm Baeder bool isZero() const { return !V; } 146a07aba5dSTimm Baeder 147a07aba5dSTimm Baeder bool isMin() const { return *this == min(bitWidth()); } 148a07aba5dSTimm Baeder 149a07aba5dSTimm Baeder bool isMinusOne() const { return Signed && V == ReprT(-1); } 150a07aba5dSTimm Baeder 151a07aba5dSTimm Baeder constexpr static bool isSigned() { return Signed; } 152a07aba5dSTimm Baeder 153a07aba5dSTimm Baeder bool isNegative() const { return V < ReprT(0); } 154a07aba5dSTimm Baeder bool isPositive() const { return !isNegative(); } 155a07aba5dSTimm Baeder 156a07aba5dSTimm Baeder ComparisonCategoryResult compare(const Integral &RHS) const { 157a07aba5dSTimm Baeder return Compare(V, RHS.V); 158a07aba5dSTimm Baeder } 159a07aba5dSTimm Baeder 160ef2a104cSTimm Baeder void bitcastToMemory(std::byte *Dest) const { 161ef2a104cSTimm Baeder std::memcpy(Dest, &V, sizeof(V)); 162ef2a104cSTimm Baeder } 163ef2a104cSTimm Baeder 164ef2a104cSTimm Baeder static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) { 165ef2a104cSTimm Baeder assert(BitWidth == sizeof(ReprT) * 8); 166ef2a104cSTimm Baeder ReprT V; 167ef2a104cSTimm Baeder 168ef2a104cSTimm Baeder std::memcpy(&V, Src, sizeof(ReprT)); 169ef2a104cSTimm Baeder return Integral(V); 170ef2a104cSTimm Baeder } 171ef2a104cSTimm Baeder 172a07aba5dSTimm Baeder std::string toDiagnosticString(const ASTContext &Ctx) const { 173a07aba5dSTimm Baeder std::string NameStr; 174a07aba5dSTimm Baeder llvm::raw_string_ostream OS(NameStr); 175a07aba5dSTimm Baeder OS << V; 176a07aba5dSTimm Baeder return NameStr; 177a07aba5dSTimm Baeder } 178a07aba5dSTimm Baeder 179a07aba5dSTimm Baeder unsigned countLeadingZeros() const { 180a07aba5dSTimm Baeder if constexpr (!Signed) 181a07aba5dSTimm Baeder return llvm::countl_zero<ReprT>(V); 182*2503a665STimm Bäder if (isPositive()) 183*2503a665STimm Bäder return llvm::countl_zero<typename AsUnsigned::ReprT>( 184*2503a665STimm Bäder static_cast<typename AsUnsigned::ReprT>(V)); 185*2503a665STimm Bäder llvm_unreachable("Don't call countLeadingZeros() on negative values."); 186a07aba5dSTimm Baeder } 187a07aba5dSTimm Baeder 188a07aba5dSTimm Baeder Integral truncate(unsigned TruncBits) const { 18912ca72baSTimm Bäder assert(TruncBits >= 1); 190a07aba5dSTimm Baeder if (TruncBits >= Bits) 191a07aba5dSTimm Baeder return *this; 192a07aba5dSTimm Baeder const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1; 193a07aba5dSTimm Baeder const ReprT SignBit = ReprT(1) << (TruncBits - 1); 194a07aba5dSTimm Baeder const ReprT ExtMask = ~BitMask; 195a07aba5dSTimm Baeder return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0)); 196a07aba5dSTimm Baeder } 197a07aba5dSTimm Baeder 198a07aba5dSTimm Baeder void print(llvm::raw_ostream &OS) const { OS << V; } 199a07aba5dSTimm Baeder 200a07aba5dSTimm Baeder static Integral min(unsigned NumBits) { return Integral(Min); } 201a07aba5dSTimm Baeder static Integral max(unsigned NumBits) { return Integral(Max); } 202a07aba5dSTimm Baeder 203a07aba5dSTimm Baeder template <typename ValT> static Integral from(ValT Value) { 204a07aba5dSTimm Baeder if constexpr (std::is_integral<ValT>::value) 205a07aba5dSTimm Baeder return Integral(Value); 206a07aba5dSTimm Baeder else 207a07aba5dSTimm Baeder return Integral::from(static_cast<Integral::ReprT>(Value)); 208a07aba5dSTimm Baeder } 209a07aba5dSTimm Baeder 210a07aba5dSTimm Baeder template <unsigned SrcBits, bool SrcSign> 211a07aba5dSTimm Baeder static std::enable_if_t<SrcBits != 0, Integral> 212a07aba5dSTimm Baeder from(Integral<SrcBits, SrcSign> Value) { 213a07aba5dSTimm Baeder return Integral(Value.V); 214a07aba5dSTimm Baeder } 215a07aba5dSTimm Baeder 216*2503a665STimm Bäder static Integral zero(unsigned BitWidth = 0) { return from(0); } 217a07aba5dSTimm Baeder 218a07aba5dSTimm Baeder template <typename T> static Integral from(T Value, unsigned NumBits) { 219a07aba5dSTimm Baeder return Integral(Value); 220a07aba5dSTimm Baeder } 221a07aba5dSTimm Baeder 222a07aba5dSTimm Baeder static bool inRange(int64_t Value, unsigned NumBits) { 223a07aba5dSTimm Baeder return CheckRange<ReprT, Min, Max>(Value); 224a07aba5dSTimm Baeder } 225a07aba5dSTimm Baeder 226a07aba5dSTimm Baeder static bool increment(Integral A, Integral *R) { 227a07aba5dSTimm Baeder return add(A, Integral(ReprT(1)), A.bitWidth(), R); 228a07aba5dSTimm Baeder } 229a07aba5dSTimm Baeder 230a07aba5dSTimm Baeder static bool decrement(Integral A, Integral *R) { 231a07aba5dSTimm Baeder return sub(A, Integral(ReprT(1)), A.bitWidth(), R); 232a07aba5dSTimm Baeder } 233a07aba5dSTimm Baeder 234a07aba5dSTimm Baeder static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) { 235a07aba5dSTimm Baeder return CheckAddUB(A.V, B.V, R->V); 236a07aba5dSTimm Baeder } 237a07aba5dSTimm Baeder 238a07aba5dSTimm Baeder static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) { 239a07aba5dSTimm Baeder return CheckSubUB(A.V, B.V, R->V); 240a07aba5dSTimm Baeder } 241a07aba5dSTimm Baeder 242a07aba5dSTimm Baeder static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) { 243a07aba5dSTimm Baeder return CheckMulUB(A.V, B.V, R->V); 244a07aba5dSTimm Baeder } 245a07aba5dSTimm Baeder 246a07aba5dSTimm Baeder static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) { 247a07aba5dSTimm Baeder *R = Integral(A.V % B.V); 248a07aba5dSTimm Baeder return false; 249a07aba5dSTimm Baeder } 250a07aba5dSTimm Baeder 251a07aba5dSTimm Baeder static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) { 252a07aba5dSTimm Baeder *R = Integral(A.V / B.V); 253a07aba5dSTimm Baeder return false; 254a07aba5dSTimm Baeder } 255a07aba5dSTimm Baeder 256a07aba5dSTimm Baeder static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) { 257a07aba5dSTimm Baeder *R = Integral(A.V & B.V); 258a07aba5dSTimm Baeder return false; 259a07aba5dSTimm Baeder } 260a07aba5dSTimm Baeder 261a07aba5dSTimm Baeder static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) { 262a07aba5dSTimm Baeder *R = Integral(A.V | B.V); 263a07aba5dSTimm Baeder return false; 264a07aba5dSTimm Baeder } 265a07aba5dSTimm Baeder 266a07aba5dSTimm Baeder static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) { 267a07aba5dSTimm Baeder *R = Integral(A.V ^ B.V); 268a07aba5dSTimm Baeder return false; 269a07aba5dSTimm Baeder } 270a07aba5dSTimm Baeder 271a07aba5dSTimm Baeder static bool neg(Integral A, Integral *R) { 272a07aba5dSTimm Baeder if (Signed && A.isMin()) 273a07aba5dSTimm Baeder return true; 274a07aba5dSTimm Baeder 275a07aba5dSTimm Baeder *R = -A; 276a07aba5dSTimm Baeder return false; 277a07aba5dSTimm Baeder } 278a07aba5dSTimm Baeder 279a07aba5dSTimm Baeder static bool comp(Integral A, Integral *R) { 280a07aba5dSTimm Baeder *R = Integral(~A.V); 281a07aba5dSTimm Baeder return false; 282a07aba5dSTimm Baeder } 283a07aba5dSTimm Baeder 284a07aba5dSTimm Baeder template <unsigned RHSBits, bool RHSSign> 285a07aba5dSTimm Baeder static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B, 286a07aba5dSTimm Baeder unsigned OpBits, Integral *R) { 287a07aba5dSTimm Baeder *R = Integral::from(A.V << B.V, OpBits); 288a07aba5dSTimm Baeder } 289a07aba5dSTimm Baeder 290a07aba5dSTimm Baeder template <unsigned RHSBits, bool RHSSign> 291a07aba5dSTimm Baeder static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B, 292a07aba5dSTimm Baeder unsigned OpBits, Integral *R) { 293a07aba5dSTimm Baeder *R = Integral::from(A.V >> B.V, OpBits); 294a07aba5dSTimm Baeder } 295a07aba5dSTimm Baeder 296a07aba5dSTimm Baeder private: 297a07aba5dSTimm Baeder template <typename T> static bool CheckAddUB(T A, T B, T &R) { 298a07aba5dSTimm Baeder if constexpr (std::is_signed_v<T>) { 299a07aba5dSTimm Baeder return llvm::AddOverflow<T>(A, B, R); 300a07aba5dSTimm Baeder } else { 301a07aba5dSTimm Baeder R = A + B; 302a07aba5dSTimm Baeder return false; 303a07aba5dSTimm Baeder } 304a07aba5dSTimm Baeder } 305a07aba5dSTimm Baeder 306a07aba5dSTimm Baeder template <typename T> static bool CheckSubUB(T A, T B, T &R) { 307a07aba5dSTimm Baeder if constexpr (std::is_signed_v<T>) { 308a07aba5dSTimm Baeder return llvm::SubOverflow<T>(A, B, R); 309a07aba5dSTimm Baeder } else { 310a07aba5dSTimm Baeder R = A - B; 311a07aba5dSTimm Baeder return false; 312a07aba5dSTimm Baeder } 313a07aba5dSTimm Baeder } 314a07aba5dSTimm Baeder 315a07aba5dSTimm Baeder template <typename T> static bool CheckMulUB(T A, T B, T &R) { 316a07aba5dSTimm Baeder if constexpr (std::is_signed_v<T>) { 317a07aba5dSTimm Baeder return llvm::MulOverflow<T>(A, B, R); 318a07aba5dSTimm Baeder } else { 319a07aba5dSTimm Baeder R = A * B; 320a07aba5dSTimm Baeder return false; 321a07aba5dSTimm Baeder } 322a07aba5dSTimm Baeder } 323a07aba5dSTimm Baeder template <typename T, T Min, T Max> static bool CheckRange(int64_t V) { 324a07aba5dSTimm Baeder if constexpr (std::is_signed_v<T>) { 325a07aba5dSTimm Baeder return Min <= V && V <= Max; 326a07aba5dSTimm Baeder } else { 327a07aba5dSTimm Baeder return V >= 0 && static_cast<uint64_t>(V) <= Max; 328a07aba5dSTimm Baeder } 329a07aba5dSTimm Baeder } 330a07aba5dSTimm Baeder }; 331a07aba5dSTimm Baeder 332a07aba5dSTimm Baeder template <unsigned Bits, bool Signed> 333a07aba5dSTimm Baeder llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) { 334a07aba5dSTimm Baeder I.print(OS); 335a07aba5dSTimm Baeder return OS; 336a07aba5dSTimm Baeder } 337a07aba5dSTimm Baeder 338a07aba5dSTimm Baeder } // namespace interp 339a07aba5dSTimm Baeder } // namespace clang 340a07aba5dSTimm Baeder 341a07aba5dSTimm Baeder #endif 342