llir-opt  0.0.1
Low-Level Post-Link Optimiser for OCaml and C
cast.h
1 // This file if part of the llir-opt project.
2 // Licensing information can be found in the LICENSE file.
3 // (C) 2018 Nandor Licker. All rights reserved.
4 
5 #pragma once
6 
7 #include <type_traits>
8 
9 #include "core/value.h"
10 #include "core/global.h"
11 #include "core/expr.h"
12 #include "core/constant.h"
13 #include "core/inst.h"
14 
15 class Inst;
16 
17 
18 namespace detail {
19 
23 template <typename T, typename U>
24 struct copy_const {
25  using type = typename std::conditional
26  < std::is_const<T>::value
27  , typename std::add_const<U>::type
28  , U
29  >::type;
30 };
31 
35 template <typename T>
36 struct is_mutable_value : std::false_type {};
37 
38 template<> struct is_mutable_value<Global> : std::true_type {};
39 template<> struct is_mutable_value<Constant> : std::true_type {};
40 template<> struct is_mutable_value<Expr> : std::true_type {};
41 template<> struct is_mutable_value<Inst> : std::true_type {};
42 
43 template <typename T>
44 struct is_value {
45  using TT = typename std::remove_const<T>::type;
46 
47  static constexpr bool value = is_mutable_value<TT>::value;
48 };
49 
53 template <typename T, typename U>
54 struct is_class {
55  using TT = typename std::remove_const<T>::type;
56 
57  static constexpr bool value =
58  std::is_base_of<Value, TT>::value &&
59  std::is_base_of<U, TT>::value &&
60  !std::is_same<U, TT>::value;
61 };
62 
63 }
64 
68 template <typename T>
69 typename std::enable_if<detail::is_value<T>::value, T *>::type
70 cast_or_null(typename detail::copy_const<T, Value>::type *v)
71 {
72  if (v == nullptr) {
73  return nullptr;
74  }
75  if (v->Is(T::kValueKind)) {
76  return static_cast<T *>(v);
77  }
78  return nullptr;
79 }
80 
84 template<>
85 inline Inst *cast_or_null<Inst>(Value *v)
86 {
87  if (v == nullptr) {
88  return nullptr;
89  }
90  if ((reinterpret_cast<uintptr_t>(v) & 1) || v->Is(Inst::kValueKind)) {
91  return static_cast<Inst *>(v);
92  }
93  return nullptr;
94 }
95 
99 template<>
100 inline const Inst *cast_or_null<const Inst>(const Value *v)
101 {
102  if (v == nullptr) {
103  return nullptr;
104  }
105  if ((reinterpret_cast<uintptr_t>(v) & 1) || v->Is(Inst::kValueKind)) {
106  return static_cast<const Inst *>(v);
107  }
108  return nullptr;
109 }
110 
114 template <typename T>
115 typename std::enable_if<detail::is_class<T, Inst>::value, T *>::type
116 cast_or_null(typename detail::copy_const<T, Value>::type *value)
117 {
118  if (value == nullptr) {
119  return nullptr;
120  }
121  if (!value->Is(Value::Kind::INST)) {
122  return nullptr;
123  }
124  auto *inst = static_cast<typename detail::copy_const<T, Inst>::type *>(value);
125  if (!inst->Is(T::kInstKind)) {
126  return nullptr;
127  }
128  return static_cast<T *>(value);
129 }
130 
134 template <typename T>
135 typename std::enable_if<detail::is_class<T, Global>::value, T *>::type
136 cast_or_null(typename detail::copy_const<T, Value>::type *value)
137 {
138  if (value == nullptr) {
139  return nullptr;
140  }
141  if (!value->Is(Value::Kind::GLOBAL)) {
142  return nullptr;
143  }
144  if (!static_cast<const Global *>(value)->Is(T::kGlobalKind)) {
145  return nullptr;
146  }
147  return static_cast<T *>(value);
148 }
149 
153 template <typename T>
154 typename std::enable_if<detail::is_class<T, Constant>::value, T *>::type
155 cast_or_null(typename detail::copy_const<T, Value>::type *value)
156 {
157  if (value == nullptr) {
158  return nullptr;
159  }
160  if (!value->Is(Value::Kind::CONST)) {
161  return nullptr;
162  }
163  if (!static_cast<const Constant *>(value)->Is(T::kConstKind)) {
164  return nullptr;
165  }
166  return static_cast<T *>(value);
167 }
168 
172 template <typename T>
173 typename std::enable_if<detail::is_class<T, Expr>::value, T *>::type
174 cast_or_null(typename detail::copy_const<T, Value>::type *value)
175 {
176  if (value == nullptr) {
177  return nullptr;
178  }
179  if (!value->Is(Value::Kind::EXPR)) {
180  return nullptr;
181  }
182  if (!static_cast<const Expr *>(value)->Is(T::kExprKind)) {
183  return nullptr;
184  }
185  return static_cast<T *>(value);
186 }
187 
188 
192 template <typename T, typename U>
193 T *cast(U *from)
194 {
195  if (T *t = ::cast_or_null<T>(from)) {
196  return t;
197  }
198  llvm_unreachable("invalid dynamic type");
199 }
200 
204 template <typename T, typename U>
205 Ref<T> cast_or_null(Ref<U> from)
206 {
207  return Ref(::cast_or_null<T>(from.Get()), from.Index());
208 }
209 
213 template <typename T, typename U>
214 ConstRef<T> cast_or_null(ConstRef<U> from)
215 {
216  return ConstRef(::cast_or_null<const T>(from.Get()), from.Index());
217 }
218 
222 template <typename T, typename U>
223 Ref<T> cast(Ref<U> from)
224 {
225  return Ref(::cast<T>(from.Get()), from.Index());
226 }
227 
231 template <typename T, typename U>
232 ConstRef<T> cast(ConstRef<U> from)
233 {
234  return ConstRef(::cast<const T>(from.Get()), from.Index());
235 }
236 
240 template <typename T, typename U>
241 bool isa(U *from)
242 {
243  return ::cast_or_null<const T>(from);
244 }
Inst::kValueKind
static constexpr Value::Kind kValueKind
Kind of the instruction.
Definition: inst.h:59
Inst
Definition: inst.h:53
detail::is_mutable_value
Definition: cast.h:36
detail::is_class
Definition: cast.h:54
ConstRef
Definition: ref.h:83
Value
Definition: value.h:22
Constant
Definition: constant.h:21
Expr
Definition: expr.h:19
detail::copy_const
Definition: cast.h:24
Ref
Definition: ref.h:63
Value::Is
bool Is(Kind kind) const
Checks if the value is of a specific kind.
Definition: value.h:153
detail::is_value
Definition: cast.h:44
Global
Definition: global.h:23