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 class FixedPoint; 30 template <bool Signed> class IntegralAP; 31 template <unsigned Bits, bool Signed> class Integral; 32 33 /// Enumeration of the primitive types of the VM. 34 enum PrimType : unsigned { 35 PT_Sint8 = 0, 36 PT_Uint8 = 1, 37 PT_Sint16 = 2, 38 PT_Uint16 = 3, 39 PT_Sint32 = 4, 40 PT_Uint32 = 5, 41 PT_Sint64 = 6, 42 PT_Uint64 = 7, 43 PT_IntAP = 8, 44 PT_IntAPS = 9, 45 PT_Bool = 10, 46 PT_FixedPoint = 11, 47 PT_Float = 12, 48 PT_Ptr = 13, 49 PT_FnPtr = 14, 50 PT_MemberPtr = 15, 51 }; 52 53 inline constexpr bool isPtrType(PrimType T) { 54 return T == PT_Ptr || T == PT_FnPtr || T == PT_MemberPtr; 55 } 56 57 enum class CastKind : uint8_t { 58 Reinterpret, 59 Atomic, 60 }; 61 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 62 interp::CastKind CK) { 63 switch (CK) { 64 case interp::CastKind::Reinterpret: 65 OS << "reinterpret_cast"; 66 break; 67 case interp::CastKind::Atomic: 68 OS << "atomic"; 69 break; 70 } 71 return OS; 72 } 73 74 constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; } 75 76 /// Mapping from primitive types to their representation. 77 template <PrimType T> struct PrimConv; 78 template <> struct PrimConv<PT_Sint8> { 79 using T = Integral<8, true>; 80 }; 81 template <> struct PrimConv<PT_Uint8> { 82 using T = Integral<8, false>; 83 }; 84 template <> struct PrimConv<PT_Sint16> { 85 using T = Integral<16, true>; 86 }; 87 template <> struct PrimConv<PT_Uint16> { 88 using T = Integral<16, false>; 89 }; 90 template <> struct PrimConv<PT_Sint32> { 91 using T = Integral<32, true>; 92 }; 93 template <> struct PrimConv<PT_Uint32> { 94 using T = Integral<32, false>; 95 }; 96 template <> struct PrimConv<PT_Sint64> { 97 using T = Integral<64, true>; 98 }; 99 template <> struct PrimConv<PT_Uint64> { 100 using T = Integral<64, false>; 101 }; 102 template <> struct PrimConv<PT_IntAP> { 103 using T = IntegralAP<false>; 104 }; 105 template <> struct PrimConv<PT_IntAPS> { 106 using T = IntegralAP<true>; 107 }; 108 template <> struct PrimConv<PT_Float> { 109 using T = Floating; 110 }; 111 template <> struct PrimConv<PT_Bool> { 112 using T = Boolean; 113 }; 114 template <> struct PrimConv<PT_Ptr> { 115 using T = Pointer; 116 }; 117 template <> struct PrimConv<PT_FnPtr> { 118 using T = FunctionPointer; 119 }; 120 template <> struct PrimConv<PT_MemberPtr> { 121 using T = MemberPointer; 122 }; 123 template <> struct PrimConv<PT_FixedPoint> { 124 using T = FixedPoint; 125 }; 126 127 /// Returns the size of a primitive type in bytes. 128 size_t primSize(PrimType Type); 129 130 /// Aligns a size to the pointer alignment. 131 constexpr size_t align(size_t Size) { 132 return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *); 133 } 134 135 constexpr bool aligned(uintptr_t Value) { return Value == align(Value); } 136 static_assert(aligned(sizeof(void *))); 137 138 static inline bool aligned(const void *P) { 139 return aligned(reinterpret_cast<uintptr_t>(P)); 140 } 141 142 } // namespace interp 143 } // namespace clang 144 145 /// Helper macro to simplify type switches. 146 /// The macro implicitly exposes a type T in the scope of the inner block. 147 #define TYPE_SWITCH_CASE(Name, B) \ 148 case Name: { \ 149 using T = PrimConv<Name>::T; \ 150 B; \ 151 break; \ 152 } 153 #define TYPE_SWITCH(Expr, B) \ 154 do { \ 155 switch (Expr) { \ 156 TYPE_SWITCH_CASE(PT_Sint8, B) \ 157 TYPE_SWITCH_CASE(PT_Uint8, B) \ 158 TYPE_SWITCH_CASE(PT_Sint16, B) \ 159 TYPE_SWITCH_CASE(PT_Uint16, B) \ 160 TYPE_SWITCH_CASE(PT_Sint32, B) \ 161 TYPE_SWITCH_CASE(PT_Uint32, B) \ 162 TYPE_SWITCH_CASE(PT_Sint64, B) \ 163 TYPE_SWITCH_CASE(PT_Uint64, B) \ 164 TYPE_SWITCH_CASE(PT_IntAP, B) \ 165 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 166 TYPE_SWITCH_CASE(PT_Float, B) \ 167 TYPE_SWITCH_CASE(PT_Bool, B) \ 168 TYPE_SWITCH_CASE(PT_Ptr, B) \ 169 TYPE_SWITCH_CASE(PT_FnPtr, B) \ 170 TYPE_SWITCH_CASE(PT_MemberPtr, B) \ 171 TYPE_SWITCH_CASE(PT_FixedPoint, B) \ 172 } \ 173 } while (0) 174 175 #define INT_TYPE_SWITCH(Expr, B) \ 176 do { \ 177 switch (Expr) { \ 178 TYPE_SWITCH_CASE(PT_Sint8, B) \ 179 TYPE_SWITCH_CASE(PT_Uint8, B) \ 180 TYPE_SWITCH_CASE(PT_Sint16, B) \ 181 TYPE_SWITCH_CASE(PT_Uint16, B) \ 182 TYPE_SWITCH_CASE(PT_Sint32, B) \ 183 TYPE_SWITCH_CASE(PT_Uint32, B) \ 184 TYPE_SWITCH_CASE(PT_Sint64, B) \ 185 TYPE_SWITCH_CASE(PT_Uint64, B) \ 186 TYPE_SWITCH_CASE(PT_IntAP, B) \ 187 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 188 TYPE_SWITCH_CASE(PT_Bool, B) \ 189 default: \ 190 llvm_unreachable("Not an integer value"); \ 191 } \ 192 } while (0) 193 194 #define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \ 195 do { \ 196 switch (Expr) { \ 197 TYPE_SWITCH_CASE(PT_Sint8, B) \ 198 TYPE_SWITCH_CASE(PT_Uint8, B) \ 199 TYPE_SWITCH_CASE(PT_Sint16, B) \ 200 TYPE_SWITCH_CASE(PT_Uint16, B) \ 201 TYPE_SWITCH_CASE(PT_Sint32, B) \ 202 TYPE_SWITCH_CASE(PT_Uint32, B) \ 203 TYPE_SWITCH_CASE(PT_Sint64, B) \ 204 TYPE_SWITCH_CASE(PT_Uint64, B) \ 205 TYPE_SWITCH_CASE(PT_IntAP, B) \ 206 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 207 default: \ 208 llvm_unreachable("Not an integer value"); \ 209 } \ 210 } while (0) 211 212 #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ 213 do { \ 214 switch (Expr) { \ 215 TYPE_SWITCH_CASE(PT_Ptr, B) \ 216 default: { \ 217 D; \ 218 break; \ 219 } \ 220 } \ 221 } while (0) 222 #endif 223