[Mlir-commits] [mlir] 7e19707 - [mlir][ODS] Copy constant generated interface model prototypes (#226323)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Sep 29 06:47:55 PDT 2026


Author: Mehdi Amini
Date: 2026-09-29T13:47:48Z
New Revision: 7e19707aeebbd0ae3101ddc7347fef7a865154f4

URL: https://github.com/llvm/llvm-project/commit/7e19707aeebbd0ae3101ddc7347fef7a865154f4
DIFF: https://github.com/llvm/llvm-project/commit/7e19707aeebbd0ae3101ddc7347fef7a865154f4.diff

LOG: [mlir][ODS] Copy constant generated interface model prototypes (#226323)

Generate constexpr constructors for interface models whose concept is a
table of callbacks. Construct exact generated models from a static
prototype; keep external and fallback models on their existing path.

In OpenMPDialect.cpp this saves about 0.22B compiler instructions and
10.5KB of text.

Assisted-by: Codex

Added: 
    

Modified: 
    mlir/include/mlir/Support/InterfaceSupport.h
    mlir/test/mlir-tblgen/op-interface.td
    mlir/tools/mlir-tblgen/OpInterfacesGen.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Support/InterfaceSupport.h b/mlir/include/mlir/Support/InterfaceSupport.h
index 6f654f1785713..8ab691454f64b 100644
--- a/mlir/include/mlir/Support/InterfaceSupport.h
+++ b/mlir/include/mlir/Support/InterfaceSupport.h
@@ -18,6 +18,8 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/TypeName.h"
 
+#include <type_traits>
+
 namespace mlir {
 namespace detail {
 //===----------------------------------------------------------------------===//
@@ -157,6 +159,16 @@ class InterfaceMap {
   template <typename T>
   using detect_initialize_method = llvm::is_detected<has_initialize_method, T>;
 
+  // Only exact generated models with trivial copy construction can be copied
+  // from a constant prototype. Derived models may carry additional state or
+  // use a custom constructor to configure callbacks.
+  template <typename T, typename = void>
+  struct IsConstexprGeneratedModel : std::false_type {};
+  template <typename T>
+  struct IsConstexprGeneratedModel<T, std::void_t<typename T::GeneratedModel>>
+      : std::bool_constant<std::is_same_v<T, typename T::GeneratedModel> &&
+                           std::is_trivially_copy_constructible_v<T>> {};
+
 public:
   InterfaceMap() = default;
   InterfaceMap(InterfaceMap &&) = default;
@@ -228,9 +240,19 @@ class InterfaceMap {
     // static_assert(std::is_trivially_destructible_v<InterfaceModel>,
     //               "interface models must be trivially destructible");
 
-    // Build the interface model, optionally initializing if necessary.
-    InterfaceModel *model =
-        new (malloc(sizeof(InterfaceModel))) InterfaceModel();
+    // Generated models contain a fixed table of callbacks. Copy a constant
+    // prototype so the callbacks need not be set up for each model.
+    InterfaceModel *model;
+    if constexpr (IsConstexprGeneratedModel<InterfaceModel>::value) {
+      static constexpr InterfaceModel prototype;
+      model = new (malloc(sizeof(InterfaceModel))) InterfaceModel(prototype);
+    } else {
+      // Construct fallback, external, and custom models normally; they may
+      // need more than a copy of the generated callback table.
+      model = new (malloc(sizeof(InterfaceModel))) InterfaceModel();
+    }
+    // Run model-specific initialization after either path, including links to
+    // registered base interfaces.
     if constexpr (detect_initialize_method<InterfaceModel>::value)
       model->initializeInterfaceConcept(*this);
 

diff  --git a/mlir/test/mlir-tblgen/op-interface.td b/mlir/test/mlir-tblgen/op-interface.td
index b156fe195a7ed..e12ede40e029a 100644
--- a/mlir/test/mlir-tblgen/op-interface.td
+++ b/mlir/test/mlir-tblgen/op-interface.td
@@ -184,9 +184,12 @@ def DeclareMethodsWithDefaultOp : Op<TestDialect, "declare_methods_op",
 // DECL-LABEL: TestOpInterfaceInterfaceTraits
 // DECL: static int shared_shared_body_foo(const Concept *impl, ::mlir::Operation *tablegen_opaque_val, int input);
 // DECL: class Model : public Concept
-// DECL: Model() : Concept{foo, body_foo, Concept::shared_shared_body_foo, mixed_body_foo, default_foo}
+// DECL: using GeneratedModel = Model;
+// DECL: constexpr Model() : Concept{foo, body_foo, Concept::shared_shared_body_foo, mixed_body_foo, default_foo}
 // DECL: static inline int foo(
 // DECL: class FallbackModel : public Concept
+// DECL-NOT: using GeneratedModel = Model;
+// DECL: FallbackModel() : Concept{foo, body_foo, shared_body_foo, mixed_body_foo, default_foo}
 // DECL: static inline int foo(
 // DECL: class TestOpInterface : public ::mlir::OpInterface<TestOpInterface, detail::TestOpInterfaceInterfaceTraits>
 

diff  --git a/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp b/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
index 764357720ddab..3f62969312de8 100644
--- a/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
@@ -316,11 +316,16 @@ void InterfaceGenerator::emitModelDecl(const Interface &interface) {
     os << "  class " << modelClass << " : public Concept {\n  public:\n";
     os << "    using Interface = " << interface.getFullyQualifiedName()
        << ";\n";
+    if (StringRef(modelClass) == "Model")
+      os << "    using GeneratedModel = Model;\n";
     // The Concept's function-pointer members and these wrapper signatures are
     // named by the unique name so that overloaded interface methods stay
     // distinct here; only the forward target (the concrete model call) uses the
     // shared source name. Do not collapse these to getName().
-    os << "    " << modelClass << "() : Concept{";
+    os << "    ";
+    if (StringRef(modelClass) == "Model")
+      os << "constexpr ";
+    os << modelClass << "() : Concept{";
     llvm::interleaveComma(
         interface.getMethods(), os, [&](const InterfaceMethod &method) {
           if (StringRef(modelClass) == "Model" &&


        


More information about the Mlir-commits mailing list