[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