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