[Mlir-commits] [mlir] [mlir-c] Add IRMapping C API bindings (PR #206146)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Jun 26 11:56:04 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Maksim Levental (makslevental)

<details>
<summary>Changes</summary>

Expose IRMapping through the MLIR C API with full create/destroy/map, lookup, contains/erase, and clone-with-mapping functionality.

Assisted by: Claude

---
Full diff: https://github.com/llvm/llvm-project/pull/206146.diff


7 Files Affected:

- (modified) mlir/include/mlir-c/IR.h (+89) 
- (modified) mlir/include/mlir-c/Rewrite.h (+5) 
- (added) mlir/include/mlir/CAPI/IRMapping.h (+18) 
- (modified) mlir/lib/CAPI/IR/IR.cpp (+85) 
- (modified) mlir/lib/CAPI/Transforms/Rewrite.cpp (+7) 
- (modified) mlir/test/CAPI/ir.c (+117) 
- (modified) mlir/test/CAPI/rewrite.c (+43) 


``````````diff
diff --git a/mlir/include/mlir-c/IR.h b/mlir/include/mlir-c/IR.h
index fdff79f8b67dd..311234e42df60 100644
--- a/mlir/include/mlir-c/IR.h
+++ b/mlir/include/mlir-c/IR.h
@@ -59,6 +59,7 @@ DEFINE_C_API_STRUCT(MlirOpPrintingFlags, void);
 DEFINE_C_API_STRUCT(MlirBlock, void);
 DEFINE_C_API_STRUCT(MlirRegion, void);
 DEFINE_C_API_STRUCT(MlirSymbolTable, void);
+DEFINE_C_API_STRUCT(MlirIRMapping, void);
 
 DEFINE_C_API_STRUCT(MlirAttribute, const void);
 DEFINE_C_API_STRUCT(MlirIdentifier, const void);
@@ -1302,6 +1303,94 @@ MLIR_CAPI_EXPORTED void mlirSymbolTableWalkSymbolTables(
     MlirOperation from, bool allSymUsesVisible,
     void (*callback)(MlirOperation, bool, void *userData), void *userData);
 
+//===----------------------------------------------------------------------===//
+// IRMapping API
+//===----------------------------------------------------------------------===//
+
+/// Creates a new empty IRMapping.
+MLIR_CAPI_EXPORTED MlirIRMapping mlirIRMappingCreate(void);
+
+/// Destroys the given IRMapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingDestroy(MlirIRMapping mapping);
+
+/// Checks whether an IRMapping is null.
+static inline bool mlirIRMappingIsNull(MlirIRMapping mapping) {
+  return !mapping.ptr;
+}
+
+/// Maps a Value in the mapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingMapValue(MlirIRMapping mapping,
+                                              MlirValue from, MlirValue to);
+
+/// Maps a Block in the mapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingMapBlock(MlirIRMapping mapping,
+                                              MlirBlock from, MlirBlock to);
+
+/// Maps an Operation in the mapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingMapOperation(MlirIRMapping mapping,
+                                                  MlirOperation from,
+                                                  MlirOperation to);
+
+/// Clears all mappings.
+MLIR_CAPI_EXPORTED void mlirIRMappingClear(MlirIRMapping mapping);
+
+/// Looks up a mapped Value. Returns the mapped value, or the input value if
+/// no mapping exists.
+MLIR_CAPI_EXPORTED MlirValue
+mlirIRMappingLookupOrDefaultValue(MlirIRMapping mapping, MlirValue from);
+
+/// Looks up a mapped Value. Returns a null MlirValue if no mapping exists.
+MLIR_CAPI_EXPORTED MlirValue
+mlirIRMappingLookupOrNullValue(MlirIRMapping mapping, MlirValue from);
+
+/// Looks up a mapped Block. Returns the mapped block, or the input block if
+/// no mapping exists.
+MLIR_CAPI_EXPORTED MlirBlock
+mlirIRMappingLookupOrDefaultBlock(MlirIRMapping mapping, MlirBlock from);
+
+/// Looks up a mapped Block. Returns a null MlirBlock if no mapping exists.
+MLIR_CAPI_EXPORTED MlirBlock
+mlirIRMappingLookupOrNullBlock(MlirIRMapping mapping, MlirBlock from);
+
+/// Looks up a mapped Operation. Returns the mapped operation, or the input
+/// operation if no mapping exists.
+MLIR_CAPI_EXPORTED MlirOperation mlirIRMappingLookupOrDefaultOperation(
+    MlirIRMapping mapping, MlirOperation from);
+
+/// Looks up a mapped Operation. Returns a null MlirOperation if no mapping
+/// exists.
+MLIR_CAPI_EXPORTED MlirOperation
+mlirIRMappingLookupOrNullOperation(MlirIRMapping mapping, MlirOperation from);
+
+/// Returns true if the mapping contains a mapping for the given value.
+MLIR_CAPI_EXPORTED bool mlirIRMappingContainsValue(MlirIRMapping mapping,
+                                                   MlirValue value);
+
+/// Returns true if the mapping contains a mapping for the given block.
+MLIR_CAPI_EXPORTED bool mlirIRMappingContainsBlock(MlirIRMapping mapping,
+                                                   MlirBlock block);
+
+/// Returns true if the mapping contains a mapping for the given operation.
+MLIR_CAPI_EXPORTED bool mlirIRMappingContainsOperation(MlirIRMapping mapping,
+                                                       MlirOperation op);
+
+/// Erases a value mapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingEraseValue(MlirIRMapping mapping,
+                                                MlirValue value);
+
+/// Erases a block mapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingEraseBlock(MlirIRMapping mapping,
+                                                MlirBlock block);
+
+/// Erases an operation mapping.
+MLIR_CAPI_EXPORTED void mlirIRMappingEraseOperation(MlirIRMapping mapping,
+                                                    MlirOperation op);
+
+/// Clones the operation with the given mapping. The mapping is updated with
+/// the cloned operation's results and regions.
+MLIR_CAPI_EXPORTED MlirOperation
+mlirOperationCloneWithMapping(MlirOperation op, MlirIRMapping mapping);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/mlir/include/mlir-c/Rewrite.h b/mlir/include/mlir-c/Rewrite.h
index 2e12f9cabbddd..ac243a4c9d8f9 100644
--- a/mlir/include/mlir-c/Rewrite.h
+++ b/mlir/include/mlir-c/Rewrite.h
@@ -161,6 +161,11 @@ mlirRewriterBaseClone(MlirRewriterBase rewriter, MlirOperation op);
 MLIR_CAPI_EXPORTED MlirOperation mlirRewriterBaseCloneWithoutRegions(
     MlirRewriterBase rewriter, MlirOperation op);
 
+/// Clones the given operation using the rewriter and the provided IRMapping.
+/// The mapping is updated with the results of the cloned operation.
+MLIR_CAPI_EXPORTED MlirOperation mlirRewriterBaseCloneWithMapping(
+    MlirRewriterBase rewriter, MlirOperation op, MlirIRMapping mapping);
+
 /// Clone the blocks that belong to "region" before the given position in
 /// another region "parent".
 MLIR_CAPI_EXPORTED void
diff --git a/mlir/include/mlir/CAPI/IRMapping.h b/mlir/include/mlir/CAPI/IRMapping.h
new file mode 100644
index 0000000000000..dc0a76490d8a6
--- /dev/null
+++ b/mlir/include/mlir/CAPI/IRMapping.h
@@ -0,0 +1,18 @@
+//===- IRMapping.h - C API wrap/unwrap for IRMapping -------------*- C++ -*===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CAPI_IRMAPPING_H
+#define MLIR_CAPI_IRMAPPING_H
+
+#include "mlir-c/IR.h"
+#include "mlir/CAPI/Wrap.h"
+#include "mlir/IR/IRMapping.h"
+
+DEFINE_C_API_PTR_METHODS(MlirIRMapping, mlir::IRMapping)
+
+#endif // MLIR_CAPI_IRMAPPING_H
diff --git a/mlir/lib/CAPI/IR/IR.cpp b/mlir/lib/CAPI/IR/IR.cpp
index 28ca830270366..94442e2be19a4 100644
--- a/mlir/lib/CAPI/IR/IR.cpp
+++ b/mlir/lib/CAPI/IR/IR.cpp
@@ -12,6 +12,7 @@
 #include "mlir/AsmParser/AsmParser.h"
 #include "mlir/Bytecode/BytecodeWriter.h"
 #include "mlir/CAPI/IR.h"
+#include "mlir/CAPI/IRMapping.h"
 #include "mlir/CAPI/Support.h"
 #include "mlir/CAPI/Utils.h"
 #include "mlir/IR/Attributes.h"
@@ -1409,3 +1410,87 @@ void mlirSymbolTableWalkSymbolTables(MlirOperation from, bool allSymUsesVisible,
                                            userData);
                                 });
 }
+
+//===----------------------------------------------------------------------===//
+// IRMapping API
+//===----------------------------------------------------------------------===//
+
+MlirIRMapping mlirIRMappingCreate(void) { return wrap(new IRMapping()); }
+
+void mlirIRMappingDestroy(MlirIRMapping mapping) { delete unwrap(mapping); }
+
+void mlirIRMappingMapValue(MlirIRMapping mapping, MlirValue from,
+                           MlirValue to) {
+  unwrap(mapping)->map(unwrap(from), unwrap(to));
+}
+
+void mlirIRMappingMapBlock(MlirIRMapping mapping, MlirBlock from,
+                           MlirBlock to) {
+  unwrap(mapping)->map(unwrap(from), unwrap(to));
+}
+
+void mlirIRMappingMapOperation(MlirIRMapping mapping, MlirOperation from,
+                               MlirOperation to) {
+  unwrap(mapping)->map(unwrap(from), unwrap(to));
+}
+
+void mlirIRMappingClear(MlirIRMapping mapping) { unwrap(mapping)->clear(); }
+
+MlirValue mlirIRMappingLookupOrDefaultValue(MlirIRMapping mapping,
+                                            MlirValue from) {
+  return wrap(unwrap(mapping)->lookupOrDefault(unwrap(from)));
+}
+
+MlirValue mlirIRMappingLookupOrNullValue(MlirIRMapping mapping,
+                                         MlirValue from) {
+  return wrap(unwrap(mapping)->lookupOrNull(unwrap(from)));
+}
+
+MlirBlock mlirIRMappingLookupOrDefaultBlock(MlirIRMapping mapping,
+                                            MlirBlock from) {
+  return wrap(unwrap(mapping)->lookupOrDefault(unwrap(from)));
+}
+
+MlirBlock mlirIRMappingLookupOrNullBlock(MlirIRMapping mapping,
+                                         MlirBlock from) {
+  return wrap(unwrap(mapping)->lookupOrNull(unwrap(from)));
+}
+
+MlirOperation mlirIRMappingLookupOrDefaultOperation(MlirIRMapping mapping,
+                                                    MlirOperation from) {
+  return wrap(unwrap(mapping)->lookupOrDefault(unwrap(from)));
+}
+
+MlirOperation mlirIRMappingLookupOrNullOperation(MlirIRMapping mapping,
+                                                 MlirOperation from) {
+  return wrap(unwrap(mapping)->lookupOrNull(unwrap(from)));
+}
+
+bool mlirIRMappingContainsValue(MlirIRMapping mapping, MlirValue value) {
+  return unwrap(mapping)->contains(unwrap(value));
+}
+
+bool mlirIRMappingContainsBlock(MlirIRMapping mapping, MlirBlock block) {
+  return unwrap(mapping)->contains(unwrap(block));
+}
+
+bool mlirIRMappingContainsOperation(MlirIRMapping mapping, MlirOperation op) {
+  return unwrap(mapping)->contains(unwrap(op));
+}
+
+void mlirIRMappingEraseValue(MlirIRMapping mapping, MlirValue value) {
+  unwrap(mapping)->erase(unwrap(value));
+}
+
+void mlirIRMappingEraseBlock(MlirIRMapping mapping, MlirBlock block) {
+  unwrap(mapping)->erase(unwrap(block));
+}
+
+void mlirIRMappingEraseOperation(MlirIRMapping mapping, MlirOperation op) {
+  unwrap(mapping)->erase(unwrap(op));
+}
+
+MlirOperation mlirOperationCloneWithMapping(MlirOperation op,
+                                            MlirIRMapping mapping) {
+  return wrap(unwrap(op)->clone(*unwrap(mapping)));
+}
diff --git a/mlir/lib/CAPI/Transforms/Rewrite.cpp b/mlir/lib/CAPI/Transforms/Rewrite.cpp
index 4f75cc758bc48..56ce9212f4811 100644
--- a/mlir/lib/CAPI/Transforms/Rewrite.cpp
+++ b/mlir/lib/CAPI/Transforms/Rewrite.cpp
@@ -11,6 +11,7 @@
 #include "mlir-c/Support.h"
 #include "mlir-c/Transforms.h"
 #include "mlir/CAPI/IR.h"
+#include "mlir/CAPI/IRMapping.h"
 #include "mlir/CAPI/Rewrite.h"
 #include "mlir/CAPI/Support.h"
 #include "mlir/CAPI/Wrap.h"
@@ -118,6 +119,12 @@ MlirOperation mlirRewriterBaseCloneWithoutRegions(MlirRewriterBase rewriter,
   return wrap(unwrap(rewriter)->cloneWithoutRegions(*unwrap(op)));
 }
 
+MlirOperation mlirRewriterBaseCloneWithMapping(MlirRewriterBase rewriter,
+                                               MlirOperation op,
+                                               MlirIRMapping mapping) {
+  return wrap(unwrap(rewriter)->clone(*unwrap(op), *unwrap(mapping)));
+}
+
 void mlirRewriterBaseCloneRegionBefore(MlirRewriterBase rewriter,
                                        MlirRegion region, MlirBlock before) {
 
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index ec0a877f830dd..6b7c10385343c 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -2623,6 +2623,121 @@ int testInterfaces(MlirContext ctx) {
   return 0;
 }
 
+int testIRMapping(MlirContext ctx) {
+  fprintf(stderr, "@testIRMapping\n");
+  // CHECK-LABEL: @testIRMapping
+
+  mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("arith"));
+
+  MlirIRMapping mapping = mlirIRMappingCreate();
+  assert(!mlirIRMappingIsNull(mapping));
+
+  const char *moduleStr = "func.func @f(%arg0: i32, %arg1: i32) -> i32 {\n"
+                          "  %0 = arith.addi %arg0, %arg1 : i32\n"
+                          "  return %0 : i32\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 arg0 = mlirBlockGetArgument(funcBody, 0);
+  MlirValue arg1 = mlirBlockGetArgument(funcBody, 1);
+  MlirOperation addOp = mlirBlockGetFirstOperation(funcBody);
+  MlirValue addResult = mlirOperationGetResult(addOp, 0);
+
+  // --- Task 1: Map ---
+
+  mlirIRMappingMapValue(mapping, arg0, addResult);
+  mlirIRMappingMapBlock(mapping, funcBody, funcBody);
+  mlirIRMappingMapOperation(mapping, addOp, addOp);
+
+  // --- Task 2: Lookup ---
+
+  // Value lookup: mapped
+  MlirValue looked = mlirIRMappingLookupOrDefaultValue(mapping, arg0);
+  assert(mlirValueEqual(looked, addResult));
+
+  // Value lookup: unmapped returns default (the input itself)
+  MlirValue defaulted = mlirIRMappingLookupOrDefaultValue(mapping, arg1);
+  assert(mlirValueEqual(defaulted, arg1));
+
+  // Value lookup: unmapped returns null
+  MlirValue nullVal = mlirIRMappingLookupOrNullValue(mapping, arg1);
+  assert(mlirValueIsNull(nullVal));
+
+  // Block lookup: mapped
+  MlirBlock lookedBlock = mlirIRMappingLookupOrDefaultBlock(mapping, funcBody);
+  assert(mlirBlockEqual(lookedBlock, funcBody));
+
+  // Operation lookup: mapped
+  MlirOperation lookedOp =
+      mlirIRMappingLookupOrDefaultOperation(mapping, addOp);
+  assert(mlirOperationEqual(lookedOp, addOp));
+
+  // --- Task 3: Contains and Erase ---
+
+  assert(mlirIRMappingContainsValue(mapping, arg0));
+  assert(mlirIRMappingContainsBlock(mapping, funcBody));
+  assert(mlirIRMappingContainsOperation(mapping, addOp));
+  assert(!mlirIRMappingContainsValue(mapping, arg1));
+
+  // Erase value
+  mlirIRMappingEraseValue(mapping, arg0);
+  assert(!mlirIRMappingContainsValue(mapping, arg0));
+  assert(mlirIRMappingContainsBlock(mapping, funcBody));
+
+  // Erase block
+  mlirIRMappingEraseBlock(mapping, funcBody);
+  assert(!mlirIRMappingContainsBlock(mapping, funcBody));
+
+  // Erase operation
+  mlirIRMappingEraseOperation(mapping, addOp);
+  assert(!mlirIRMappingContainsOperation(mapping, addOp));
+
+  // Block lookup: unmapped returns null
+  MlirBlock nullBlock = mlirIRMappingLookupOrNullBlock(mapping, funcBody);
+  assert(mlirBlockIsNull(nullBlock));
+
+  // Operation lookup: unmapped returns null
+  MlirOperation nullOp = mlirIRMappingLookupOrNullOperation(mapping, addOp);
+  assert(mlirOperationIsNull(nullOp));
+
+  // Clear
+  mlirIRMappingMapValue(mapping, arg0, addResult);
+  mlirIRMappingClear(mapping);
+  assert(!mlirIRMappingContainsValue(mapping, arg0));
+
+  // --- Task 4: Clone with mapping ---
+
+  MlirIRMapping cloneMapping = mlirIRMappingCreate();
+  mlirIRMappingMapValue(cloneMapping, arg0, arg1);
+  mlirIRMappingMapValue(cloneMapping, arg1, arg0);
+
+  MlirOperation cloned = mlirOperationCloneWithMapping(addOp, cloneMapping);
+  assert(!mlirOperationIsNull(cloned));
+
+  // The cloned op should have its operands remapped
+  MlirValue clonedOp0 = mlirOperationGetOperand(cloned, 0);
+  MlirValue clonedOp1 = mlirOperationGetOperand(cloned, 1);
+  assert(mlirValueEqual(clonedOp0, arg1));
+  assert(mlirValueEqual(clonedOp1, arg0));
+
+  // The mapping should now contain the cloned result
+  assert(mlirIRMappingContainsValue(cloneMapping, addResult));
+
+  mlirOperationDestroy(cloned);
+  mlirIRMappingDestroy(cloneMapping);
+  mlirIRMappingDestroy(mapping);
+  mlirModuleDestroy(module);
+
+  // CHECK: testIRMapping: PASSED
+  fprintf(stderr, "testIRMapping: PASSED\n");
+  return 0;
+}
+
 int main(void) {
   MlirContext ctx = mlirContextCreate();
   registerAllUpstreamDialects(ctx);
@@ -2674,6 +2789,8 @@ int main(void) {
     return 17;
   if (testInterfaces(ctx))
     return 18;
+  if (testIRMapping(ctx))
+    return 19;
 
   // CHECK: DESTROY MAIN CONTEXT
   // CHECK: reportResourceDelete: resource_i64_blob
diff --git a/mlir/test/CAPI/rewrite.c b/mlir/test/CAPI/rewrite.c
index 48d70579fa325..3809dd6a7843f 100644
--- a/mlir/test/CAPI/rewrite.c
+++ b/mlir/test/CAPI/rewrite.c
@@ -581,6 +581,48 @@ void testGreedyRewriteDriverConfig(MlirContext ctx) {
   mlirGreedyRewriteDriverConfigDestroy(config);
 }
 
+void testCloneWithMapping(MlirContext ctx) {
+  // CHECK-LABEL: @testCloneWithMapping
+  fprintf(stderr, "@testCloneWithMapping\n");
+
+  const char *moduleString =
+      "%x, %y = \"dialect.create_values\"() : () -> (index, index)\n"
+      "%sum = \"dialect.add\"(%x, %y) : (index, index) -> index\n";
+  MlirModule module =
+      mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(moduleString));
+  MlirBlock body = mlirModuleGetBody(module);
+
+  MlirOperation createValues = mlirBlockGetFirstOperation(body);
+  MlirValue x = mlirOperationGetResult(createValues, 0);
+  MlirValue y = mlirOperationGetResult(createValues, 1);
+  MlirOperation addOp = mlirOperationGetNextInBlock(createValues);
+
+  MlirRewriterBase rewriter = mlirIRRewriterCreate(ctx);
+  mlirRewriterBaseSetInsertionPointAfter(rewriter, addOp);
+
+  // Clone addOp with a mapping that swaps x -> y, y -> x
+  MlirIRMapping mapping = mlirIRMappingCreate();
+  mlirIRMappingMapValue(mapping, x, y);
+  mlirIRMappingMapValue(mapping, y, x);
+
+  MlirOperation cloned =
+      mlirRewriterBaseCloneWithMapping(rewriter, addOp, mapping);
+  assert(!mlirOperationIsNull(cloned));
+
+  // Verify operands are remapped
+  MlirValue clonedOp0 = mlirOperationGetOperand(cloned, 0);
+  MlirValue clonedOp1 = mlirOperationGetOperand(cloned, 1);
+  assert(mlirValueEqual(clonedOp0, y));
+  assert(mlirValueEqual(clonedOp1, x));
+
+  mlirIRMappingDestroy(mapping);
+  mlirIRRewriterDestroy(rewriter);
+  mlirModuleDestroy(module);
+
+  // CHECK: testCloneWithMapping: PASSED
+  fprintf(stderr, "testCloneWithMapping: PASSED\n");
+}
+
 int main(void) {
   MlirContext ctx = mlirContextCreate();
   mlirContextSetAllowUnregisteredDialects(ctx, true);
@@ -595,6 +637,7 @@ int main(void) {
   testOpModification(ctx);
   testReplaceUses(ctx);
   testGreedyRewriteDriverConfig(ctx);
+  testCloneWithMapping(ctx);
 
   mlirContextDestroy(ctx);
   return 0;

``````````

</details>


https://github.com/llvm/llvm-project/pull/206146


More information about the Mlir-commits mailing list