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