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 21namespace clang { 22namespace interp { 23 24class Pointer; 25class Boolean; 26class Floating; 27class FunctionPointer; 28template <bool Signed> class IntegralAP; 29template <unsigned Bits, bool Signed> class Integral; 30 31/// Enumeration of the primitive types of the VM. 32enum PrimType : unsigned { 33 PT_Sint8, 34 PT_Uint8, 35 PT_Sint16, 36 PT_Uint16, 37 PT_Sint32, 38 PT_Uint32, 39 PT_Sint64, 40 PT_Uint64, 41 PT_IntAP, 42 PT_IntAPS, 43 PT_Bool, 44 PT_Float, 45 PT_Ptr, 46 PT_FnPtr, 47}; 48 49enum class CastKind : uint8_t { 50 Reinterpret, 51}; 52inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 53 interp::CastKind CK) { 54 switch (CK) { 55 case interp::CastKind::Reinterpret: 56 OS << "reinterpret_cast"; 57 break; 58 } 59 return OS; 60} 61 62constexpr bool isIntegralType(PrimType T) { return T <= PT_Bool; } 63 64/// Mapping from primitive types to their representation. 65template <PrimType T> struct PrimConv; 66template <> struct PrimConv<PT_Sint8> { using T = Integral<8, true>; }; 67template <> struct PrimConv<PT_Uint8> { using T = Integral<8, false>; }; 68template <> struct PrimConv<PT_Sint16> { using T = Integral<16, true>; }; 69template <> struct PrimConv<PT_Uint16> { using T = Integral<16, false>; }; 70template <> struct PrimConv<PT_Sint32> { using T = Integral<32, true>; }; 71template <> struct PrimConv<PT_Uint32> { using T = Integral<32, false>; }; 72template <> struct PrimConv<PT_Sint64> { using T = Integral<64, true>; }; 73template <> struct PrimConv<PT_Uint64> { using T = Integral<64, false>; }; 74template <> struct PrimConv<PT_IntAP> { 75 using T = IntegralAP<false>; 76}; 77template <> struct PrimConv<PT_IntAPS> { 78 using T = IntegralAP<true>; 79}; 80template <> struct PrimConv<PT_Float> { using T = Floating; }; 81template <> struct PrimConv<PT_Bool> { using T = Boolean; }; 82template <> struct PrimConv<PT_Ptr> { using T = Pointer; }; 83template <> struct PrimConv<PT_FnPtr> { 84 using T = FunctionPointer; 85}; 86 87/// Returns the size of a primitive type in bytes. 88size_t primSize(PrimType Type); 89 90/// Aligns a size to the pointer alignment. 91constexpr size_t align(size_t Size) { 92 return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *); 93} 94 95constexpr bool aligned(uintptr_t Value) { return Value == align(Value); } 96static_assert(aligned(sizeof(void *))); 97 98static inline bool aligned(const void *P) { 99 return aligned(reinterpret_cast<uintptr_t>(P)); 100} 101 102} // namespace interp 103} // namespace clang 104 105/// Helper macro to simplify type switches. 106/// The macro implicitly exposes a type T in the scope of the inner block. 107#define TYPE_SWITCH_CASE(Name, B) \ 108 case Name: { using T = PrimConv<Name>::T; B; break; } 109#define TYPE_SWITCH(Expr, B) \ 110 do { \ 111 switch (Expr) { \ 112 TYPE_SWITCH_CASE(PT_Sint8, B) \ 113 TYPE_SWITCH_CASE(PT_Uint8, B) \ 114 TYPE_SWITCH_CASE(PT_Sint16, B) \ 115 TYPE_SWITCH_CASE(PT_Uint16, B) \ 116 TYPE_SWITCH_CASE(PT_Sint32, B) \ 117 TYPE_SWITCH_CASE(PT_Uint32, B) \ 118 TYPE_SWITCH_CASE(PT_Sint64, B) \ 119 TYPE_SWITCH_CASE(PT_Uint64, B) \ 120 TYPE_SWITCH_CASE(PT_IntAP, B) \ 121 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 122 TYPE_SWITCH_CASE(PT_Float, B) \ 123 TYPE_SWITCH_CASE(PT_Bool, B) \ 124 TYPE_SWITCH_CASE(PT_Ptr, B) \ 125 TYPE_SWITCH_CASE(PT_FnPtr, B) \ 126 } \ 127 } while (0) 128 129#define INT_TYPE_SWITCH(Expr, B) \ 130 do { \ 131 switch (Expr) { \ 132 TYPE_SWITCH_CASE(PT_Sint8, B) \ 133 TYPE_SWITCH_CASE(PT_Uint8, B) \ 134 TYPE_SWITCH_CASE(PT_Sint16, B) \ 135 TYPE_SWITCH_CASE(PT_Uint16, B) \ 136 TYPE_SWITCH_CASE(PT_Sint32, B) \ 137 TYPE_SWITCH_CASE(PT_Uint32, B) \ 138 TYPE_SWITCH_CASE(PT_Sint64, B) \ 139 TYPE_SWITCH_CASE(PT_Uint64, B) \ 140 TYPE_SWITCH_CASE(PT_IntAP, B) \ 141 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 142 TYPE_SWITCH_CASE(PT_Bool, B) \ 143 default: \ 144 llvm_unreachable("Not an integer value"); \ 145 } \ 146 } while (0) 147 148#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ 149 do { \ 150 switch (Expr) { \ 151 TYPE_SWITCH_CASE(PT_Ptr, B) \ 152 default: { D; break; } \ 153 } \ 154 } while (0) 155#endif 156