1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_CODEGEN_TNODE_H_
6 #define V8_CODEGEN_TNODE_H_
7
8 #include "src/codegen/machine-type.h"
9
10 namespace v8 {
11 namespace internal {
12
13 class HeapNumber;
14 class BigInt;
15 class Object;
16 class Smi;
17 class TaggedIndex;
18
19 namespace compiler {
20
21 class Node;
22
23 } // namespace compiler
24
25 struct UntaggedT {};
26
27 struct IntegralT : UntaggedT {};
28
29 struct WordT : IntegralT {
30 static const MachineRepresentation kMachineRepresentation =
31 MachineType::PointerRepresentation();
32 };
33
34 struct RawPtrT : WordT {
35 static constexpr MachineType kMachineType = MachineType::Pointer();
36 };
37
38 template <class To>
39 struct RawPtr : RawPtrT {};
40
41 struct Word32T : IntegralT {
42 static const MachineRepresentation kMachineRepresentation =
43 MachineRepresentation::kWord32;
44 };
45 struct Int32T : Word32T {
46 static constexpr MachineType kMachineType = MachineType::Int32();
47 };
48 struct Uint32T : Word32T {
49 static constexpr MachineType kMachineType = MachineType::Uint32();
50 };
51 struct Int16T : Int32T {
52 static constexpr MachineType kMachineType = MachineType::Int16();
53 };
54 struct Uint16T : Uint32T, Int32T {
55 static constexpr MachineType kMachineType = MachineType::Uint16();
56 };
57 struct Int8T : Int16T {
58 static constexpr MachineType kMachineType = MachineType::Int8();
59 };
60 struct Uint8T : Uint16T, Int16T {
61 static constexpr MachineType kMachineType = MachineType::Uint8();
62 };
63
64 struct Word64T : IntegralT {
65 static const MachineRepresentation kMachineRepresentation =
66 MachineRepresentation::kWord64;
67 };
68 struct Int64T : Word64T {
69 static constexpr MachineType kMachineType = MachineType::Int64();
70 };
71 struct Uint64T : Word64T {
72 static constexpr MachineType kMachineType = MachineType::Uint64();
73 };
74
75 struct IntPtrT : WordT {
76 static constexpr MachineType kMachineType = MachineType::IntPtr();
77 };
78 struct UintPtrT : WordT {
79 static constexpr MachineType kMachineType = MachineType::UintPtr();
80 };
81
82 struct ExternalPointerT : UntaggedT {
83 static const MachineRepresentation kMachineRepresentation =
84 MachineType::PointerRepresentation();
85 static constexpr MachineType kMachineType = MachineType::Pointer();
86 };
87
88 struct Float32T : UntaggedT {
89 static const MachineRepresentation kMachineRepresentation =
90 MachineRepresentation::kFloat32;
91 static constexpr MachineType kMachineType = MachineType::Float32();
92 };
93
94 struct Float64T : UntaggedT {
95 static const MachineRepresentation kMachineRepresentation =
96 MachineRepresentation::kFloat64;
97 static constexpr MachineType kMachineType = MachineType::Float64();
98 };
99
100 #ifdef V8_COMPRESS_POINTERS
101 using TaggedT = Int32T;
102 #else
103 using TaggedT = IntPtrT;
104 #endif
105
106 // Result of a comparison operation.
107 struct BoolT : Word32T {};
108
109 // Value type of a Turbofan node with two results.
110 template <class T1, class T2>
111 struct PairT {};
112
CommonMachineType(MachineType type1,MachineType type2)113 inline constexpr MachineType CommonMachineType(MachineType type1,
114 MachineType type2) {
115 return (type1 == type2) ? type1
116 : ((type1.IsTagged() && type2.IsTagged())
117 ? MachineType::AnyTagged()
118 : MachineType::None());
119 }
120
121 template <class Type, class Enable = void>
122 struct MachineTypeOf {
123 static constexpr MachineType value = Type::kMachineType;
124 };
125
126 template <class Type, class Enable>
127 constexpr MachineType MachineTypeOf<Type, Enable>::value;
128
129 template <>
130 struct MachineTypeOf<Object> {
131 static constexpr MachineType value = MachineType::AnyTagged();
132 };
133 template <>
134 struct MachineTypeOf<MaybeObject> {
135 static constexpr MachineType value = MachineType::AnyTagged();
136 };
137 template <>
138 struct MachineTypeOf<Smi> {
139 static constexpr MachineType value = MachineType::TaggedSigned();
140 };
141 template <>
142 struct MachineTypeOf<TaggedIndex> {
143 static constexpr MachineType value = MachineType::Pointer();
144 };
145 template <class HeapObjectSubtype>
146 struct MachineTypeOf<HeapObjectSubtype,
147 typename std::enable_if<std::is_base_of<
148 HeapObject, HeapObjectSubtype>::value>::type> {
149 static constexpr MachineType value = MachineType::TaggedPointer();
150 };
151 template <>
152 struct MachineTypeOf<ExternalReference> {
153 static constexpr MachineType value = MachineType::Pointer();
154 };
155
156 template <class HeapObjectSubtype>
157 constexpr MachineType MachineTypeOf<
158 HeapObjectSubtype, typename std::enable_if<std::is_base_of<
159 HeapObject, HeapObjectSubtype>::value>::type>::value;
160
161 template <class Type, class Enable = void>
162 struct MachineRepresentationOf {
163 static const MachineRepresentation value = Type::kMachineRepresentation;
164 };
165 // If T defines kMachineType, then we take the machine representation from
166 // there.
167 template <class T>
168 struct MachineRepresentationOf<T, base::void_t<decltype(T::kMachineType)>> {
169 static const MachineRepresentation value = T::kMachineType.representation();
170 };
171 template <class T>
172 struct MachineRepresentationOf<
173 T, typename std::enable_if<std::is_base_of<Object, T>::value>::type> {
174 static const MachineRepresentation value =
175 MachineTypeOf<T>::value.representation();
176 };
177 template <class T>
178 struct MachineRepresentationOf<
179 T, typename std::enable_if<std::is_base_of<MaybeObject, T>::value>::type> {
180 static const MachineRepresentation value =
181 MachineTypeOf<T>::value.representation();
182 };
183 template <>
184 struct MachineRepresentationOf<ExternalReference> {
185 static const MachineRepresentation value = RawPtrT::kMachineRepresentation;
186 };
187
188 template <typename T>
189 constexpr bool IsMachineRepresentationOf(MachineRepresentation r) {
190 return MachineRepresentationOf<T>::value == r;
191 }
192
193 template <class T>
194 constexpr MachineRepresentation PhiMachineRepresentationOf =
195 std::is_base_of<Word32T, T>::value ? MachineRepresentation::kWord32
196 : MachineRepresentationOf<T>::value;
197
198 template <class T>
199 struct is_valid_type_tag {
200 static const bool value = std::is_base_of<Object, T>::value ||
201 std::is_base_of<UntaggedT, T>::value ||
202 std::is_base_of<MaybeObject, T>::value ||
203 std::is_same<ExternalReference, T>::value;
204 static const bool is_tagged = std::is_base_of<Object, T>::value ||
205 std::is_base_of<MaybeObject, T>::value;
206 };
207
208 template <class T1, class T2>
209 struct is_valid_type_tag<PairT<T1, T2>> {
210 static const bool value =
211 is_valid_type_tag<T1>::value && is_valid_type_tag<T2>::value;
212 static const bool is_tagged = false;
213 };
214
215 template <class T1, class T2>
216 struct UnionT;
217
218 template <class T1, class T2>
219 struct is_valid_type_tag<UnionT<T1, T2>> {
220 static const bool is_tagged =
221 is_valid_type_tag<T1>::is_tagged && is_valid_type_tag<T2>::is_tagged;
222 static const bool value = is_tagged;
223 };
224
225 template <class T1, class T2>
226 struct UnionT {
227 static constexpr MachineType kMachineType =
228 CommonMachineType(MachineTypeOf<T1>::value, MachineTypeOf<T2>::value);
229 static const MachineRepresentation kMachineRepresentation =
230 kMachineType.representation();
231 static_assert(kMachineRepresentation != MachineRepresentation::kNone,
232 "no common representation");
233 static_assert(is_valid_type_tag<T1>::is_tagged &&
234 is_valid_type_tag<T2>::is_tagged,
235 "union types are only possible for tagged values");
236 };
237
238 using AnyTaggedT = UnionT<Object, MaybeObject>;
239 using Number = UnionT<Smi, HeapNumber>;
240 using Numeric = UnionT<Number, BigInt>;
241 using ContextOrEmptyContext = UnionT<Context, Smi>;
242
243 // A pointer to a builtin function, used by Torque's function pointers.
244 using BuiltinPtr = Smi;
245
246 template <class T, class U>
247 struct is_subtype {
248 static const bool value =
249 std::is_base_of<U, T>::value || (std::is_same<U, MaybeObject>::value &&
250 std::is_convertible<T, Object>::value);
251 };
252 template <class T1, class T2, class U>
253 struct is_subtype<UnionT<T1, T2>, U> {
254 static const bool value =
255 is_subtype<T1, U>::value && is_subtype<T2, U>::value;
256 };
257 template <class T, class U1, class U2>
258 struct is_subtype<T, UnionT<U1, U2>> {
259 static const bool value =
260 is_subtype<T, U1>::value || is_subtype<T, U2>::value;
261 };
262 template <class T1, class T2, class U1, class U2>
263 struct is_subtype<UnionT<T1, T2>, UnionT<U1, U2>> {
264 static const bool value =
265 (is_subtype<T1, U1>::value || is_subtype<T1, U2>::value) &&
266 (is_subtype<T2, U1>::value || is_subtype<T2, U2>::value);
267 };
268
269 template <class T, class U>
270 struct types_have_common_values {
271 static const bool value = is_subtype<T, U>::value || is_subtype<U, T>::value;
272 };
273 template <class U>
274 struct types_have_common_values<BoolT, U> {
275 static const bool value = types_have_common_values<Word32T, U>::value;
276 };
277 template <class U>
278 struct types_have_common_values<Uint32T, U> {
279 static const bool value = types_have_common_values<Word32T, U>::value;
280 };
281 template <class U>
282 struct types_have_common_values<Int32T, U> {
283 static const bool value = types_have_common_values<Word32T, U>::value;
284 };
285 template <class U>
286 struct types_have_common_values<Uint64T, U> {
287 static const bool value = types_have_common_values<Word64T, U>::value;
288 };
289 template <class U>
290 struct types_have_common_values<Int64T, U> {
291 static const bool value = types_have_common_values<Word64T, U>::value;
292 };
293 template <class U>
294 struct types_have_common_values<IntPtrT, U> {
295 static const bool value = types_have_common_values<WordT, U>::value;
296 };
297 template <class U>
298 struct types_have_common_values<UintPtrT, U> {
299 static const bool value = types_have_common_values<WordT, U>::value;
300 };
301 template <class T1, class T2, class U>
302 struct types_have_common_values<UnionT<T1, T2>, U> {
303 static const bool value = types_have_common_values<T1, U>::value ||
304 types_have_common_values<T2, U>::value;
305 };
306
307 template <class T, class U1, class U2>
308 struct types_have_common_values<T, UnionT<U1, U2>> {
309 static const bool value = types_have_common_values<T, U1>::value ||
310 types_have_common_values<T, U2>::value;
311 };
312 template <class T1, class T2, class U1, class U2>
313 struct types_have_common_values<UnionT<T1, T2>, UnionT<U1, U2>> {
314 static const bool value = types_have_common_values<T1, U1>::value ||
315 types_have_common_values<T1, U2>::value ||
316 types_have_common_values<T2, U1>::value ||
317 types_have_common_values<T2, U2>::value;
318 };
319
320 // TNode<T> is an SSA value with the static type tag T, which is one of the
321 // following:
322 // - MaybeObject represents the type of all tagged values, including weak
323 // pointers.
324 // - a subclass of internal::Object represents a non-weak tagged type.
325 // - a subclass of internal::UntaggedT represents an untagged type
326 // - ExternalReference
327 // - PairT<T1, T2> for an operation returning two values, with types T1
328 // and T2
329 // - UnionT<T1, T2> represents either a value of type T1 or of type T2.
330 template <class T>
331 class TNode {
332 public:
333 template <class U,
334 typename std::enable_if<is_subtype<U, T>::value, int>::type = 0>
335 TNode(const TNode<U>& other) : node_(other) {
336 LazyTemplateChecks();
337 }
338 TNode() : TNode(nullptr) {}
339
340 TNode operator=(TNode other) {
341 DCHECK_NOT_NULL(other.node_);
342 node_ = other.node_;
343 return *this;
344 }
345
346 bool is_null() const { return node_ == nullptr; }
347
348 operator compiler::Node*() const { return node_; }
349
350 static TNode UncheckedCast(compiler::Node* node) { return TNode(node); }
351
352 protected:
353 explicit TNode(compiler::Node* node) : node_(node) { LazyTemplateChecks(); }
354
355 private:
356 // These checks shouldn't be checked before TNode is actually used.
357 void LazyTemplateChecks() {
358 static_assert(is_valid_type_tag<T>::value, "invalid type tag");
359 }
360
361 compiler::Node* node_;
362 };
363
364 // SloppyTNode<T> is a variant of TNode<T> and allows implicit casts from
365 // Node*. It is intended for function arguments as long as some call sites
366 // still use untyped Node* arguments.
367 // TODO(tebbi): Delete this class once transition is finished.
368 template <class T>
369 class SloppyTNode : public TNode<T> {
370 public:
371 SloppyTNode(compiler::Node* node) // NOLINT(runtime/explicit)
372 : TNode<T>(node) {}
373 template <class U, typename std::enable_if<is_subtype<U, T>::value,
374 int>::type = 0>
375 SloppyTNode(const TNode<U>& other) // NOLINT(runtime/explicit)
376 : TNode<T>(other) {}
377 };
378
379 } // namespace internal
380 } // namespace v8
381
382 #endif // V8_CODEGEN_TNODE_H_
383