1 //===- TypeID.h - TypeID RTTI class -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains a definition of the TypeID class. This provides a non
10 // RTTI mechanism for producing unique type IDs in LLVM.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef MLIR_SUPPORT_TYPEID_H
15 #define MLIR_SUPPORT_TYPEID_H
16
17 #include "mlir/Support/LLVM.h"
18 #include "llvm/ADT/DenseMapInfo.h"
19 #include "llvm/Support/PointerLikeTypeTraits.h"
20
21 namespace mlir {
22
23 namespace detail {
24 struct TypeIDExported;
25 } // namespace detail
26
27 /// This class provides an efficient unique identifier for a specific C++ type.
28 /// This allows for a C++ type to be compared, hashed, and stored in an opaque
29 /// context. This class is similar in some ways to std::type_index, but can be
30 /// used for any type. For example, this class could be used to implement LLVM
31 /// style isa/dyn_cast functionality for a type hierarchy:
32 ///
33 /// struct Base {
34 /// Base(TypeID typeID) : typeID(typeID) {}
35 /// TypeID typeID;
36 /// };
37 ///
38 /// struct DerivedA : public Base {
39 /// DerivedA() : Base(TypeID::get<DerivedA>()) {}
40 ///
41 /// static bool classof(const Base *base) {
42 /// return base->typeID == TypeID::get<DerivedA>();
43 /// }
44 /// };
45 ///
46 /// void foo(Base *base) {
47 /// if (DerivedA *a = llvm::dyn_cast<DerivedA>(base))
48 /// ...
49 /// }
50 ///
51 class TypeID {
52 /// This class represents the storage of a type info object.
53 /// Note: We specify an explicit alignment here to allow use with
54 /// PointerIntPair and other utilities/data structures that require a known
55 /// pointer alignment.
56 struct alignas(8) Storage {};
57
58 public:
TypeID()59 TypeID() : TypeID(get<void>()) {}
60 TypeID(const TypeID &) = default;
61
62 /// Comparison operations.
63 bool operator==(const TypeID &other) const {
64 return storage == other.storage;
65 }
66 bool operator!=(const TypeID &other) const { return !(*this == other); }
67
68 /// Construct a type info object for the given type T.
69 template <typename T>
70 static TypeID get();
71 template <template <typename> class Trait>
72 static TypeID get();
73
74 /// Methods for supporting PointerLikeTypeTraits.
getAsOpaquePointer()75 const void *getAsOpaquePointer() const {
76 return static_cast<const void *>(storage);
77 }
getFromOpaquePointer(const void * pointer)78 static TypeID getFromOpaquePointer(const void *pointer) {
79 return TypeID(reinterpret_cast<const Storage *>(pointer));
80 }
81
82 /// Enable hashing TypeID.
83 friend ::llvm::hash_code hash_value(TypeID id);
84
85 private:
TypeID(const Storage * storage)86 TypeID(const Storage *storage) : storage(storage) {}
87
88 /// The storage of this type info object.
89 const Storage *storage;
90
91 // See TypeIDExported below for an explanation of the trampoline behavior.
92 friend struct detail::TypeIDExported;
93 };
94
95 /// Enable hashing TypeID.
hash_value(TypeID id)96 inline ::llvm::hash_code hash_value(TypeID id) {
97 return llvm::hash_value(id.storage);
98 }
99
100 namespace detail {
101
102 /// The static local instance of each get method must be emitted with
103 /// "default" (public) visibility across all shared libraries, regardless of
104 /// whether they are compiled with hidden visibility or not. The only reliable
105 /// way to make this happen is to set the visibility attribute at the
106 /// containing namespace/struct scope. We don't do this on the TypeID (internal
107 /// API) class in order to reduce the scope of what gets exported with
108 /// public visibility. Instead, the get() methods on TypeID trampoline
109 /// through those on this detail class with specific visibility controls
110 /// applied, making visibility declarations on the internal TypeID class not
111 /// required (all visibility relevant pieces are here).
112 /// TODO: This currently won't work when using DLLs as it requires properly
113 /// attaching dllimport and dllexport. Fix this when that information is
114 /// available within LLVM.
115 struct LLVM_EXTERNAL_VISIBILITY TypeIDExported {
116 template <typename T>
getTypeIDExported117 static TypeID get() {
118 static TypeID::Storage instance;
119 return TypeID(&instance);
120 }
121 template <template <typename> class Trait>
getTypeIDExported122 static TypeID get() {
123 static TypeID::Storage instance;
124 return TypeID(&instance);
125 }
126 };
127
128 } // namespace detail
129
130 template <typename T>
get()131 TypeID TypeID::get() {
132 return detail::TypeIDExported::get<T>();
133 }
134 template <template <typename> class Trait>
get()135 TypeID TypeID::get() {
136 return detail::TypeIDExported::get<Trait>();
137 }
138
139 } // end namespace mlir
140
141 namespace llvm {
142 template <> struct DenseMapInfo<mlir::TypeID> {
143 static mlir::TypeID getEmptyKey() {
144 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
145 return mlir::TypeID::getFromOpaquePointer(pointer);
146 }
147 static mlir::TypeID getTombstoneKey() {
148 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
149 return mlir::TypeID::getFromOpaquePointer(pointer);
150 }
151 static unsigned getHashValue(mlir::TypeID val) {
152 return mlir::hash_value(val);
153 }
154 static bool isEqual(mlir::TypeID lhs, mlir::TypeID rhs) { return lhs == rhs; }
155 };
156
157 /// We align TypeID::Storage by 8, so allow LLVM to steal the low bits.
158 template <> struct PointerLikeTypeTraits<mlir::TypeID> {
159 static inline void *getAsVoidPointer(mlir::TypeID info) {
160 return const_cast<void *>(info.getAsOpaquePointer());
161 }
162 static inline mlir::TypeID getFromVoidPointer(void *ptr) {
163 return mlir::TypeID::getFromOpaquePointer(ptr);
164 }
165 static constexpr int NumLowBitsAvailable = 3;
166 };
167
168 } // end namespace llvm
169
170 #endif // MLIR_SUPPORT_TYPEID_H
171