| //===- TopologicalSortUtils.h - Topological sort 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_TRANSFORMS_TOPOLOGICALSORTUTILS_H |
| #define MLIR_TRANSFORMS_TOPOLOGICALSORTUTILS_H |
| |
| #include "mlir/IR/Block.h" |
| |
| namespace mlir { |
| |
| /// Given a block, sort a range operations in said block in topological order. |
| /// The main purpose is readability of graph regions, potentially faster |
| /// processing of certain transformations and analyses, or fixing the SSA |
| /// dominance of blocks that require it after transformations. The function |
| /// sorts the given operations such that, as much as possible, all users appear |
| /// after their producers. |
| /// |
| /// For example: |
| /// |
| /// ```mlir |
| /// %0 = test.foo |
| /// %1 = test.bar %0, %2 |
| /// %2 = test.baz |
| /// ``` |
| /// |
| /// Will become: |
| /// |
| /// ```mlir |
| /// %0 = test.foo |
| /// %1 = test.baz |
| /// %2 = test.bar %0, %1 |
| /// ``` |
| /// |
| /// The sort also works on operations with regions and implicit captures. For |
| /// example: |
| /// |
| /// ```mlir |
| /// %0 = test.foo { |
| /// test.baz %1 |
| /// %1 = test.bar %2 |
| /// } |
| /// %2 = test.foo |
| /// ``` |
| /// |
| /// Will become: |
| /// |
| /// ```mlir |
| /// %0 = test.foo |
| /// %1 = test.foo { |
| /// test.baz %2 |
| /// %2 = test.bar %0 |
| /// } |
| /// ``` |
| /// |
| /// Note that the sort is not recursive on nested regions. This sort is stable; |
| /// if the operations are already topologically sorted, nothing changes. |
| /// |
| /// Operations that form cycles are moved to the end of the block in order. If |
| /// the sort is left with only operations that form a cycle, it breaks the cycle |
| /// by marking the first encountered operation as ready and moving on. |
| /// |
| /// The function optionally accepts a callback that can be provided by users to |
| /// virtually break cycles early. It is called on top-level operations in the |
| /// block with value uses at or below those operations. The function should |
| /// return true to mark that value as ready to be scheduled. |
| /// |
| /// For example, if `isOperandReady` is set to always mark edges from `foo.A` to |
| /// `foo.B` as ready, these operations: |
| /// |
| /// ```mlir |
| /// %0 = foo.B(%1) |
| /// %1 = foo.C(%2) |
| /// %2 = foo.A(%0) |
| /// ``` |
| /// |
| /// Are sorted as: |
| /// |
| /// ```mlir |
| /// %0 = foo.A(%2) |
| /// %1 = foo.C(%0) |
| /// %2 = foo.B(%1) |
| /// ``` |
| bool sortTopologically( |
| Block *block, iterator_range<Block::iterator> ops, |
| function_ref<bool(Value, Operation *)> isOperandReady = nullptr); |
| |
| /// Given a block, sort its operations in topological order, excluding its |
| /// terminator if it has one. This sort is stable. |
| bool sortTopologically( |
| Block *block, |
| function_ref<bool(Value, Operation *)> isOperandReady = nullptr); |
| |
| /// Compute a topological ordering of the given ops. This sort is not stable. |
| /// |
| /// Note: If the specified ops contain incomplete/interrupted SSA use-def |
| /// chains, the result may not actually be a topological sorting with respect to |
| /// the entire program. |
| bool computeTopologicalSorting( |
| MutableArrayRef<Operation *> ops, |
| function_ref<bool(Value, Operation *)> isOperandReady = nullptr); |
| |
| } // end namespace mlir |
| |
| #endif // MLIR_TRANSFORMS_TOPOLOGICALSORTUTILS_H |