[Mlir-commits] [mlir] [mlir-c] Add DestinationStyleOpInterface C API bindings (PR #206561)

Maksim Levental llvmlistbot at llvm.org
Mon Jun 29 11:51:51 PDT 2026


https://github.com/makslevental updated https://github.com/llvm/llvm-project/pull/206561

>From c5c2ce7256e041185531f866970f7061bf67ad50 Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Mon, 29 Jun 2026 11:34:10 -0700
Subject: [PATCH] [mlir-c] Add DestinationStyleOpInterface C API bindings

---
 mlir/include/mlir-c/Interfaces.h        | 40 +++++++++++++++++
 mlir/lib/CAPI/Interfaces/CMakeLists.txt |  1 +
 mlir/lib/CAPI/Interfaces/Interfaces.cpp | 42 ++++++++++++++++++
 mlir/test/CAPI/ir.c                     | 58 +++++++++++++++++++++++++
 4 files changed, 141 insertions(+)

diff --git a/mlir/include/mlir-c/Interfaces.h b/mlir/include/mlir-c/Interfaces.h
index a5251dc78471f..f7cd57b7d7462 100644
--- a/mlir/include/mlir-c/Interfaces.h
+++ b/mlir/include/mlir-c/Interfaces.h
@@ -165,6 +165,46 @@ MLIR_CAPI_EXPORTED void mlirMemoryEffectsOpInterfaceAttachFallbackModel(
     MlirContext ctx, MlirStringRef opName,
     MlirMemoryEffectsOpInterfaceCallbacks callbacks);
 
+//===---------------------------------------------------------------------===//
+// DestinationStyleOpInterface
+//===---------------------------------------------------------------------===//
+
+/// Returns the interface TypeID of the DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED MlirTypeID mlirDestinationStyleOpInterfaceTypeID(void);
+
+/// Returns the number of "init" (destination) operands of the given
+/// destination-style operation. The operation must implement
+/// DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED intptr_t
+mlirDestinationStyleOpInterfaceGetNumDpsInits(MlirOperation op);
+
+/// Returns the `i`-th "init" operand as an OpOperand. The operation must
+/// implement DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED MlirOpOperand
+mlirDestinationStyleOpInterfaceGetDpsInitOperand(MlirOperation op, intptr_t i);
+
+/// Returns the number of "input" operands of the given destination-style
+/// operation. The operation must implement DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED intptr_t
+mlirDestinationStyleOpInterfaceGetNumDpsInputs(MlirOperation op);
+
+/// Returns the `i`-th "input" operand as an OpOperand. The operation must
+/// implement DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED MlirOpOperand
+mlirDestinationStyleOpInterfaceGetDpsInputOperand(MlirOperation op, intptr_t i);
+
+/// Returns true if the given OpOperand is an "input" of the operation. The
+/// operation must implement DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED bool
+mlirDestinationStyleOpInterfaceIsDpsInput(MlirOperation op,
+                                          MlirOpOperand operand);
+
+/// Returns true if the given OpOperand is an "init" of the operation. The
+/// operation must implement DestinationStyleOpInterface.
+MLIR_CAPI_EXPORTED bool
+mlirDestinationStyleOpInterfaceIsDpsInit(MlirOperation op,
+                                         MlirOpOperand operand);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/mlir/lib/CAPI/Interfaces/CMakeLists.txt b/mlir/lib/CAPI/Interfaces/CMakeLists.txt
index dbe3f33975980..3aa3edad26e5b 100644
--- a/mlir/lib/CAPI/Interfaces/CMakeLists.txt
+++ b/mlir/lib/CAPI/Interfaces/CMakeLists.txt
@@ -2,5 +2,6 @@ add_mlir_upstream_c_api_library(MLIRCAPIInterfaces
   Interfaces.cpp
 
   LINK_LIBS PUBLIC
+  MLIRDestinationStyleOpInterface
   MLIRInferTypeOpInterface
   MLIRSideEffectInterfaces)
diff --git a/mlir/lib/CAPI/Interfaces/Interfaces.cpp b/mlir/lib/CAPI/Interfaces/Interfaces.cpp
index 35a2bd562a8a1..4878ad79f7123 100644
--- a/mlir/lib/CAPI/Interfaces/Interfaces.cpp
+++ b/mlir/lib/CAPI/Interfaces/Interfaces.cpp
@@ -15,6 +15,7 @@
 #include "mlir/CAPI/Support.h"
 #include "mlir/CAPI/Wrap.h"
 #include "mlir/IR/ValueRange.h"
+#include "mlir/Interfaces/DestinationStyleOpInterface.h"
 #include "mlir/Interfaces/InferTypeOpInterface.h"
 #include "llvm/ADT/ScopeExit.h"
 #include <optional>
@@ -345,3 +346,44 @@ void mlirMemoryEffectsOpInterfaceAttachFallbackModel(
   assert(model && "Failed to get MemoryEffectOpInterfaceFallbackModel");
   model->setCallbacks(callbacks);
 }
+
+//===---------------------------------------------------------------------===//
+// DestinationStyleOpInterface
+//===---------------------------------------------------------------------===//
+
+MlirTypeID mlirDestinationStyleOpInterfaceTypeID(void) {
+  return wrap(DestinationStyleOpInterface::getInterfaceID());
+}
+
+intptr_t mlirDestinationStyleOpInterfaceGetNumDpsInits(MlirOperation op) {
+  return cast<DestinationStyleOpInterface>(unwrap(op)).getNumDpsInits();
+}
+
+MlirOpOperand mlirDestinationStyleOpInterfaceGetDpsInitOperand(MlirOperation op,
+                                                               intptr_t i) {
+  return wrap(
+      cast<DestinationStyleOpInterface>(unwrap(op)).getDpsInitOperand(i));
+}
+
+intptr_t mlirDestinationStyleOpInterfaceGetNumDpsInputs(MlirOperation op) {
+  return cast<DestinationStyleOpInterface>(unwrap(op)).getNumDpsInputs();
+}
+
+MlirOpOperand
+mlirDestinationStyleOpInterfaceGetDpsInputOperand(MlirOperation op,
+                                                  intptr_t i) {
+  return wrap(
+      cast<DestinationStyleOpInterface>(unwrap(op)).getDpsInputOperand(i));
+}
+
+bool mlirDestinationStyleOpInterfaceIsDpsInput(MlirOperation op,
+                                               MlirOpOperand operand) {
+  return cast<DestinationStyleOpInterface>(unwrap(op))
+      .isDpsInput(unwrap(operand));
+}
+
+bool mlirDestinationStyleOpInterfaceIsDpsInit(MlirOperation op,
+                                              MlirOpOperand operand) {
+  return cast<DestinationStyleOpInterface>(unwrap(op))
+      .isDpsInit(unwrap(operand));
+}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index 57ae8b9a2819b..498d92b07e784 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -2900,6 +2900,62 @@ int testDominanceInfo(MlirContext ctx) {
   return 0;
 }
 
+int testDestinationStyleOpInterface(MlirContext ctx) {
+  fprintf(stderr, "@testDestinationStyleOpInterface\n");
+  // CHECK-LABEL: @testDestinationStyleOpInterface
+
+  mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("linalg"));
+
+  // linalg.fill is a destination-style op: `ins(%val)` is the input operand
+  // (operand 0) and `outs(%init)` is the init/destination operand (operand 1).
+  const char *moduleStr =
+      "func.func @f(%val: f32, %init: tensor<4xf32>) -> tensor<4xf32> {\n"
+      "  %0 = linalg.fill ins(%val : f32) outs(%init : tensor<4xf32>) -> "
+      "tensor<4xf32>\n"
+      "  return %0 : tensor<4xf32>\n"
+      "}\n";
+  MlirModule module =
+      mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(moduleStr));
+
+  MlirBlock moduleBody = mlirModuleGetBody(module);
+  MlirOperation funcOp = mlirBlockGetFirstOperation(moduleBody);
+  MlirRegion funcRegion = mlirOperationGetRegion(funcOp, 0);
+  MlirBlock funcBody = mlirRegionGetFirstBlock(funcRegion);
+  MlirValue initArg = mlirBlockGetArgument(funcBody, 1);
+  MlirOperation fillOp = mlirBlockGetFirstOperation(funcBody);
+
+  // The linalg.fill op implements the interface.
+  MlirTypeID id = mlirDestinationStyleOpInterfaceTypeID();
+  assert(!mlirTypeIDIsNull(id));
+  assert(mlirOperationImplementsInterface(fillOp, id));
+
+  // One input, one init.
+  assert(mlirDestinationStyleOpInterfaceGetNumDpsInputs(fillOp) == 1);
+  assert(mlirDestinationStyleOpInterfaceGetNumDpsInits(fillOp) == 1);
+
+  MlirOpOperand inputOperand =
+      mlirDestinationStyleOpInterfaceGetDpsInputOperand(fillOp, 0);
+  MlirOpOperand initOperand =
+      mlirDestinationStyleOpInterfaceGetDpsInitOperand(fillOp, 0);
+
+  // Classification of operands as input vs. init.
+  assert(mlirDestinationStyleOpInterfaceIsDpsInput(fillOp, inputOperand));
+  assert(mlirDestinationStyleOpInterfaceIsDpsInit(fillOp, initOperand));
+  assert(!mlirDestinationStyleOpInterfaceIsDpsInput(fillOp, initOperand));
+  assert(!mlirDestinationStyleOpInterfaceIsDpsInit(fillOp, inputOperand));
+
+  // The input is operand 0; the init is operand 1 and matches the %init arg.
+  assert(mlirOpOperandGetOperandNumber(inputOperand) == 0);
+  assert(mlirOpOperandGetOperandNumber(initOperand) == 1);
+  assert(mlirValueEqual(mlirOpOperandGetValue(initOperand), initArg));
+
+  mlirModuleDestroy(module);
+
+  // CHECK: testDestinationStyleOpInterface: PASSED
+  fprintf(stderr, "testDestinationStyleOpInterface: PASSED\n");
+  return 0;
+}
+
 int main(void) {
   MlirContext ctx = mlirContextCreate();
   registerAllUpstreamDialects(ctx);
@@ -2955,6 +3011,8 @@ int main(void) {
     return 19;
   if (testDominanceInfo(ctx))
     return 20;
+  if (testDestinationStyleOpInterface(ctx))
+    return 21;
 
   // CHECK: DESTROY MAIN CONTEXT
   // CHECK: reportResourceDelete: resource_i64_blob



More information about the Mlir-commits mailing list