1 //===--- PrimType.h - Types for the constexpr VM ----------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Defines the VM types and helpers operating on types. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_AST_INTERP_TYPE_H 14 #define LLVM_CLANG_AST_INTERP_TYPE_H 15 16 #include "llvm/Support/raw_ostream.h" 17 #include <climits> 18 #include <cstddef> 19 #include <cstdint> 20 21 namespace clang { 22 namespace interp { 23 24 class Pointer; 25 class Boolean; 26 class Floating; 27 class FunctionPointer; 28 class MemberPointer; 29 template <bool Signed> class IntegralAP; 30 template <unsigned Bits, bool Signed> class Integral; 31 32 /// Enumeration of the primitive types of the VM. 33 enum PrimType : unsigned { 34 PT_Sint8 = 0, 35 PT_Uint8 = 1, 36 PT_Sint16 = 2, 37 PT_Uint16 = 3, 38 PT_Sint32 = 4, 39 PT_Uint32 = 5, 40 PT_Sint64 = 6, 41 PT_Uint64 = 7, 42 PT_IntAP = 8, 43 PT_IntAPS = 9, 44 PT_Bool = 10, 45 PT_Float = 11, 46 PT_Ptr = 12, 47 PT_FnPtr = 13, 48 PT_MemberPtr = 14, 49 }; 50 51 inline constexpr bool isPtrType(PrimType T) { 52 return T == PT_Ptr || T == PT_FnPtr || T == PT_MemberPtr; 53 } 54 55 enum class CastKind : uint8_t { 56 Reinterpret, 57 Atomic, 58 }; 59 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 60 interp::CastKind CK) { 61 switch (CK) { 62 case interp::CastKind::Reinterpret: 63 OS << "reinterpret_cast"; 64 break; 65 case interp::CastKind::Atomic: 66 OS << "atomic"; 67 break; 68 } 69 return OS; 70 } 71 72 constexpr bool isIntegralType(PrimType T) { return T <= PT_Bool; } 73 74 /// Mapping from primitive types to their representation. 75 template <PrimType T> struct PrimConv; 76 template <> struct PrimConv<PT_Sint8> { using T = Integral<8, true>; }; 77 template <> struct PrimConv<PT_Uint8> { using T = Integral<8, false>; }; 78 template <> struct PrimConv<PT_Sint16> { using T = Integral<16, true>; }; 79 template <> struct PrimConv<PT_Uint16> { using T = Integral<16, false>; }; 80 template <> struct PrimConv<PT_Sint32> { using T = Integral<32, true>; }; 81 template <> struct PrimConv<PT_Uint32> { using T = Integral<32, false>; }; 82 template <> struct PrimConv<PT_Sint64> { using T = Integral<64, true>; }; 83 template <> struct PrimConv<PT_Uint64> { using T = Integral<64, false>; }; 84 template <> struct PrimConv<PT_IntAP> { 85 using T = IntegralAP<false>; 86 }; 87 template <> struct PrimConv<PT_IntAPS> { 88 using T = IntegralAP<true>; 89 }; 90 template <> struct PrimConv<PT_Float> { using T = Floating; }; 91 template <> struct PrimConv<PT_Bool> { using T = Boolean; }; 92 template <> struct PrimConv<PT_Ptr> { using T = Pointer; }; 93 template <> struct PrimConv<PT_FnPtr> { 94 using T = FunctionPointer; 95 }; 96 template <> struct PrimConv<PT_MemberPtr> { 97 using T = MemberPointer; 98 }; 99 100 /// Returns the size of a primitive type in bytes. 101 size_t primSize(PrimType Type); 102 103 /// Aligns a size to the pointer alignment. 104 constexpr size_t align(size_t Size) { 105 return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *); 106 } 107 108 constexpr bool aligned(uintptr_t Value) { return Value == align(Value); } 109 static_assert(aligned(sizeof(void *))); 110 111 static inline bool aligned(const void *P) { 112 return aligned(reinterpret_cast<uintptr_t>(P)); 113 } 114 115 } // namespace interp 116 } // namespace clang 117 118 /// Helper macro to simplify type switches. 119 /// The macro implicitly exposes a type T in the scope of the inner block. 120 #define TYPE_SWITCH_CASE(Name, B) \ 121 case Name: { using T = PrimConv<Name>::T; B; break; } 122 #define TYPE_SWITCH(Expr, B) \ 123 do { \ 124 switch (Expr) { \ 125 TYPE_SWITCH_CASE(PT_Sint8, B) \ 126 TYPE_SWITCH_CASE(PT_Uint8, B) \ 127 TYPE_SWITCH_CASE(PT_Sint16, B) \ 128 TYPE_SWITCH_CASE(PT_Uint16, B) \ 129 TYPE_SWITCH_CASE(PT_Sint32, B) \ 130 TYPE_SWITCH_CASE(PT_Uint32, B) \ 131 TYPE_SWITCH_CASE(PT_Sint64, B) \ 132 TYPE_SWITCH_CASE(PT_Uint64, B) \ 133 TYPE_SWITCH_CASE(PT_IntAP, B) \ 134 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 135 TYPE_SWITCH_CASE(PT_Float, B) \ 136 TYPE_SWITCH_CASE(PT_Bool, B) \ 137 TYPE_SWITCH_CASE(PT_Ptr, B) \ 138 TYPE_SWITCH_CASE(PT_FnPtr, B) \ 139 TYPE_SWITCH_CASE(PT_MemberPtr, B) \ 140 } \ 141 } while (0) 142 143 #define INT_TYPE_SWITCH(Expr, B) \ 144 do { \ 145 switch (Expr) { \ 146 TYPE_SWITCH_CASE(PT_Sint8, B) \ 147 TYPE_SWITCH_CASE(PT_Uint8, B) \ 148 TYPE_SWITCH_CASE(PT_Sint16, B) \ 149 TYPE_SWITCH_CASE(PT_Uint16, B) \ 150 TYPE_SWITCH_CASE(PT_Sint32, B) \ 151 TYPE_SWITCH_CASE(PT_Uint32, B) \ 152 TYPE_SWITCH_CASE(PT_Sint64, B) \ 153 TYPE_SWITCH_CASE(PT_Uint64, B) \ 154 TYPE_SWITCH_CASE(PT_IntAP, B) \ 155 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 156 TYPE_SWITCH_CASE(PT_Bool, B) \ 157 default: \ 158 llvm_unreachable("Not an integer value"); \ 159 } \ 160 } while (0) 161 162 #define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \ 163 do { \ 164 switch (Expr) { \ 165 TYPE_SWITCH_CASE(PT_Sint8, B) \ 166 TYPE_SWITCH_CASE(PT_Uint8, B) \ 167 TYPE_SWITCH_CASE(PT_Sint16, B) \ 168 TYPE_SWITCH_CASE(PT_Uint16, B) \ 169 TYPE_SWITCH_CASE(PT_Sint32, B) \ 170 TYPE_SWITCH_CASE(PT_Uint32, B) \ 171 TYPE_SWITCH_CASE(PT_Sint64, B) \ 172 TYPE_SWITCH_CASE(PT_Uint64, B) \ 173 TYPE_SWITCH_CASE(PT_IntAP, B) \ 174 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 175 default: \ 176 llvm_unreachable("Not an integer value"); \ 177 } \ 178 } while (0) 179 180 #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ 181 do { \ 182 switch (Expr) { \ 183 TYPE_SWITCH_CASE(PT_Ptr, B) \ 184 default: { D; break; } \ 185 } \ 186 } while (0) 187 #endif 188