[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