[Mlir-commits] [mlir] [mlir-c] Add mlirOperationIsAncestor and mlirOperationIsProperAncestor (PR #206556)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Sep 23 22:13:03 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Maksim Levental (makslevental)
<details>
<summary>Changes</summary>
Exposes `Operation::isAncestor` and `Operation::isProperAncestor` through the MLIR C API.
Assisted by: Claude
---
Full diff: https://github.com/llvm/llvm-project/pull/206556.diff
3 Files Affected:
- (modified) mlir/include/mlir-c/IR.h (+10)
- (modified) mlir/lib/CAPI/IR/IR.cpp (+8)
- (modified) mlir/test/CAPI/ir.c (+64)
``````````diff
diff --git a/mlir/include/mlir-c/IR.h b/mlir/include/mlir-c/IR.h
index 7e9be93474296..67d0440042d7c 100644
--- a/mlir/include/mlir-c/IR.h
+++ b/mlir/include/mlir-c/IR.h
@@ -725,6 +725,16 @@ MLIR_CAPI_EXPORTED MlirBlock mlirOperationGetBlock(MlirOperation op);
MLIR_CAPI_EXPORTED MlirOperation
mlirOperationGetParentOperation(MlirOperation op);
+/// Returns true if `a` is an ancestor of `b`, i.e. `a` contains `b` or
+/// `a == b`.
+MLIR_CAPI_EXPORTED bool mlirOperationIsAncestor(MlirOperation a,
+ MlirOperation b);
+
+/// Returns true if `a` is a proper ancestor of `b`, i.e. `a` contains `b` but
+/// `a != b`.
+MLIR_CAPI_EXPORTED bool mlirOperationIsProperAncestor(MlirOperation a,
+ MlirOperation b);
+
/// Returns the number of regions attached to the given operation.
MLIR_CAPI_EXPORTED intptr_t mlirOperationGetNumRegions(MlirOperation op);
diff --git a/mlir/lib/CAPI/IR/IR.cpp b/mlir/lib/CAPI/IR/IR.cpp
index fdd4c9e52f9ba..e01e49559eb17 100644
--- a/mlir/lib/CAPI/IR/IR.cpp
+++ b/mlir/lib/CAPI/IR/IR.cpp
@@ -728,6 +728,14 @@ MlirOperation mlirOperationGetParentOperation(MlirOperation op) {
return wrap(unwrap(op)->getParentOp());
}
+bool mlirOperationIsAncestor(MlirOperation a, MlirOperation b) {
+ return unwrap(a)->isAncestor(unwrap(b));
+}
+
+bool mlirOperationIsProperAncestor(MlirOperation a, MlirOperation b) {
+ return unwrap(a)->isProperAncestor(unwrap(b));
+}
+
intptr_t mlirOperationGetNumRegions(MlirOperation op) {
return static_cast<intptr_t>(unwrap(op)->getNumRegions());
}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index c66f00b2b8be1..477d229c555b1 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -3381,6 +3381,68 @@ int testOperationEquivalence(MlirContext ctx) {
return 0;
}
+int testOperationIsAncestor(MlirContext ctx) {
+ fprintf(stderr, "@testOperationIsAncestor\n");
+ // CHECK-LABEL: @testOperationIsAncestor
+
+ mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("arith"));
+
+ const char *moduleStr = "func.func @f() {\n"
+ " %c0 = arith.constant 0 : i32\n"
+ " return\n"
+ "}\n"
+ "func.func @g() {\n"
+ " %c1 = arith.constant 1 : i32\n"
+ " return\n"
+ "}\n";
+ MlirModule module =
+ mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(moduleStr));
+ MlirOperation moduleOp = mlirModuleGetOperation(module);
+ MlirBlock moduleBody = mlirModuleGetBody(module);
+ MlirOperation funcOp = mlirBlockGetFirstOperation(moduleBody);
+ MlirRegion funcRegion = mlirOperationGetRegion(funcOp, 0);
+ MlirBlock funcBody = mlirRegionGetFirstBlock(funcRegion);
+ MlirOperation constOp = mlirBlockGetFirstOperation(funcBody);
+
+ // A sibling func @g, and the constant in its own body, are both unrelated to
+ // @f and @f's constant.
+ MlirOperation otherFuncOp = mlirOperationGetNextInBlock(funcOp);
+ MlirRegion otherFuncRegion = mlirOperationGetRegion(otherFuncOp, 0);
+ MlirBlock otherFuncBody = mlirRegionGetFirstBlock(otherFuncRegion);
+ MlirOperation otherConstOp = mlirBlockGetFirstOperation(otherFuncBody);
+
+ // The module and the func both (properly) contain the constant.
+ assert(mlirOperationIsAncestor(moduleOp, constOp));
+ assert(mlirOperationIsProperAncestor(moduleOp, constOp));
+ assert(mlirOperationIsAncestor(funcOp, constOp));
+ assert(mlirOperationIsProperAncestor(funcOp, constOp));
+
+ // An operation is its own ancestor, but not its own proper ancestor.
+ assert(mlirOperationIsAncestor(constOp, constOp));
+ assert(!mlirOperationIsProperAncestor(constOp, constOp));
+
+ // The containment relation is not symmetric.
+ assert(!mlirOperationIsAncestor(constOp, moduleOp));
+
+ // Operations in disjoint subtrees are genuinely unrelated: neither is an
+ // ancestor of the other, in either direction. The sibling funcs, and the
+ // constants living in their separate bodies, share the module as a common
+ // root but do not contain one another -- so an implementation that merely
+ // tested for a shared root would be caught here.
+ assert(!mlirOperationIsAncestor(funcOp, otherFuncOp));
+ assert(!mlirOperationIsAncestor(otherFuncOp, funcOp));
+ assert(!mlirOperationIsProperAncestor(funcOp, otherFuncOp));
+ assert(!mlirOperationIsAncestor(funcOp, otherConstOp));
+ assert(!mlirOperationIsAncestor(otherConstOp, constOp));
+ assert(!mlirOperationIsAncestor(constOp, otherConstOp));
+
+ mlirModuleDestroy(module);
+
+ // CHECK: testOperationIsAncestor: PASSED
+ fprintf(stderr, "testOperationIsAncestor: PASSED\n");
+ return 0;
+}
+
int main(void) {
MlirContext ctx = mlirContextCreate();
registerAllUpstreamDialects(ctx);
@@ -3441,6 +3503,8 @@ int main(void) {
return 21;
if (testOperationEquivalence(ctx))
return 22;
+ if (testOperationIsAncestor(ctx))
+ return 23;
// CHECK: DESTROY MAIN CONTEXT
// CHECK: reportResourceDelete: resource_i64_blob
``````````
</details>
https://github.com/llvm/llvm-project/pull/206556
More information about the Mlir-commits
mailing list