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