[Mlir-commits] [mlir] 9c8fe39 - [mlir] check interfaces are attached to the expected object

Alex Zinenko llvmlistbot at llvm.org
Wed Jun 15 06:08:08 PDT 2022


Author: Alex Zinenko
Date: 2022-06-15T15:07:57+02:00
New Revision: 9c8fe394cf6bcba6dbe643747d1eb2811734883b

URL: https://github.com/llvm/llvm-project/commit/9c8fe394cf6bcba6dbe643747d1eb2811734883b
DIFF: https://github.com/llvm/llvm-project/commit/9c8fe394cf6bcba6dbe643747d1eb2811734883b.diff

LOG: [mlir] check interfaces are attached to the expected object

Add static assertions into the various `attachInterface` methods, which are
used for adding external interface implementations to attributes, operations
and types, that ensure `ExternalModel` interface classes are instantiated for
the same concrete operation for the concrete base (potentially self) attribute
or type as they are attached to. `FallbackModel`s remain usable for generic
interface models that should support more than one kind of entities.

Reviewed By: springerm

Differential Revision: https://reviews.llvm.org/D127850

Added: 
    

Modified: 
    mlir/include/mlir/IR/OpDefinition.h
    mlir/include/mlir/IR/StorageUniquerSupport.h
    mlir/tools/mlir-tblgen/OpInterfacesGen.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h
index 33d962d01598a..42eccde488919 100644
--- a/mlir/include/mlir/IR/OpDefinition.h
+++ b/mlir/include/mlir/IR/OpDefinition.h
@@ -1679,8 +1679,8 @@ class Op : public OpState, public Traits<ConcreteType>... {
         reinterpret_cast<Operation *>(const_cast<void *>(pointer)));
   }
 
-  /// Attach the given models as implementations of the corresponding interfaces
-  /// for the concrete operation.
+  /// Attach the given models as implementations of the corresponding
+  /// interfaces for the concrete operation.
   template <typename... Models>
   static void attachInterface(MLIRContext &context) {
     Optional<RegisteredOperationName> info = RegisteredOperationName::lookup(
@@ -1689,6 +1689,7 @@ class Op : public OpState, public Traits<ConcreteType>... {
       llvm::report_fatal_error(
           "Attempting to attach an interface to an unregistered operation " +
           ConcreteType::getOperationName() + ".");
+    (void)std::initializer_list<int>{(checkInterfaceTarget<Models>(), 0)...};
     info->attachInterface<Models...>();
   }
 
@@ -1714,6 +1715,32 @@ class Op : public OpState, public Traits<ConcreteType>... {
   template <typename T>
   using detect_has_print = llvm::is_detected<has_print, T>;
 
+  /// Trait to check if T provides a 'ConcreteEntity' type alias.
+  template <typename T>
+  using has_concrete_entity_t = typename T::ConcreteEntity;
+
+  /// A struct-wrapped type alias to T::ConcreteEntity if provided and to
+  /// ConcreteType otherwise. This is akin to std::conditional but doesn't fail
+  /// on the missing typedef. Useful for checking if the interface is targeting
+  /// the right class.
+  template <typename T,
+            bool = llvm::is_detected<has_concrete_entity_t, T>::value>
+  struct InterfaceTargetOrOpT {
+    using type = typename T::ConcreteEntity;
+  };
+  template <typename T> struct InterfaceTargetOrOpT<T, false> {
+    using type = ConcreteType;
+  };
+
+  /// A hook for static assertion that the external interface model T is
+  /// targeting the concrete type of this op. The model can also be a fallback
+  /// model that works for every op.
+  template <typename T> static void checkInterfaceTarget() {
+    static_assert(std::is_same<typename InterfaceTargetOrOpT<T>::type,
+                               ConcreteType>::value,
+                  "attaching an interface to the wrong op kind");
+  }
+
   /// Returns an interface map containing the interfaces registered to this
   /// operation.
   static detail::InterfaceMap getInterfaceMap() {

diff  --git a/mlir/include/mlir/IR/StorageUniquerSupport.h b/mlir/include/mlir/IR/StorageUniquerSupport.h
index 8cd159e6f0438..6d854f66f6ff7 100644
--- a/mlir/include/mlir/IR/StorageUniquerSupport.h
+++ b/mlir/include/mlir/IR/StorageUniquerSupport.h
@@ -127,6 +127,8 @@ class StorageUserBase : public BaseT, public Traits<ConcreteT>... {
     if (!abstract)
       llvm::report_fatal_error("Registering an interface for an attribute/type "
                                "that is not itself registered.");
+    (void)std::initializer_list<int>{
+        (checkInterfaceTarget<IfaceModels>(), 0)...};
     abstract->interfaceMap.template insert<IfaceModels...>();
   }
 
@@ -182,6 +184,35 @@ class StorageUserBase : public BaseT, public Traits<ConcreteT>... {
 
   /// Utility for easy access to the storage instance.
   ImplType *getImpl() const { return static_cast<ImplType *>(this->impl); }
+
+private:
+  /// Trait to check if T provides a 'ConcreteEntity' type alias.
+  template <typename T>
+  using has_concrete_entity_t = typename T::ConcreteEntity;
+
+  /// A struct-wrapped type alias to T::ConcreteEntity if provided and to
+  /// ConcreteT otherwise. This is akin to std::conditional but doesn't fail on
+  /// the missing typedef. Useful for checking if the interface is targeting the
+  /// right class.
+  template <typename T,
+            bool = llvm::is_detected<has_concrete_entity_t, T>::value>
+  struct IfaceTargetOrConcreteT {
+    using type = typename T::ConcreteEntity;
+  };
+  template <typename T>
+  struct IfaceTargetOrConcreteT<T, false> {
+    using type = ConcreteT;
+  };
+
+  /// A hook for static assertion that the external interface model T is
+  /// targeting a base class of the concrete attribute/type. The model can also
+  /// be a fallback model that works for every attribute/type.
+  template <typename T>
+  static void checkInterfaceTarget() {
+    static_assert(std::is_base_of<typename IfaceTargetOrConcreteT<T>::type,
+                                  ConcreteT>::value,
+                  "attaching an interface to the wrong attribute/type kind");
+  }
 };
 } // namespace detail
 } // namespace mlir

diff  --git a/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp b/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
index 76a5164eba3c8..a6d3cccdd8770 100644
--- a/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
@@ -250,6 +250,7 @@ void InterfaceGenerator::emitModelDecl(const Interface &interface) {
      << ">\n";
   os << "  class ExternalModel : public FallbackModel<ConcreteModel> {\n";
   os << "  public:\n";
+  os << "    using ConcreteEntity = " << valueTemplate << ";\n";
 
   // Emit declarations for methods that have default implementations. Other
   // methods are expected to be implemented by the concrete derived model.


        


More information about the Mlir-commits mailing list