[Mlir-commits] [mlir] [mlir-c] Add slice analysis and topological sort (PR #206550)
Maksim Levental
llvmlistbot at llvm.org
Tue Sep 22 16:53:27 PDT 2026
https://github.com/makslevental updated https://github.com/llvm/llvm-project/pull/206550
>From 0c8140997dd0f5f81fbe08ce62f10d8b4ba95dc9 Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Mon, 29 Jun 2026 10:58:28 -0700
Subject: [PATCH 1/3] [mlir-c] Add forward slice analysis
---
mlir/include/mlir-c/Analysis.h | 51 ++++++++++++++++++++++
mlir/lib/CAPI/IR/Analysis.cpp | 43 +++++++++++++++++++
mlir/lib/CAPI/IR/CMakeLists.txt | 2 +
mlir/test/CAPI/ir.c | 75 +++++++++++++++++++++++++++++++++
4 files changed, 171 insertions(+)
create mode 100644 mlir/include/mlir-c/Analysis.h
create mode 100644 mlir/lib/CAPI/IR/Analysis.cpp
diff --git a/mlir/include/mlir-c/Analysis.h b/mlir/include/mlir-c/Analysis.h
new file mode 100644
index 00000000000000..f07fdde3208d22
--- /dev/null
+++ b/mlir/include/mlir-c/Analysis.h
@@ -0,0 +1,51 @@
+//===- Analysis.h - C API for MLIR Analysis Utilities -------------*- 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_C_ANALYSIS_H
+#define MLIR_C_ANALYSIS_H
+
+#include "mlir-c/IR.h"
+#include "mlir-c/Support.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//===----------------------------------------------------------------------===//
+// Slice analysis
+//===----------------------------------------------------------------------===//
+
+/// Filter callback for slice analysis, corresponding to
+/// `mlir::SliceOptions::filter`. Return true to keep traversing through the
+/// given operation, false to treat it as a frontier and stop propagation.
+typedef bool (*MlirSliceFilterCallback)(MlirOperation op, void *userData);
+
+/// Returns the number of operations in the forward slice of the given
+/// operation, i.e. the number of entries mlirGetForwardSlice will write. Use
+/// this to allocate the buffer passed to mlirGetForwardSlice. `filter` may be
+/// NULL to traverse all operations; otherwise it acts as a frontier (see
+/// MlirSliceFilterCallback).
+MLIR_CAPI_EXPORTED intptr_t mlirGetForwardSliceSize(
+ MlirOperation op, MlirSliceFilterCallback filter, void *filterUserData);
+
+/// Computes the forward slice of the given operation, i.e. all its transitive
+/// users, not including the operation itself. The result operations are written
+/// (in slice order) into the caller-allocated `slice` buffer, which must have
+/// room for mlirGetForwardSliceSize() entries. `filter` must match the one
+/// passed to mlirGetForwardSliceSize and may be NULL to traverse all
+/// operations; otherwise it acts as a frontier (see MlirSliceFilterCallback).
+MLIR_CAPI_EXPORTED void mlirGetForwardSlice(MlirOperation op,
+ MlirSliceFilterCallback filter,
+ void *filterUserData,
+ MlirOperation *slice);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MLIR_C_ANALYSIS_H
diff --git a/mlir/lib/CAPI/IR/Analysis.cpp b/mlir/lib/CAPI/IR/Analysis.cpp
new file mode 100644
index 00000000000000..1c52092eb0733f
--- /dev/null
+++ b/mlir/lib/CAPI/IR/Analysis.cpp
@@ -0,0 +1,43 @@
+//===- Analysis.cpp - C API for MLIR Analysis Utilities -------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir-c/Analysis.h"
+
+#include "mlir/Analysis/SliceAnalysis.h"
+#include "mlir/CAPI/IR.h"
+#include "mlir/CAPI/Support.h"
+
+using namespace mlir;
+
+static SetVector<Operation *> computeForwardSlice(
+ MlirOperation op, MlirSliceFilterCallback filter, void *filterUserData) {
+ SetVector<Operation *> result;
+ ForwardSliceOptions options;
+ if (filter) {
+ options.filter = [filter, filterUserData](Operation *op) {
+ return filter(wrap(op), filterUserData);
+ };
+ }
+ getForwardSlice(unwrap(op), &result, options);
+ return result;
+}
+
+intptr_t mlirGetForwardSliceSize(MlirOperation op,
+ MlirSliceFilterCallback filter,
+ void *filterUserData) {
+ return static_cast<intptr_t>(
+ computeForwardSlice(op, filter, filterUserData).size());
+}
+
+void mlirGetForwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
+ void *filterUserData, MlirOperation *slice) {
+ SetVector<Operation *> result =
+ computeForwardSlice(op, filter, filterUserData);
+ for (intptr_t i = 0, e = static_cast<intptr_t>(result.size()); i < e; ++i)
+ slice[i] = wrap(result[i]);
+}
diff --git a/mlir/lib/CAPI/IR/CMakeLists.txt b/mlir/lib/CAPI/IR/CMakeLists.txt
index 8bc76677d2bfd2..8cad2cfab9b2c3 100644
--- a/mlir/lib/CAPI/IR/CMakeLists.txt
+++ b/mlir/lib/CAPI/IR/CMakeLists.txt
@@ -2,6 +2,7 @@
add_mlir_upstream_c_api_library(MLIRCAPIIR
AffineExpr.cpp
AffineMap.cpp
+ Analysis.cpp
BuiltinAttributes.cpp
BuiltinTypes.cpp
Diagnostics.cpp
@@ -14,6 +15,7 @@ add_mlir_upstream_c_api_library(MLIRCAPIIR
Support.cpp
LINK_LIBS PUBLIC
+ MLIRAnalysis
MLIRBytecodeWriter
MLIRIR
MLIRParser
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index 3e1e5f9d43d3c3..b22505dc0270ef 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -13,6 +13,7 @@
#include "mlir-c/IR.h"
#include "mlir-c/AffineExpr.h"
#include "mlir-c/AffineMap.h"
+#include "mlir-c/Analysis.h"
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/BuiltinTypes.h"
#include "mlir-c/Diagnostics.h"
@@ -3347,6 +3348,78 @@ int testOperationEquivalence(MlirContext ctx) {
return 0;
}
+// Prints the names of the operations in a slice buffer, for FileCheck.
+static void printSlice(MlirOperation *slice, intptr_t n) {
+ for (intptr_t i = 0; i < n; ++i) {
+ MlirStringRef name = mlirIdentifierStr(mlirOperationGetName(slice[i]));
+ fprintf(stderr, "slice: %.*s\n", (int)name.length, name.data);
+ }
+}
+
+// Slice filter that treats `arith.subi` as a frontier (stops propagation
+// through it, and excludes it from the slice).
+static bool sliceFilterExcludeSubi(MlirOperation op, void *userData) {
+ (void)userData;
+ MlirStringRef name = mlirIdentifierStr(mlirOperationGetName(op));
+ return !mlirStringRefEqual(name,
+ mlirStringRefCreateFromCString("arith.subi"));
+}
+
+int testForwardSlice(MlirContext ctx) {
+ fprintf(stderr, "@testForwardSlice\n");
+ // CHECK-LABEL: @testForwardSlice
+
+ mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("arith"));
+
+ const char *moduleStr = "func.func @f(%arg0: i32) -> i32 {\n"
+ " %0 = arith.addi %arg0, %arg0 : i32\n"
+ " %1 = arith.muli %0, %arg0 : i32\n"
+ " %2 = arith.subi %1, %0 : i32\n"
+ " return %2 : 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);
+ MlirOperation addOp = mlirBlockGetFirstOperation(funcBody);
+
+ // The forward slice of the addi is its transitive users: the muli, the subi
+ // and the return (the addi itself is not included). Query the size first,
+ // then fill a buffer.
+ intptr_t count = mlirGetForwardSliceSize(addOp, NULL, NULL);
+ assert(count == 3);
+ MlirOperation slice[3];
+ mlirGetForwardSlice(addOp, NULL, NULL, slice);
+ fprintf(stderr, "unfiltered forward slice:\n");
+ // CHECK: unfiltered forward slice:
+ printSlice(slice, count);
+ // CHECK-DAG: slice: arith.muli
+ // CHECK-DAG: slice: arith.subi
+ // CHECK-DAG: slice: func.return
+
+ // With a filter that excludes the subi, propagation stops there: only the
+ // muli remains. The return is only reachable through the (excluded) subi, so
+ // it drops out of the slice as well.
+ intptr_t filteredCount =
+ mlirGetForwardSliceSize(addOp, sliceFilterExcludeSubi, NULL);
+ assert(filteredCount == 1);
+ mlirGetForwardSlice(addOp, sliceFilterExcludeSubi, NULL, slice);
+ fprintf(stderr, "filtered forward slice:\n");
+ // CHECK: filtered forward slice:
+ printSlice(slice, filteredCount);
+ // CHECK-NEXT: slice: arith.muli
+ // CHECK-NOT: slice:
+
+ mlirModuleDestroy(module);
+
+ // CHECK: testForwardSlice: PASSED
+ fprintf(stderr, "testForwardSlice: PASSED\n");
+ return 0;
+}
+
int main(void) {
MlirContext ctx = mlirContextCreate();
registerAllUpstreamDialects(ctx);
@@ -3407,6 +3480,8 @@ int main(void) {
return 21;
if (testOperationEquivalence(ctx))
return 22;
+ if (testForwardSlice(ctx))
+ return 23;
// CHECK: DESTROY MAIN CONTEXT
// CHECK: reportResourceDelete: resource_i64_blob
>From c3af701d31e8d78b562d68ba96946196699080d3 Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Mon, 29 Jun 2026 11:00:13 -0700
Subject: [PATCH 2/3] [mlir-c] Add backward slice analysis
---
mlir/include/mlir-c/Analysis.h | 20 +++++++++++
mlir/lib/CAPI/IR/Analysis.cpp | 30 ++++++++++++++++
mlir/test/CAPI/ir.c | 65 ++++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+)
diff --git a/mlir/include/mlir-c/Analysis.h b/mlir/include/mlir-c/Analysis.h
index f07fdde3208d22..a970c9e478b105 100644
--- a/mlir/include/mlir-c/Analysis.h
+++ b/mlir/include/mlir-c/Analysis.h
@@ -44,6 +44,26 @@ MLIR_CAPI_EXPORTED void mlirGetForwardSlice(MlirOperation op,
void *filterUserData,
MlirOperation *slice);
+/// Returns the number of operations in the backward slice of the given
+/// operation, i.e. the number of entries mlirGetBackwardSlice will write, or a
+/// negative value if the backward slice could not be computed. Use this to
+/// allocate the buffer passed to mlirGetBackwardSlice. `filter` may be NULL to
+/// traverse all operations; otherwise it acts as a frontier (see
+/// MlirSliceFilterCallback).
+MLIR_CAPI_EXPORTED intptr_t mlirGetBackwardSliceSize(
+ MlirOperation op, MlirSliceFilterCallback filter, void *filterUserData);
+
+/// Computes the backward slice of the given operation, i.e. all its transitive
+/// definitions, not including the operation itself. The result operations are
+/// written (in slice order) into the caller-allocated `slice` buffer, which
+/// must have room for mlirGetBackwardSliceSize() entries. `filter` must match
+/// the one passed to mlirGetBackwardSliceSize and may be NULL to traverse all
+/// operations; otherwise it acts as a frontier (see MlirSliceFilterCallback).
+MLIR_CAPI_EXPORTED void mlirGetBackwardSlice(MlirOperation op,
+ MlirSliceFilterCallback filter,
+ void *filterUserData,
+ MlirOperation *slice);
+
#ifdef __cplusplus
}
#endif
diff --git a/mlir/lib/CAPI/IR/Analysis.cpp b/mlir/lib/CAPI/IR/Analysis.cpp
index 1c52092eb0733f..15d666b23ffbb6 100644
--- a/mlir/lib/CAPI/IR/Analysis.cpp
+++ b/mlir/lib/CAPI/IR/Analysis.cpp
@@ -41,3 +41,33 @@ void mlirGetForwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
for (intptr_t i = 0, e = static_cast<intptr_t>(result.size()); i < e; ++i)
slice[i] = wrap(result[i]);
}
+
+static LogicalResult computeBackwardSlice(MlirOperation op,
+ MlirSliceFilterCallback filter,
+ void *filterUserData,
+ SetVector<Operation *> &result) {
+ BackwardSliceOptions options;
+ if (filter) {
+ options.filter = [filter, filterUserData](Operation *op) {
+ return filter(wrap(op), filterUserData);
+ };
+ }
+ return getBackwardSlice(unwrap(op), &result, options);
+}
+
+intptr_t mlirGetBackwardSliceSize(MlirOperation op,
+ MlirSliceFilterCallback filter,
+ void *filterUserData) {
+ SetVector<Operation *> result;
+ if (failed(computeBackwardSlice(op, filter, filterUserData, result)))
+ return -1;
+ return static_cast<intptr_t>(result.size());
+}
+
+void mlirGetBackwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
+ void *filterUserData, MlirOperation *slice) {
+ SetVector<Operation *> result;
+ (void)computeBackwardSlice(op, filter, filterUserData, result);
+ for (intptr_t i = 0, e = static_cast<intptr_t>(result.size()); i < e; ++i)
+ slice[i] = wrap(result[i]);
+}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index b22505dc0270ef..6be57a681919d3 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -3420,6 +3420,69 @@ int testForwardSlice(MlirContext ctx) {
return 0;
}
+// Slice filter that treats `arith.muli` as a frontier.
+static bool sliceFilterExcludeMuli(MlirOperation op, void *userData) {
+ (void)userData;
+ MlirStringRef name = mlirIdentifierStr(mlirOperationGetName(op));
+ return !mlirStringRefEqual(name,
+ mlirStringRefCreateFromCString("arith.muli"));
+}
+
+int testBackwardSlice(MlirContext ctx) {
+ fprintf(stderr, "@testBackwardSlice\n");
+ // CHECK-LABEL: @testBackwardSlice
+
+ mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("arith"));
+
+ const char *moduleStr = "func.func @f(%arg0: i32) -> i32 {\n"
+ " %0 = arith.addi %arg0, %arg0 : i32\n"
+ " %1 = arith.muli %0, %arg0 : i32\n"
+ " %2 = arith.subi %1, %0 : i32\n"
+ " return %2 : 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);
+ MlirOperation addOp = mlirBlockGetFirstOperation(funcBody);
+ MlirOperation mulOp = mlirOperationGetNextInBlock(addOp);
+ MlirOperation subOp = mlirOperationGetNextInBlock(mulOp);
+
+ // The backward slice of the subi is its transitive definitions: the muli and
+ // the addi (the subi itself is not included; block arguments have no defining
+ // op and are skipped).
+ intptr_t count = mlirGetBackwardSliceSize(subOp, NULL, NULL);
+ assert(count == 2);
+ MlirOperation slice[2];
+ mlirGetBackwardSlice(subOp, NULL, NULL, slice);
+ fprintf(stderr, "unfiltered backward slice:\n");
+ // CHECK: unfiltered backward slice:
+ printSlice(slice, count);
+ // CHECK-DAG: slice: arith.addi
+ // CHECK-DAG: slice: arith.muli
+
+ // With a filter that excludes the muli, propagation stops there. The addi is
+ // still reached directly through the subi's other operand, so it remains.
+ intptr_t filteredCount =
+ mlirGetBackwardSliceSize(subOp, sliceFilterExcludeMuli, NULL);
+ assert(filteredCount == 1);
+ mlirGetBackwardSlice(subOp, sliceFilterExcludeMuli, NULL, slice);
+ fprintf(stderr, "filtered backward slice:\n");
+ // CHECK: filtered backward slice:
+ printSlice(slice, filteredCount);
+ // CHECK-NEXT: slice: arith.addi
+ // CHECK-NOT: slice:
+
+ mlirModuleDestroy(module);
+
+ // CHECK: testBackwardSlice: PASSED
+ fprintf(stderr, "testBackwardSlice: PASSED\n");
+ return 0;
+}
+
int main(void) {
MlirContext ctx = mlirContextCreate();
registerAllUpstreamDialects(ctx);
@@ -3482,6 +3545,8 @@ int main(void) {
return 22;
if (testForwardSlice(ctx))
return 23;
+ if (testBackwardSlice(ctx))
+ return 24;
// CHECK: DESTROY MAIN CONTEXT
// CHECK: reportResourceDelete: resource_i64_blob
>From 1b442014c03c0555b612f2667ba3ed0b3bbeaddb Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Mon, 29 Jun 2026 11:02:21 -0700
Subject: [PATCH 3/3] [mlir-c] Add getBlocksSortedByDominance and
topologicalSort
---
mlir/include/mlir-c/Analysis.h | 24 +++++++++++
mlir/lib/CAPI/IR/Analysis.cpp | 23 ++++++++++
mlir/test/CAPI/ir.c | 77 ++++++++++++++++++++++++++++++++++
3 files changed, 124 insertions(+)
diff --git a/mlir/include/mlir-c/Analysis.h b/mlir/include/mlir-c/Analysis.h
index a970c9e478b105..c74e9639f8b8e3 100644
--- a/mlir/include/mlir-c/Analysis.h
+++ b/mlir/include/mlir-c/Analysis.h
@@ -64,6 +64,30 @@ MLIR_CAPI_EXPORTED void mlirGetBackwardSlice(MlirOperation op,
void *filterUserData,
MlirOperation *slice);
+//===----------------------------------------------------------------------===//
+// Topological sort
+//===----------------------------------------------------------------------===//
+
+/// Returns the number of blocks in the given region, i.e. the number of entries
+/// mlirRegionGetBlocksSortedByDominance will write. Use this to allocate the
+/// buffer passed to mlirRegionGetBlocksSortedByDominance.
+MLIR_CAPI_EXPORTED intptr_t
+mlirRegionGetBlocksSortedByDominanceSize(MlirRegion region);
+
+/// Writes the blocks of the given region, sorted by dominance (a stable order
+/// in which a block appears after all blocks that dominate it), into the
+/// caller-allocated `blocks` buffer, which must have room for
+/// mlirRegionGetBlocksSortedByDominanceSize() entries.
+MLIR_CAPI_EXPORTED void
+mlirRegionGetBlocksSortedByDominance(MlirRegion region, MlirBlock *blocks);
+
+/// Topologically sorts the `nOps` operations in `ops` (taking region semantics
+/// into account) so that definitions come before uses, writing the result into
+/// the caller-allocated `sorted` buffer, which must have room for `nOps`
+/// entries. The input operations need not all belong to the same block.
+MLIR_CAPI_EXPORTED void mlirTopologicalSort(intptr_t nOps, MlirOperation *ops,
+ MlirOperation *sorted);
+
#ifdef __cplusplus
}
#endif
diff --git a/mlir/lib/CAPI/IR/Analysis.cpp b/mlir/lib/CAPI/IR/Analysis.cpp
index 15d666b23ffbb6..3ddd76c426f48c 100644
--- a/mlir/lib/CAPI/IR/Analysis.cpp
+++ b/mlir/lib/CAPI/IR/Analysis.cpp
@@ -9,6 +9,7 @@
#include "mlir-c/Analysis.h"
#include "mlir/Analysis/SliceAnalysis.h"
+#include "mlir/Analysis/TopologicalSortUtils.h"
#include "mlir/CAPI/IR.h"
#include "mlir/CAPI/Support.h"
@@ -71,3 +72,25 @@ void mlirGetBackwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
for (intptr_t i = 0, e = static_cast<intptr_t>(result.size()); i < e; ++i)
slice[i] = wrap(result[i]);
}
+
+intptr_t mlirRegionGetBlocksSortedByDominanceSize(MlirRegion region) {
+ return static_cast<intptr_t>(
+ getBlocksSortedByDominance(*unwrap(region)).size());
+}
+
+void mlirRegionGetBlocksSortedByDominance(MlirRegion region,
+ MlirBlock *blocks) {
+ SetVector<Block *> sorted = getBlocksSortedByDominance(*unwrap(region));
+ for (intptr_t i = 0, e = static_cast<intptr_t>(sorted.size()); i < e; ++i)
+ blocks[i] = wrap(sorted[i]);
+}
+
+void mlirTopologicalSort(intptr_t nOps, MlirOperation *ops,
+ MlirOperation *sorted) {
+ SetVector<Operation *> toSort;
+ for (intptr_t i = 0; i < nOps; ++i)
+ toSort.insert(unwrap(ops[i]));
+ SetVector<Operation *> result = topologicalSort(toSort);
+ for (intptr_t i = 0, e = static_cast<intptr_t>(result.size()); i < e; ++i)
+ sorted[i] = wrap(result[i]);
+}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index 6be57a681919d3..f885a81cd9483e 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -3483,6 +3483,81 @@ int testBackwardSlice(MlirContext ctx) {
return 0;
}
+int testTopologicalSort(MlirContext ctx) {
+ fprintf(stderr, "@testTopologicalSort\n");
+ // CHECK-LABEL: @testTopologicalSort
+
+ mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("arith"));
+ mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("cf"));
+
+ // Blocks sorted by dominance: the entry block dominates all others and must
+ // come first; the merge block ^bb3 comes last.
+ const char *cfgStr = "func.func @g(%cond: i1) -> i32 {\n"
+ " %c0 = arith.constant 0 : i32\n"
+ " %c1 = arith.constant 1 : i32\n"
+ " cf.cond_br %cond, ^bb1, ^bb2\n"
+ "^bb1:\n"
+ " cf.br ^bb3(%c0 : i32)\n"
+ "^bb2:\n"
+ " cf.br ^bb3(%c1 : i32)\n"
+ "^bb3(%result: i32):\n"
+ " return %result : i32\n"
+ "}\n";
+ MlirModule cfgModule =
+ mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(cfgStr));
+ MlirBlock cfgModuleBody = mlirModuleGetBody(cfgModule);
+ MlirOperation gFuncOp = mlirBlockGetFirstOperation(cfgModuleBody);
+ MlirRegion gRegion = mlirOperationGetRegion(gFuncOp, 0);
+ MlirBlock entry = mlirRegionGetFirstBlock(gRegion);
+ MlirBlock bb3 = mlirBlockGetNextInRegion(
+ mlirBlockGetNextInRegion(mlirBlockGetNextInRegion(entry)));
+
+ intptr_t numBlocks = mlirRegionGetBlocksSortedByDominanceSize(gRegion);
+ assert(numBlocks == 4);
+ MlirBlock blocks[4];
+ mlirRegionGetBlocksSortedByDominance(gRegion, blocks);
+ // The entry block dominates everything (reported first); the merge block is
+ // dominated by the entry (reported last).
+ assert(mlirBlockEqual(blocks[0], entry));
+ assert(mlirBlockEqual(blocks[3], bb3));
+
+ mlirModuleDestroy(cfgModule);
+
+ // Topological sort of a set of operations passed in reverse program order.
+ const char *chainStr = "func.func @f(%arg0: i32) -> i32 {\n"
+ " %0 = arith.addi %arg0, %arg0 : i32\n"
+ " %1 = arith.muli %0, %arg0 : i32\n"
+ " %2 = arith.subi %1, %0 : i32\n"
+ " return %2 : i32\n"
+ "}\n";
+ MlirModule chainModule =
+ mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(chainStr));
+ MlirBlock chainModuleBody = mlirModuleGetBody(chainModule);
+ MlirOperation fFuncOp = mlirBlockGetFirstOperation(chainModuleBody);
+ MlirRegion fRegion = mlirOperationGetRegion(fFuncOp, 0);
+ MlirBlock fBody = mlirRegionGetFirstBlock(fRegion);
+ MlirOperation addOp = mlirBlockGetFirstOperation(fBody);
+ MlirOperation mulOp = mlirOperationGetNextInBlock(addOp);
+ MlirOperation subOp = mlirOperationGetNextInBlock(mulOp);
+
+ // Pass them reversed; the sort must restore defs-before-uses order.
+ MlirOperation unsorted[3] = {subOp, mulOp, addOp};
+ MlirOperation sorted[3];
+ mlirTopologicalSort(3, unsorted, sorted);
+ fprintf(stderr, "topo sort:\n");
+ // CHECK: topo sort:
+ printSlice(sorted, 3);
+ // CHECK-NEXT: slice: arith.addi
+ // CHECK-NEXT: slice: arith.muli
+ // CHECK-NEXT: slice: arith.subi
+
+ mlirModuleDestroy(chainModule);
+
+ // CHECK: testTopologicalSort: PASSED
+ fprintf(stderr, "testTopologicalSort: PASSED\n");
+ return 0;
+}
+
int main(void) {
MlirContext ctx = mlirContextCreate();
registerAllUpstreamDialects(ctx);
@@ -3547,6 +3622,8 @@ int main(void) {
return 23;
if (testBackwardSlice(ctx))
return 24;
+ if (testTopologicalSort(ctx))
+ return 25;
// CHECK: DESTROY MAIN CONTEXT
// CHECK: reportResourceDelete: resource_i64_blob
More information about the Mlir-commits
mailing list