[Mlir-commits] [mlir] [mlir-c] Add slice analysis and topological sort (PR #206550)

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


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

>From a0f26dbcc6fe055228e43e8afe30f3d54a171469 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  | 44 ++++++++++++++++++++
 mlir/lib/CAPI/IR/Analysis.cpp   | 40 ++++++++++++++++++
 mlir/lib/CAPI/IR/CMakeLists.txt |  2 +
 mlir/test/CAPI/ir.c             | 74 +++++++++++++++++++++++++++++++++
 4 files changed, 160 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 0000000000000..8e0da6344b5f8
--- /dev/null
+++ b/mlir/include/mlir-c/Analysis.h
@@ -0,0 +1,44 @@
+//===- 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);
+
+/// 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, up to `n`
+/// entries; the total number of operations in the slice is returned (which may
+/// exceed `n`). Passing `n == 0` (with `slice` ignored) queries the size.
+/// `filter` may be NULL to traverse all operations; otherwise it acts as a
+/// frontier (see MlirSliceFilterCallback).
+MLIR_CAPI_EXPORTED intptr_t mlirGetForwardSlice(MlirOperation op,
+                                                MlirSliceFilterCallback filter,
+                                                void *filterUserData,
+                                                intptr_t n, 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 0000000000000..dae2d4e514f3f
--- /dev/null
+++ b/mlir/lib/CAPI/IR/Analysis.cpp
@@ -0,0 +1,40 @@
+//===- 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"
+
+#include <algorithm>
+
+using namespace mlir;
+
+/// Copies up to `n` operations from `slice` into the caller-provided `result`
+/// buffer (wrapping each), returning the total number of operations.
+static intptr_t copySlice(const SetVector<Operation *> &slice, intptr_t n,
+                          MlirOperation *result) {
+  intptr_t count = static_cast<intptr_t>(slice.size());
+  for (intptr_t i = 0, e = std::min(count, n); i < e; ++i)
+    result[i] = wrap(slice[i]);
+  return count;
+}
+
+intptr_t mlirGetForwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
+                             void *filterUserData, intptr_t n,
+                             MlirOperation *slice) {
+  SetVector<Operation *> result;
+  ForwardSliceOptions options;
+  if (filter)
+    options.filter = [filter, filterUserData](Operation *op) {
+      return filter(wrap(op), filterUserData);
+    };
+  getForwardSlice(unwrap(op), &result, options);
+  return copySlice(result, n, slice);
+}
diff --git a/mlir/lib/CAPI/IR/CMakeLists.txt b/mlir/lib/CAPI/IR/CMakeLists.txt
index 8bc76677d2bfd..8cad2cfab9b2c 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 57ae8b9a2819b..10fbd0a25b659 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"
@@ -2900,6 +2901,77 @@ int testDominanceInfo(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.
+  assert(mlirGetForwardSlice(addOp, NULL, NULL, 0, NULL) == 3);
+  MlirOperation slice[3];
+  intptr_t count = mlirGetForwardSlice(addOp, NULL, NULL, 3, slice);
+  assert(count == 3);
+  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 =
+      mlirGetForwardSlice(addOp, sliceFilterExcludeSubi, NULL, 3, slice);
+  assert(filteredCount == 1);
+  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);
@@ -2955,6 +3027,8 @@ int main(void) {
     return 19;
   if (testDominanceInfo(ctx))
     return 20;
+  if (testForwardSlice(ctx))
+    return 21;
 
   // CHECK: DESTROY MAIN CONTEXT
   // CHECK: reportResourceDelete: resource_i64_blob

>From 88944b6711822f294e80d468228595ea96b80a24 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 | 14 ++++++++
 mlir/lib/CAPI/IR/Analysis.cpp  | 14 ++++++++
 mlir/test/CAPI/ir.c            | 63 ++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+)

diff --git a/mlir/include/mlir-c/Analysis.h b/mlir/include/mlir-c/Analysis.h
index 8e0da6344b5f8..8d244959a9d6d 100644
--- a/mlir/include/mlir-c/Analysis.h
+++ b/mlir/include/mlir-c/Analysis.h
@@ -37,6 +37,20 @@ MLIR_CAPI_EXPORTED intptr_t mlirGetForwardSlice(MlirOperation op,
                                                 void *filterUserData,
                                                 intptr_t n, MlirOperation *slice);
 
+/// 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, up to `n`
+/// entries; the total number of operations in the slice is returned. A negative
+/// return value indicates the backward slice could not be computed. Passing
+/// `n == 0` (with `slice` ignored) queries the size. `filter` may be NULL to
+/// traverse all operations; otherwise it acts as a frontier (see
+/// MlirSliceFilterCallback).
+MLIR_CAPI_EXPORTED intptr_t mlirGetBackwardSlice(MlirOperation op,
+                                                 MlirSliceFilterCallback filter,
+                                                 void *filterUserData,
+                                                 intptr_t n,
+                                                 MlirOperation *slice);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/mlir/lib/CAPI/IR/Analysis.cpp b/mlir/lib/CAPI/IR/Analysis.cpp
index dae2d4e514f3f..a40f6687a78d3 100644
--- a/mlir/lib/CAPI/IR/Analysis.cpp
+++ b/mlir/lib/CAPI/IR/Analysis.cpp
@@ -38,3 +38,17 @@ intptr_t mlirGetForwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
   getForwardSlice(unwrap(op), &result, options);
   return copySlice(result, n, slice);
 }
+
+intptr_t mlirGetBackwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
+                              void *filterUserData, intptr_t n,
+                              MlirOperation *slice) {
+  SetVector<Operation *> result;
+  BackwardSliceOptions options;
+  if (filter)
+    options.filter = [filter, filterUserData](Operation *op) {
+      return filter(wrap(op), filterUserData);
+    };
+  if (failed(getBackwardSlice(unwrap(op), &result, options)))
+    return -1;
+  return copySlice(result, n, slice);
+}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index 10fbd0a25b659..7969b6683ac61 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -2918,6 +2918,14 @@ static bool sliceFilterExcludeSubi(MlirOperation op, void *userData) {
                              mlirStringRefCreateFromCString("arith.subi"));
 }
 
+// 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 testForwardSlice(MlirContext ctx) {
   fprintf(stderr, "@testForwardSlice\n");
   // CHECK-LABEL: @testForwardSlice
@@ -2972,6 +2980,59 @@ int testForwardSlice(MlirContext ctx) {
   return 0;
 }
 
+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).
+  MlirOperation slice[2];
+  intptr_t count = mlirGetBackwardSlice(subOp, NULL, NULL, 2, slice);
+  assert(count == 2);
+  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 =
+      mlirGetBackwardSlice(subOp, sliceFilterExcludeMuli, NULL, 2, slice);
+  assert(filteredCount == 1);
+  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);
@@ -3029,6 +3090,8 @@ int main(void) {
     return 20;
   if (testForwardSlice(ctx))
     return 21;
+  if (testBackwardSlice(ctx))
+    return 22;
 
   // CHECK: DESTROY MAIN CONTEXT
   // CHECK: reportResourceDelete: resource_i64_blob

>From 8a3261bec77b2d7713163400aaa15077b7b30d73 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 | 22 +++++++++-
 mlir/lib/CAPI/IR/Analysis.cpp  | 20 +++++++++
 mlir/test/CAPI/ir.c            | 76 ++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/mlir/include/mlir-c/Analysis.h b/mlir/include/mlir-c/Analysis.h
index 8d244959a9d6d..e0d5c87618180 100644
--- a/mlir/include/mlir-c/Analysis.h
+++ b/mlir/include/mlir-c/Analysis.h
@@ -35,7 +35,8 @@ typedef bool (*MlirSliceFilterCallback)(MlirOperation op, void *userData);
 MLIR_CAPI_EXPORTED intptr_t mlirGetForwardSlice(MlirOperation op,
                                                 MlirSliceFilterCallback filter,
                                                 void *filterUserData,
-                                                intptr_t n, MlirOperation *slice);
+                                                intptr_t n,
+                                                MlirOperation *slice);
 
 /// Computes the backward slice of the given operation, i.e. all its transitive
 /// definitions, not including the operation itself. The result operations are
@@ -51,6 +52,25 @@ MLIR_CAPI_EXPORTED intptr_t mlirGetBackwardSlice(MlirOperation op,
                                                  intptr_t n,
                                                  MlirOperation *slice);
 
+//===----------------------------------------------------------------------===//
+// Topological sort
+//===----------------------------------------------------------------------===//
+
+/// Returns the blocks of the given region sorted by dominance, a stable order
+/// in which a block appears after all blocks that dominate it. The result
+/// blocks are written into the caller-allocated `blocks` buffer, up to `n`
+/// entries; the total number of blocks in the region is returned. Passing
+/// `n == 0` (with `blocks` ignored) queries the size.
+MLIR_CAPI_EXPORTED intptr_t mlirRegionGetBlocksSortedByDominance(
+    MlirRegion region, intptr_t n, 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 a40f6687a78d3..2d59566ff22b4 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"
 
@@ -52,3 +53,22 @@ intptr_t mlirGetBackwardSlice(MlirOperation op, MlirSliceFilterCallback filter,
     return -1;
   return copySlice(result, n, slice);
 }
+
+intptr_t mlirRegionGetBlocksSortedByDominance(MlirRegion region, intptr_t n,
+                                              MlirBlock *blocks) {
+  SetVector<Block *> sorted = getBlocksSortedByDominance(*unwrap(region));
+  intptr_t count = static_cast<intptr_t>(sorted.size());
+  for (intptr_t i = 0, e = std::min(count, n); i < e; ++i)
+    blocks[i] = wrap(sorted[i]);
+  return count;
+}
+
+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 7969b6683ac61..dbb67dc91d3f3 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -3033,6 +3033,80 @@ 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)));
+
+  MlirBlock blocks[4];
+  intptr_t numBlocks = mlirRegionGetBlocksSortedByDominance(gRegion, 4, blocks);
+  assert(numBlocks == 4);
+  // 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);
@@ -3092,6 +3166,8 @@ int main(void) {
     return 21;
   if (testBackwardSlice(ctx))
     return 22;
+  if (testTopologicalSort(ctx))
+    return 23;
 
   // CHECK: DESTROY MAIN CONTEXT
   // CHECK: reportResourceDelete: resource_i64_blob



More information about the Mlir-commits mailing list