| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_CODEGEN_TNODE_H_ |
| #define V8_CODEGEN_TNODE_H_ |
| |
| #include "src/codegen/machine-type.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class HeapNumber; |
| class BigInt; |
| class Object; |
| class Smi; |
| class TaggedIndex; |
| |
| namespace compiler { |
| |
| class Node; |
| |
| } // namespace compiler |
| |
| struct UntaggedT {}; |
| |
| struct IntegralT : UntaggedT {}; |
| |
| struct WordT : IntegralT { |
| static const MachineRepresentation kMachineRepresentation = |
| MachineType::PointerRepresentation(); |
| }; |
| |
| struct RawPtrT : WordT { |
| static constexpr MachineType kMachineType = MachineType::Pointer(); |
| }; |
| |
| template <class To> |
| struct RawPtr : RawPtrT {}; |
| |
| struct Word32T : IntegralT { |
| static const MachineRepresentation kMachineRepresentation = |
| MachineRepresentation::kWord32; |
| }; |
| struct Int32T : Word32T { |
| static constexpr MachineType kMachineType = MachineType::Int32(); |
| }; |
| struct Uint32T : Word32T { |
| static constexpr MachineType kMachineType = MachineType::Uint32(); |
| }; |
| struct Int16T : Int32T { |
| static constexpr MachineType kMachineType = MachineType::Int16(); |
| }; |
| struct Uint16T : Uint32T, Int32T { |
| static constexpr MachineType kMachineType = MachineType::Uint16(); |
| }; |
| struct Int8T : Int16T { |
| static constexpr MachineType kMachineType = MachineType::Int8(); |
| }; |
| struct Uint8T : Uint16T, Int16T { |
| static constexpr MachineType kMachineType = MachineType::Uint8(); |
| }; |
| |
| struct Word64T : IntegralT { |
| static const MachineRepresentation kMachineRepresentation = |
| MachineRepresentation::kWord64; |
| }; |
| struct Int64T : Word64T { |
| static constexpr MachineType kMachineType = MachineType::Int64(); |
| }; |
| struct Uint64T : Word64T { |
| static constexpr MachineType kMachineType = MachineType::Uint64(); |
| }; |
| |
| struct IntPtrT : WordT { |
| static constexpr MachineType kMachineType = MachineType::IntPtr(); |
| }; |
| struct UintPtrT : WordT { |
| static constexpr MachineType kMachineType = MachineType::UintPtr(); |
| }; |
| |
| struct ExternalPointerT : UntaggedT { |
| static const MachineRepresentation kMachineRepresentation = |
| MachineType::PointerRepresentation(); |
| static constexpr MachineType kMachineType = MachineType::Pointer(); |
| }; |
| |
| struct Float32T : UntaggedT { |
| static const MachineRepresentation kMachineRepresentation = |
| MachineRepresentation::kFloat32; |
| static constexpr MachineType kMachineType = MachineType::Float32(); |
| }; |
| |
| struct Float64T : UntaggedT { |
| static const MachineRepresentation kMachineRepresentation = |
| MachineRepresentation::kFloat64; |
| static constexpr MachineType kMachineType = MachineType::Float64(); |
| }; |
| |
| #ifdef V8_COMPRESS_POINTERS |
| using TaggedT = Int32T; |
| #else |
| using TaggedT = IntPtrT; |
| #endif |
| |
| // Result of a comparison operation. |
| struct BoolT : Word32T {}; |
| |
| // Value type of a Turbofan node with two results. |
| template <class T1, class T2> |
| struct PairT {}; |
| |
| inline constexpr MachineType CommonMachineType(MachineType type1, |
| MachineType type2) { |
| return (type1 == type2) ? type1 |
| : ((type1.IsTagged() && type2.IsTagged()) |
| ? MachineType::AnyTagged() |
| : MachineType::None()); |
| } |
| |
| template <class Type, class Enable = void> |
| struct MachineTypeOf { |
| static constexpr MachineType value = Type::kMachineType; |
| }; |
| |
| template <class Type, class Enable> |
| constexpr MachineType MachineTypeOf<Type, Enable>::value; |
| |
| template <> |
| struct MachineTypeOf<Object> { |
| static constexpr MachineType value = MachineType::AnyTagged(); |
| }; |
| template <> |
| struct MachineTypeOf<MaybeObject> { |
| static constexpr MachineType value = MachineType::AnyTagged(); |
| }; |
| template <> |
| struct MachineTypeOf<Smi> { |
| static constexpr MachineType value = MachineType::TaggedSigned(); |
| }; |
| template <> |
| struct MachineTypeOf<TaggedIndex> { |
| static constexpr MachineType value = MachineType::Pointer(); |
| }; |
| template <class HeapObjectSubtype> |
| struct MachineTypeOf<HeapObjectSubtype, |
| typename std::enable_if<std::is_base_of< |
| HeapObject, HeapObjectSubtype>::value>::type> { |
| static constexpr MachineType value = MachineType::TaggedPointer(); |
| }; |
| template <> |
| struct MachineTypeOf<ExternalReference> { |
| static constexpr MachineType value = MachineType::Pointer(); |
| }; |
| |
| template <class HeapObjectSubtype> |
| constexpr MachineType MachineTypeOf< |
| HeapObjectSubtype, typename std::enable_if<std::is_base_of< |
| HeapObject, HeapObjectSubtype>::value>::type>::value; |
| |
| template <class Type, class Enable = void> |
| struct MachineRepresentationOf { |
| static const MachineRepresentation value = Type::kMachineRepresentation; |
| }; |
| // If T defines kMachineType, then we take the machine representation from |
| // there. |
| template <class T> |
| struct MachineRepresentationOf<T, base::void_t<decltype(T::kMachineType)>> { |
| static const MachineRepresentation value = T::kMachineType.representation(); |
| }; |
| template <class T> |
| struct MachineRepresentationOf< |
| T, typename std::enable_if<std::is_base_of<Object, T>::value>::type> { |
| static const MachineRepresentation value = |
| MachineTypeOf<T>::value.representation(); |
| }; |
| template <class T> |
| struct MachineRepresentationOf< |
| T, typename std::enable_if<std::is_base_of<MaybeObject, T>::value>::type> { |
| static const MachineRepresentation value = |
| MachineTypeOf<T>::value.representation(); |
| }; |
| template <> |
| struct MachineRepresentationOf<ExternalReference> { |
| static const MachineRepresentation value = RawPtrT::kMachineRepresentation; |
| }; |
| |
| template <typename T> |
| constexpr bool IsMachineRepresentationOf(MachineRepresentation r) { |
| return MachineRepresentationOf<T>::value == r; |
| } |
| |
| template <class T> |
| constexpr MachineRepresentation PhiMachineRepresentationOf = |
| std::is_base_of<Word32T, T>::value ? MachineRepresentation::kWord32 |
| : MachineRepresentationOf<T>::value; |
| |
| template <class T> |
| struct is_valid_type_tag { |
| static const bool value = std::is_base_of<Object, T>::value || |
| std::is_base_of<UntaggedT, T>::value || |
| std::is_base_of<MaybeObject, T>::value || |
| std::is_same<ExternalReference, T>::value; |
| static const bool is_tagged = std::is_base_of<Object, T>::value || |
| std::is_base_of<MaybeObject, T>::value; |
| }; |
| |
| template <class T1, class T2> |
| struct is_valid_type_tag<PairT<T1, T2>> { |
| static const bool value = |
| is_valid_type_tag<T1>::value && is_valid_type_tag<T2>::value; |
| static const bool is_tagged = false; |
| }; |
| |
| template <class T1, class T2> |
| struct UnionT; |
| |
| template <class T1, class T2> |
| struct is_valid_type_tag<UnionT<T1, T2>> { |
| static const bool is_tagged = |
| is_valid_type_tag<T1>::is_tagged && is_valid_type_tag<T2>::is_tagged; |
| static const bool value = is_tagged; |
| }; |
| |
| template <class T1, class T2> |
| struct UnionT { |
| static constexpr MachineType kMachineType = |
| CommonMachineType(MachineTypeOf<T1>::value, MachineTypeOf<T2>::value); |
| static const MachineRepresentation kMachineRepresentation = |
| kMachineType.representation(); |
| static_assert(kMachineRepresentation != MachineRepresentation::kNone, |
| "no common representation"); |
| static_assert(is_valid_type_tag<T1>::is_tagged && |
| is_valid_type_tag<T2>::is_tagged, |
| "union types are only possible for tagged values"); |
| }; |
| |
| using AnyTaggedT = UnionT<Object, MaybeObject>; |
| using Number = UnionT<Smi, HeapNumber>; |
| using Numeric = UnionT<Number, BigInt>; |
| using ContextOrEmptyContext = UnionT<Context, Smi>; |
| |
| // A pointer to a builtin function, used by Torque's function pointers. |
| using BuiltinPtr = Smi; |
| |
| template <class T, class U> |
| struct is_subtype { |
| static const bool value = |
| std::is_base_of<U, T>::value || (std::is_same<U, MaybeObject>::value && |
| std::is_convertible<T, Object>::value); |
| }; |
| template <class T1, class T2, class U> |
| struct is_subtype<UnionT<T1, T2>, U> { |
| static const bool value = |
| is_subtype<T1, U>::value && is_subtype<T2, U>::value; |
| }; |
| template <class T, class U1, class U2> |
| struct is_subtype<T, UnionT<U1, U2>> { |
| static const bool value = |
| is_subtype<T, U1>::value || is_subtype<T, U2>::value; |
| }; |
| template <class T1, class T2, class U1, class U2> |
| struct is_subtype<UnionT<T1, T2>, UnionT<U1, U2>> { |
| static const bool value = |
| (is_subtype<T1, U1>::value || is_subtype<T1, U2>::value) && |
| (is_subtype<T2, U1>::value || is_subtype<T2, U2>::value); |
| }; |
| |
| template <class T, class U> |
| struct types_have_common_values { |
| static const bool value = is_subtype<T, U>::value || is_subtype<U, T>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<BoolT, U> { |
| static const bool value = types_have_common_values<Word32T, U>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<Uint32T, U> { |
| static const bool value = types_have_common_values<Word32T, U>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<Int32T, U> { |
| static const bool value = types_have_common_values<Word32T, U>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<Uint64T, U> { |
| static const bool value = types_have_common_values<Word64T, U>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<Int64T, U> { |
| static const bool value = types_have_common_values<Word64T, U>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<IntPtrT, U> { |
| static const bool value = types_have_common_values<WordT, U>::value; |
| }; |
| template <class U> |
| struct types_have_common_values<UintPtrT, U> { |
| static const bool value = types_have_common_values<WordT, U>::value; |
| }; |
| template <class T1, class T2, class U> |
| struct types_have_common_values<UnionT<T1, T2>, U> { |
| static const bool value = types_have_common_values<T1, U>::value || |
| types_have_common_values<T2, U>::value; |
| }; |
| |
| template <class T, class U1, class U2> |
| struct types_have_common_values<T, UnionT<U1, U2>> { |
| static const bool value = types_have_common_values<T, U1>::value || |
| types_have_common_values<T, U2>::value; |
| }; |
| template <class T1, class T2, class U1, class U2> |
| struct types_have_common_values<UnionT<T1, T2>, UnionT<U1, U2>> { |
| static const bool value = types_have_common_values<T1, U1>::value || |
| types_have_common_values<T1, U2>::value || |
| types_have_common_values<T2, U1>::value || |
| types_have_common_values<T2, U2>::value; |
| }; |
| |
| // TNode<T> is an SSA value with the static type tag T, which is one of the |
| // following: |
| // - MaybeObject represents the type of all tagged values, including weak |
| // pointers. |
| // - a subclass of internal::Object represents a non-weak tagged type. |
| // - a subclass of internal::UntaggedT represents an untagged type |
| // - ExternalReference |
| // - PairT<T1, T2> for an operation returning two values, with types T1 |
| // and T2 |
| // - UnionT<T1, T2> represents either a value of type T1 or of type T2. |
| template <class T> |
| class TNode { |
| public: |
| template <class U, |
| typename std::enable_if<is_subtype<U, T>::value, int>::type = 0> |
| TNode(const TNode<U>& other) : node_(other) { |
| LazyTemplateChecks(); |
| } |
| TNode() : TNode(nullptr) {} |
| |
| TNode operator=(TNode other) { |
| DCHECK_NOT_NULL(other.node_); |
| node_ = other.node_; |
| return *this; |
| } |
| |
| bool is_null() const { return node_ == nullptr; } |
| |
| operator compiler::Node*() const { return node_; } |
| |
| static TNode UncheckedCast(compiler::Node* node) { return TNode(node); } |
| |
| protected: |
| explicit TNode(compiler::Node* node) : node_(node) { LazyTemplateChecks(); } |
| |
| private: |
| // These checks shouldn't be checked before TNode is actually used. |
| void LazyTemplateChecks() { |
| static_assert(is_valid_type_tag<T>::value, "invalid type tag"); |
| } |
| |
| compiler::Node* node_; |
| }; |
| |
| // SloppyTNode<T> is a variant of TNode<T> and allows implicit casts from |
| // Node*. It is intended for function arguments as long as some call sites |
| // still use untyped Node* arguments. |
| // TODO(tebbi): Delete this class once transition is finished. |
| template <class T> |
| class SloppyTNode : public TNode<T> { |
| public: |
| SloppyTNode(compiler::Node* node) // NOLINT(runtime/explicit) |
| : TNode<T>(node) {} |
| template <class U, typename std::enable_if<is_subtype<U, T>::value, |
| int>::type = 0> |
| SloppyTNode(const TNode<U>& other) // NOLINT(runtime/explicit) |
| : TNode<T>(other) {} |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_CODEGEN_TNODE_H_ |