MLIR  16.0.0git
InterfaceSupport.h
Go to the documentation of this file.
1 //===- InterfaceSupport.h - MLIR Interface Support Classes ------*- 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 defines several support classes for defining interfaces.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_SUPPORT_INTERFACESUPPORT_H
14 #define MLIR_SUPPORT_INTERFACESUPPORT_H
15 
16 #include "mlir/Support/TypeID.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/Support/TypeName.h"
20 
21 namespace mlir {
22 namespace detail {
23 //===----------------------------------------------------------------------===//
24 // Interface
25 //===----------------------------------------------------------------------===//
26 
27 /// This class represents an abstract interface. An interface is a simplified
28 /// mechanism for attaching concept based polymorphism to a class hierarchy. An
29 /// interface is comprised of two components:
30 /// * The derived interface class: This is what users interact with, and invoke
31 /// methods on.
32 /// * An interface `Trait` class: This is the class that is attached to the
33 /// object implementing the interface. It is the mechanism with which models
34 /// are specialized.
35 ///
36 /// Derived interfaces types must provide the following template types:
37 /// * ConcreteType: The CRTP derived type.
38 /// * ValueT: The opaque type the derived interface operates on. For example
39 /// `Operation*` for operation interfaces, or `Attribute` for
40 /// attribute interfaces.
41 /// * Traits: A class that contains definitions for a 'Concept' and a 'Model'
42 /// class. The 'Concept' class defines an abstract virtual interface,
43 /// where as the 'Model' class implements this interface for a
44 /// specific derived T type. Both of these classes *must* not contain
45 /// non-static data. A simple example is shown below:
46 ///
47 /// ```c++
48 /// struct ExampleInterfaceTraits {
49 /// struct Concept {
50 /// virtual unsigned getNumInputs(T t) const = 0;
51 /// };
52 /// template <typename DerivedT> class Model {
53 /// unsigned getNumInputs(T t) const final {
54 /// return cast<DerivedT>(t).getNumInputs();
55 /// }
56 /// };
57 /// };
58 /// ```
59 ///
60 /// * BaseType: A desired base type for the interface. This is a class that
61 /// provides that provides specific functionality for the `ValueT`
62 /// value. For instance the specific `Op` that will wrap the
63 /// `Operation*` for an `OpInterface`.
64 /// * BaseTrait: The base type for the interface trait. This is the base class
65 /// to use for the interface trait that will be attached to each
66 /// instance of `ValueT` that implements this interface.
67 ///
68 template <typename ConcreteType, typename ValueT, typename Traits,
69  typename BaseType,
70  template <typename, template <typename> class> class BaseTrait>
71 class Interface : public BaseType {
72 public:
73  using Concept = typename Traits::Concept;
74  template <typename T>
75  using Model = typename Traits::template Model<T>;
76  template <typename T>
77  using FallbackModel = typename Traits::template FallbackModel<T>;
78  using InterfaceBase =
80  template <typename T, typename U>
81  using ExternalModel = typename Traits::template ExternalModel<T, U>;
82  using ValueType = ValueT;
83 
84  /// This is a special trait that registers a given interface with an object.
85  template <typename ConcreteT>
86  struct Trait : public BaseTrait<ConcreteT, Trait> {
88 
89  /// Define an accessor for the ID of this interface.
90  static TypeID getInterfaceID() { return TypeID::get<ConcreteType>(); }
91  };
92 
93  /// Construct an interface from an instance of the value type.
94  Interface(ValueT t = ValueT())
95  : BaseType(t), impl(t ? ConcreteType::getInterfaceFor(t) : nullptr) {
96  assert((!t || impl) && "expected value to provide interface instance");
97  }
98  Interface(std::nullptr_t) : BaseType(ValueT()), impl(nullptr) {}
99 
100  /// Construct an interface instance from a type that implements this
101  /// interface's trait.
102  template <typename T, typename std::enable_if_t<
103  std::is_base_of<Trait<T>, T>::value> * = nullptr>
105  : BaseType(t), impl(t ? ConcreteType::getInterfaceFor(t) : nullptr) {
106  assert((!t || impl) && "expected value to provide interface instance");
107  }
108 
109  /// Constructor for DenseMapInfo's empty key and tombstone key.
110  Interface(ValueT t, std::nullptr_t) : BaseType(t), impl(nullptr) {}
111 
112  /// Support 'classof' by checking if the given object defines the concrete
113  /// interface.
114  static bool classof(ValueT t) { return ConcreteType::getInterfaceFor(t); }
115 
116  /// Define an accessor for the ID of this interface.
117  static TypeID getInterfaceID() { return TypeID::get<ConcreteType>(); }
118 
119 protected:
120  /// Get the raw concept in the correct derived concept type.
121  const Concept *getImpl() const { return impl; }
122  Concept *getImpl() { return impl; }
123 
124 private:
125  /// A pointer to the impl concept object.
126  Concept *impl;
127 };
128 
129 //===----------------------------------------------------------------------===//
130 // InterfaceMap
131 //===----------------------------------------------------------------------===//
132 
133 /// Template utility that computes the number of elements within `T` that
134 /// satisfy the given predicate.
135 template <template <class> class Pred, size_t N, typename... Ts>
136 struct count_if_t_impl : public std::integral_constant<size_t, N> {};
137 template <template <class> class Pred, size_t N, typename T, typename... Us>
138 struct count_if_t_impl<Pred, N, T, Us...>
139  : public std::integral_constant<
140  size_t,
141  count_if_t_impl<Pred, N + (Pred<T>::value ? 1 : 0), Us...>::value> {};
142 template <template <class> class Pred, typename... Ts>
143 using count_if_t = count_if_t_impl<Pred, 0, Ts...>;
144 
145 namespace {
146 /// Type trait indicating whether all template arguments are
147 /// trivially-destructible.
148 template <typename... Args>
149 struct all_trivially_destructible;
150 
151 template <typename Arg, typename... Args>
152 struct all_trivially_destructible<Arg, Args...> {
153  static constexpr const bool value =
155  all_trivially_destructible<Args...>::value;
156 };
157 
158 template <>
159 struct all_trivially_destructible<> {
160  static constexpr const bool value = true;
161 };
162 } // namespace
163 
164 /// This class provides an efficient mapping between a given `Interface` type,
165 /// and a particular implementation of its concept.
167  /// Trait to check if T provides a static 'getInterfaceID' method.
168  template <typename T, typename... Args>
169  using has_get_interface_id = decltype(T::getInterfaceID());
170  template <typename T>
171  using detect_get_interface_id = llvm::is_detected<has_get_interface_id, T>;
172  template <typename... Types>
173  using num_interface_types_t = count_if_t<detect_get_interface_id, Types...>;
174 
175 public:
176  InterfaceMap(InterfaceMap &&) = default;
178  for (auto &it : interfaces)
179  free(it.second);
180  interfaces = std::move(rhs.interfaces);
181  return *this;
182  }
184  for (auto &it : interfaces)
185  free(it.second);
186  }
187 
188  /// Construct an InterfaceMap with the given set of template types. For
189  /// convenience given that object trait lists may contain other non-interface
190  /// types, not all of the types need to be interfaces. The provided types that
191  /// do not represent interfaces are not added to the interface map.
192  template <typename... Types>
193  static InterfaceMap get() {
194  constexpr size_t numInterfaces = num_interface_types_t<Types...>::value;
195  if constexpr (numInterfaces == 0)
196  return InterfaceMap();
197 
198  std::array<std::pair<TypeID, void *>, numInterfaces> elements;
199  std::pair<TypeID, void *> *elementIt = elements.data();
200  (void)elementIt;
201  (addModelAndUpdateIterator<Types>(elementIt), ...);
202  return InterfaceMap(elements);
203  }
204 
205  /// Returns an instance of the concept object for the given interface if it
206  /// was registered to this map, null otherwise.
207  template <typename T>
208  typename T::Concept *lookup() const {
209  return reinterpret_cast<typename T::Concept *>(lookup(T::getInterfaceID()));
210  }
211 
212  /// Returns true if the interface map contains an interface for the given id.
213  bool contains(TypeID interfaceID) const { return lookup(interfaceID); }
214 
215  /// Create an InterfaceMap given with the implementation of the interfaces.
216  /// The use of this constructor is in general discouraged in favor of
217  /// 'InterfaceMap::get<InterfaceA, ...>()'.
218  InterfaceMap(MutableArrayRef<std::pair<TypeID, void *>> elements);
219 
220  /// Insert the given models as implementations of the corresponding interfaces
221  /// for the concrete attribute class.
222  template <typename... IfaceModels>
223  void insert() {
225  "interface models must be trivially destructible");
226  std::pair<TypeID, void *> elements[] = {
227  std::make_pair(IfaceModels::Interface::getInterfaceID(),
228  new (malloc(sizeof(IfaceModels))) IfaceModels())...};
229  insert(elements);
230  }
231 
232 private:
233  InterfaceMap() = default;
234 
235  /// Assign the interface model of the type to the given opaque element
236  /// iterator and increment it.
237  template <typename T>
239  addModelAndUpdateIterator(std::pair<TypeID, void *> *&elementIt) {
240  *elementIt = {T::getInterfaceID(), new (malloc(sizeof(typename T::ModelT)))
241  typename T::ModelT()};
242  ++elementIt;
243  }
244  /// Overload when `T` isn't an interface.
245  template <typename T>
247  addModelAndUpdateIterator(std::pair<TypeID, void *> *&) {}
248 
249  /// Insert the given set of interface models into the interface map.
250  void insert(ArrayRef<std::pair<TypeID, void *>> elements);
251 
252  /// Compare two TypeID instances by comparing the underlying pointer.
253  static bool compare(TypeID lhs, TypeID rhs) {
254  return lhs.getAsOpaquePointer() < rhs.getAsOpaquePointer();
255  }
256 
257  /// Returns an instance of the concept object for the given interface id if it
258  /// was registered to this map, null otherwise.
259  void *lookup(TypeID id) const {
260  const auto *it =
261  llvm::lower_bound(interfaces, id, [](const auto &it, TypeID id) {
262  return compare(it.first, id);
263  });
264  return (it != interfaces.end() && it->first == id) ? it->second : nullptr;
265  }
266 
267  /// A list of interface instances, sorted by TypeID.
269 };
270 
271 template <typename ConcreteType, typename ValueT, typename Traits,
272  typename BaseType,
273  template <typename, template <typename> class> class BaseTrait>
274 void isInterfaceImpl(
275  Interface<ConcreteType, ValueT, Traits, BaseType, BaseTrait> &);
276 
277 template <typename T>
278 using is_interface_t = decltype(isInterfaceImpl(std::declval<T &>()));
279 
280 template <typename T>
281 using IsInterface = llvm::is_detected<is_interface_t, T>;
282 
283 } // namespace detail
284 } // namespace mlir
285 
286 namespace llvm {
287 
288 template <typename T>
289 struct DenseMapInfo<T, std::enable_if_t<mlir::detail::IsInterface<T>::value>> {
291 
292  static T getEmptyKey() { return T(ValueTypeInfo::getEmptyKey(), nullptr); }
293 
294  static T getTombstoneKey() {
295  return T(ValueTypeInfo::getTombstoneKey(), nullptr);
296  }
297 
298  static unsigned getHashValue(T val) {
299  return ValueTypeInfo::getHashValue(val);
300  }
301 
302  static bool isEqual(T lhs, T rhs) { return ValueTypeInfo::isEqual(lhs, rhs); }
303 };
304 
305 } // namespace llvm
306 
307 #endif
Include the generated interface declarations.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
void isInterfaceImpl(Interface< ConcreteType, ValueT, Traits, BaseType, BaseTrait > &)
This is a special trait that registers a given interface with an object.
Interface(T t)
Construct an interface instance from a type that implements this interface&#39;s trait.
This class represents an abstract interface.
Interface(ValueT t=ValueT())
Construct an interface from an instance of the value type.
static constexpr const bool value
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
Template utility that computes the number of elements within T that satisfy the given predicate...
This class provides an efficient mapping between a given Interface type, and a particular implementat...
static TypeID getInterfaceID()
Define an accessor for the ID of this interface.
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Definition: TypeID.h:129
T::Concept * lookup() const
Returns an instance of the concept object for the given interface if it was registered to this map...
Interface(std::nullptr_t)
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
decltype(isInterfaceImpl(std::declval< T & >())) is_interface_t
void insert()
Insert the given models as implementations of the corresponding interfaces for the concrete attribute...
bool contains(TypeID interfaceID) const
Returns true if the interface map contains an interface for the given id.
llvm::is_detected< is_interface_t, T > IsInterface
static bool classof(ValueT t)
Support &#39;classof&#39; by checking if the given object defines the concrete interface. ...
Interface(ValueT t, std::nullptr_t)
Constructor for DenseMapInfo&#39;s empty key and tombstone key.
InterfaceMap & operator=(InterfaceMap &&rhs)
const Concept * getImpl() const
Get the raw concept in the correct derived concept type.
static TypeID getInterfaceID()
Define an accessor for the ID of this interface.
int compare(const Fraction &x, const Fraction &y)
Three-way comparison between two fractions.
Definition: Fraction.h:59