[Mlir-commits] [mlir] [mlir][ODS] Copy constant generated interface model prototypes (PR #226323)
Mehdi Amini
llvmlistbot at llvm.org
Tue Sep 29 03:34:40 PDT 2026
https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/226323
>From 30c1bf922fc13eaeb2fd93532a64cf106f04c1b9 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Wed, 23 Sep 2026 20:26:17 -0700
Subject: [PATCH] [mlir][ODS] Copy constant generated interface model
prototypes
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. Normal PCH compile CPU is unchanged within noise.
Assisted-by: Codex
---
mlir/include/mlir/Support/InterfaceSupport.h | 28 +++++++++++++++++---
mlir/test/mlir-tblgen/op-interface.td | 5 +++-
mlir/tools/mlir-tblgen/OpInterfacesGen.cpp | 7 ++++-
3 files changed, 35 insertions(+), 5 deletions(-)
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..c13228fef0d16 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, Concept::shared_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