• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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