//===--- PrimType.h - Types for the constexpr 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 // //===----------------------------------------------------------------------===// // // Defines the VM types and helpers operating on types. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_INTERP_TYPE_H #define LLVM_CLANG_AST_INTERP_TYPE_H #include "llvm/Support/raw_ostream.h" #include #include #include namespace clang { namespace interp { class Pointer; class Boolean; class Floating; class FunctionPointer; class MemberPointer; class FixedPoint; template class IntegralAP; template class Integral; /// Enumeration of the primitive types of the VM. enum PrimType : unsigned { PT_Sint8 = 0, PT_Uint8 = 1, PT_Sint16 = 2, PT_Uint16 = 3, PT_Sint32 = 4, PT_Uint32 = 5, PT_Sint64 = 6, PT_Uint64 = 7, PT_IntAP = 8, PT_IntAPS = 9, PT_Bool = 10, PT_FixedPoint = 11, PT_Float = 12, PT_Ptr = 13, PT_FnPtr = 14, PT_MemberPtr = 15, }; inline constexpr bool isPtrType(PrimType T) { return T == PT_Ptr || T == PT_FnPtr || T == PT_MemberPtr; } enum class CastKind : uint8_t { Reinterpret, Atomic, }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, interp::CastKind CK) { switch (CK) { case interp::CastKind::Reinterpret: OS << "reinterpret_cast"; break; case interp::CastKind::Atomic: OS << "atomic"; break; } return OS; } constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; } /// Mapping from primitive types to their representation. template struct PrimConv; template <> struct PrimConv { using T = Integral<8, true>; }; template <> struct PrimConv { using T = Integral<8, false>; }; template <> struct PrimConv { using T = Integral<16, true>; }; template <> struct PrimConv { using T = Integral<16, false>; }; template <> struct PrimConv { using T = Integral<32, true>; }; template <> struct PrimConv { using T = Integral<32, false>; }; template <> struct PrimConv { using T = Integral<64, true>; }; template <> struct PrimConv { using T = Integral<64, false>; }; template <> struct PrimConv { using T = IntegralAP; }; template <> struct PrimConv { using T = IntegralAP; }; template <> struct PrimConv { using T = Floating; }; template <> struct PrimConv { using T = Boolean; }; template <> struct PrimConv { using T = Pointer; }; template <> struct PrimConv { using T = FunctionPointer; }; template <> struct PrimConv { using T = MemberPointer; }; template <> struct PrimConv { using T = FixedPoint; }; /// Returns the size of a primitive type in bytes. size_t primSize(PrimType Type); /// Aligns a size to the pointer alignment. constexpr size_t align(size_t Size) { return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *); } constexpr bool aligned(uintptr_t Value) { return Value == align(Value); } static_assert(aligned(sizeof(void *))); static inline bool aligned(const void *P) { return aligned(reinterpret_cast(P)); } } // namespace interp } // namespace clang /// Helper macro to simplify type switches. /// The macro implicitly exposes a type T in the scope of the inner block. #define TYPE_SWITCH_CASE(Name, B) \ case Name: { \ using T = PrimConv::T; \ B; \ break; \ } #define TYPE_SWITCH(Expr, B) \ do { \ switch (Expr) { \ TYPE_SWITCH_CASE(PT_Sint8, B) \ TYPE_SWITCH_CASE(PT_Uint8, B) \ TYPE_SWITCH_CASE(PT_Sint16, B) \ TYPE_SWITCH_CASE(PT_Uint16, B) \ TYPE_SWITCH_CASE(PT_Sint32, B) \ TYPE_SWITCH_CASE(PT_Uint32, B) \ TYPE_SWITCH_CASE(PT_Sint64, B) \ TYPE_SWITCH_CASE(PT_Uint64, B) \ TYPE_SWITCH_CASE(PT_IntAP, B) \ TYPE_SWITCH_CASE(PT_IntAPS, B) \ TYPE_SWITCH_CASE(PT_Float, B) \ TYPE_SWITCH_CASE(PT_Bool, B) \ TYPE_SWITCH_CASE(PT_Ptr, B) \ TYPE_SWITCH_CASE(PT_FnPtr, B) \ TYPE_SWITCH_CASE(PT_MemberPtr, B) \ TYPE_SWITCH_CASE(PT_FixedPoint, B) \ } \ } while (0) #define INT_TYPE_SWITCH(Expr, B) \ do { \ switch (Expr) { \ TYPE_SWITCH_CASE(PT_Sint8, B) \ TYPE_SWITCH_CASE(PT_Uint8, B) \ TYPE_SWITCH_CASE(PT_Sint16, B) \ TYPE_SWITCH_CASE(PT_Uint16, B) \ TYPE_SWITCH_CASE(PT_Sint32, B) \ TYPE_SWITCH_CASE(PT_Uint32, B) \ TYPE_SWITCH_CASE(PT_Sint64, B) \ TYPE_SWITCH_CASE(PT_Uint64, B) \ TYPE_SWITCH_CASE(PT_IntAP, B) \ TYPE_SWITCH_CASE(PT_IntAPS, B) \ TYPE_SWITCH_CASE(PT_Bool, B) \ default: \ llvm_unreachable("Not an integer value"); \ } \ } while (0) #define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \ do { \ switch (Expr) { \ TYPE_SWITCH_CASE(PT_Sint8, B) \ TYPE_SWITCH_CASE(PT_Uint8, B) \ TYPE_SWITCH_CASE(PT_Sint16, B) \ TYPE_SWITCH_CASE(PT_Uint16, B) \ TYPE_SWITCH_CASE(PT_Sint32, B) \ TYPE_SWITCH_CASE(PT_Uint32, B) \ TYPE_SWITCH_CASE(PT_Sint64, B) \ TYPE_SWITCH_CASE(PT_Uint64, B) \ TYPE_SWITCH_CASE(PT_IntAP, B) \ TYPE_SWITCH_CASE(PT_IntAPS, B) \ default: \ llvm_unreachable("Not an integer value"); \ } \ } while (0) #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ do { \ switch (Expr) { \ TYPE_SWITCH_CASE(PT_Ptr, B) \ default: { \ D; \ break; \ } \ } \ } while (0) #endif