MLIR  15.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> using Model = typename Traits::template Model<T>;
75  template <typename T>
76  using FallbackModel = typename Traits::template FallbackModel<T>;
77  using InterfaceBase =
79  template <typename T, typename U>
80  using ExternalModel = typename Traits::template ExternalModel<T, U>;
81 
82  /// This is a special trait that registers a given interface with an object.
83  template <typename ConcreteT>
84  struct Trait : public BaseTrait<ConcreteT, Trait> {
86 
87  /// Define an accessor for the ID of this interface.
88  static TypeID getInterfaceID() { return TypeID::get<ConcreteType>(); }
89  };
90 
91  /// Construct an interface from an instance of the value type.
92  Interface(ValueT t = ValueT())
93  : BaseType(t), impl(t ? ConcreteType::getInterfaceFor(t) : nullptr) {
94  assert((!t || impl) && "expected value to provide interface instance");
95  }
96  Interface(std::nullptr_t) : BaseType(ValueT()), impl(nullptr) {}
97 
98  /// Construct an interface instance from a type that implements this
99  /// interface's trait.
100  template <typename T, typename std::enable_if_t<
101  std::is_base_of<Trait<T>, T>::value> * = nullptr>
103  : BaseType(t), impl(t ? ConcreteType::getInterfaceFor(t) : nullptr) {
104  assert((!t || impl) && "expected value to provide interface instance");
105  }
106 
107  /// Support 'classof' by checking if the given object defines the concrete
108  /// interface.
109  static bool classof(ValueT t) { return ConcreteType::getInterfaceFor(t); }
110 
111  /// Define an accessor for the ID of this interface.
112  static TypeID getInterfaceID() { return TypeID::get<ConcreteType>(); }
113 
114 protected:
115  /// Get the raw concept in the correct derived concept type.
116  const Concept *getImpl() const { return impl; }
117  Concept *getImpl() { return impl; }
118 
119 private:
120  /// A pointer to the impl concept object.
121  Concept *impl;
122 };
123 
124 //===----------------------------------------------------------------------===//
125 // InterfaceMap
126 //===----------------------------------------------------------------------===//
127 
128 /// Template utility that computes the number of elements within `T` that
129 /// satisfy the given predicate.
130 template <template <class> class Pred, size_t N, typename... Ts>
131 struct count_if_t_impl : public std::integral_constant<size_t, N> {};
132 template <template <class> class Pred, size_t N, typename T, typename... Us>
133 struct count_if_t_impl<Pred, N, T, Us...>
134  : public std::integral_constant<
135  size_t,
136  count_if_t_impl<Pred, N + (Pred<T>::value ? 1 : 0), Us...>::value> {};
137 template <template <class> class Pred, typename... Ts>
138 using count_if_t = count_if_t_impl<Pred, 0, Ts...>;
139 
140 namespace {
141 /// Type trait indicating whether all template arguments are
142 /// trivially-destructible.
143 template <typename... Args>
144 struct all_trivially_destructible;
145 
146 template <typename Arg, typename... Args>
147 struct all_trivially_destructible<Arg, Args...> {
148  static constexpr const bool value =
150  all_trivially_destructible<Args...>::value;
151 };
152 
153 template <>
154 struct all_trivially_destructible<> {
155  static constexpr const bool value = true;
156 };
157 } // namespace
158 
159 /// This class provides an efficient mapping between a given `Interface` type,
160 /// and a particular implementation of its concept.
162  /// Trait to check if T provides a static 'getInterfaceID' method.
163  template <typename T, typename... Args>
164  using has_get_interface_id = decltype(T::getInterfaceID());
165  template <typename T>
166  using detect_get_interface_id = llvm::is_detected<has_get_interface_id, T>;
167  template <typename... Types>
168  using num_interface_types_t = count_if_t<detect_get_interface_id, Types...>;
169 
170 public:
171  InterfaceMap(InterfaceMap &&) = default;
173  for (auto &it : interfaces)
174  free(it.second);
175  interfaces = std::move(rhs.interfaces);
176  return *this;
177  }
179  for (auto &it : interfaces)
180  free(it.second);
181  }
182 
183  /// Construct an InterfaceMap with the given set of template types. For
184  /// convenience given that object trait lists may contain other non-interface
185  /// types, not all of the types need to be interfaces. The provided types that
186  /// do not represent interfaces are not added to the interface map.
187  template <typename... Types>
188  static InterfaceMap get() {
189  // TODO: Use constexpr if here in C++17.
190  constexpr size_t numInterfaces = num_interface_types_t<Types...>::value;
191  if (numInterfaces == 0)
192  return InterfaceMap();
193 
194  std::array<std::pair<TypeID, void *>, numInterfaces> elements;
195  std::pair<TypeID, void *> *elementIt = elements.data();
196  (void)elementIt;
197  (void)std::initializer_list<int>{
198  0, (addModelAndUpdateIterator<Types>(elementIt), 0)...};
199  return InterfaceMap(elements);
200  }
201 
202  /// Returns an instance of the concept object for the given interface if it
203  /// was registered to this map, null otherwise.
204  template <typename T> typename T::Concept *lookup() const {
205  return reinterpret_cast<typename T::Concept *>(lookup(T::getInterfaceID()));
206  }
207 
208  /// Returns true if the interface map contains an interface for the given id.
209  bool contains(TypeID interfaceID) const { return lookup(interfaceID); }
210 
211  /// Create an InterfaceMap given with the implementation of the interfaces.
212  /// The use of this constructor is in general discouraged in favor of
213  /// 'InterfaceMap::get<InterfaceA, ...>()'.
214  InterfaceMap(MutableArrayRef<std::pair<TypeID, void *>> elements);
215 
216  /// Insert the given models as implementations of the corresponding interfaces
217  /// for the concrete attribute class.
218  template <typename... IfaceModels>
219  void insert() {
221  "interface models must be trivially destructible");
222  std::pair<TypeID, void *> elements[] = {
223  std::make_pair(IfaceModels::Interface::getInterfaceID(),
224  new (malloc(sizeof(IfaceModels))) IfaceModels())...};
225  insert(elements);
226  }
227 
228 private:
229  InterfaceMap() = default;
230 
231  /// Assign the interface model of the type to the given opaque element
232  /// iterator and increment it.
233  template <typename T>
235  addModelAndUpdateIterator(std::pair<TypeID, void *> *&elementIt) {
236  *elementIt = {T::getInterfaceID(), new (malloc(sizeof(typename T::ModelT)))
237  typename T::ModelT()};
238  ++elementIt;
239  }
240  /// Overload when `T` isn't an interface.
241  template <typename T>
243  addModelAndUpdateIterator(std::pair<TypeID, void *> *&) {}
244 
245  /// Insert the given set of interface models into the interface map.
246  void insert(ArrayRef<std::pair<TypeID, void *>> elements);
247 
248  /// Compare two TypeID instances by comparing the underlying pointer.
249  static bool compare(TypeID lhs, TypeID rhs) {
250  return lhs.getAsOpaquePointer() < rhs.getAsOpaquePointer();
251  }
252 
253  /// Returns an instance of the concept object for the given interface id if it
254  /// was registered to this map, null otherwise.
255  void *lookup(TypeID id) const {
256  const auto *it =
257  llvm::lower_bound(interfaces, id, [](const auto &it, TypeID id) {
258  return compare(it.first, id);
259  });
260  return (it != interfaces.end() && it->first == id) ? it->second : nullptr;
261  }
262 
263  /// A list of interface instances, sorted by TypeID.
265 };
266 
267 } // namespace detail
268 } // namespace mlir
269 
270 #endif
Include the generated interface declarations.
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)
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.
static bool classof(ValueT t)
Support &#39;classof&#39; by checking if the given object defines the concrete interface. ...
int compare(Fraction x, Fraction y)
Three-way comparison between two fractions.
Definition: Fraction.h:54
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.