[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