//===------- Char.h - Wrapper for numeric types for the VM ------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_INTERP_CHAR_H #define LLVM_CLANG_AST_INTERP_CHAR_H #include "Integral.h" #include namespace clang { namespace interp { template class Integral; template struct CharRepr; template <> struct CharRepr { using Type = uint8_t; }; template <> struct CharRepr { using Type = int8_t; }; template class Char final { private: template friend class Char; using ReprT = typename CharRepr::Type; ReprT V = 0; static_assert(std::is_trivially_copyable_v); public: using AsUnsigned = Char; constexpr Char() = default; constexpr Char(ReprT V) : V(V) {} // constexpr Char(const Char &C) : V(C.V) {} explicit Char(const APSInt &V) : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {} template static Char from(T t) { return Char(static_cast(t)); } template static Char from(T t, unsigned BitWidth) { return Char(static_cast(t)); } static bool isSigned() { return Signed; } static unsigned bitWidth() { return 8; } static bool isNumber() { return true; } static Char zero(unsigned BitWidth = 8) { return Char(0); } constexpr bool isMin() const { return V == std::numeric_limits::min(); } constexpr bool isNegative() const { return Signed && V < 0; } constexpr bool isPositive() const { return !isNegative(); } constexpr bool isZero() const { return V == 0; } constexpr bool isMinusOne() const { return Signed && V == -1; } template >> explicit operator Ty() const { return V; } bool operator<(Char RHS) const { return V < RHS.V; } bool operator>(Char RHS) const { return V > RHS.V; } bool operator<=(Char RHS) const { return V <= RHS.V; } bool operator>=(Char RHS) const { return V >= RHS.V; } bool operator==(Char RHS) const { return V == RHS.V; } bool operator!=(Char RHS) const { return V != RHS.V; } bool operator>=(unsigned RHS) const { return static_cast(V) >= RHS; } bool operator>(unsigned RHS) const { return V >= 0 && static_cast(V) > RHS; } Char operator-() const { return Char(-V); } Char operator-(Char Other) const { return Char(V - Other.V); } ComparisonCategoryResult compare(Char RHS) const { return Compare(V, RHS.V); } void bitcastToMemory(std::byte *Dest) const { std::memcpy(Dest, &V, sizeof(V)); } static Char bitcastFromMemory(const std::byte *Src, unsigned BitWidth) { assert(BitWidth == 8); ReprT V; std::memcpy(&V, Src, sizeof(ReprT)); return Char(V); } APSInt toAPSInt() const { return APSInt(APInt(8, static_cast(V), Signed), !Signed); } APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth), !Signed); } APInt toAPInt(unsigned BitWidth) const { if constexpr (Signed) return APInt(8, static_cast(V), Signed).sextOrTrunc(BitWidth); else return APInt(8, static_cast(V), Signed).zextOrTrunc(BitWidth); } APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } std::string toDiagnosticString(const ASTContext &Ctx) const { std::string NameStr; llvm::raw_string_ostream OS(NameStr); OS << V; return NameStr; } Char toUnsigned() const { return Char(V); } Char truncate(unsigned TruncBits) const { assert(TruncBits >= 1); if (TruncBits >= 8) return *this; const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1; const ReprT SignBit = ReprT(1) << (TruncBits - 1); const ReprT ExtMask = ~BitMask; return Char((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0)); } unsigned countLeadingZeros() const { if constexpr (!Signed) return llvm::countl_zero(V); if (isPositive()) return llvm::countl_zero( static_cast(V)); llvm_unreachable("Don't call countLeadingZeros() on negative values."); } static bool increment(Char A, Char *R) { return add(A, Char(ReprT(1)), A.bitWidth(), R); } static bool decrement(Char A, Char *R) { return sub(A, Char(ReprT(1)), A.bitWidth(), R); } static bool add(Char A, Char B, unsigned OpBits, Char *R) { return CheckAddUB(A.V, B.V, R->V); } static bool sub(Char A, Char B, unsigned OpBits, Char *R) { return CheckSubUB(A.V, B.V, R->V); } static bool mul(Char A, Char B, unsigned OpBits, Char *R) { return CheckMulUB(A.V, B.V, R->V); } static bool rem(Char A, Char B, unsigned OpBits, Char *R) { *R = Char(A.V % B.V); return false; } static bool div(Char A, Char B, unsigned OpBits, Char *R) { *R = Char(A.V / B.V); return false; } static bool bitAnd(Char A, Char B, unsigned OpBits, Char *R) { *R = Char(A.V & B.V); return false; } static bool bitOr(Char A, Char B, unsigned OpBits, Char *R) { *R = Char(A.V | B.V); return false; } static bool bitXor(Char A, Char B, unsigned OpBits, Char *R) { *R = Char(A.V ^ B.V); return false; } static bool neg(Char A, Char *R) { if (Signed && A.isMin()) return true; *R = Char(-A.V); return false; } static bool comp(Char A, Char *R) { *R = Char(~A.V); return false; } template static void shiftLeft(const Char A, const Char B, unsigned OpBits, Char *R) { *R = Char(A.V << B.V); } template static void shiftRight(const Char A, const Char B, unsigned OpBits, Char *R) { *R = Char(A.V >> B.V); } void print(llvm::raw_ostream &OS) const { OS << V; } }; static_assert(sizeof(Char) == 1); static_assert(sizeof(Char) == 1); template llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Char I) { I.print(OS); return OS; } } // namespace interp } // namespace clang #endif