1 | //===- ControlFlowSinkUtils.h - ControlFlow Sink Utils ----------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef MLIR_TRANSFORMS_CONTROLFLOWSINKUTILS_H |
10 | #define MLIR_TRANSFORMS_CONTROLFLOWSINKUTILS_H |
11 | |
12 | #include "mlir/Support/LLVM.h" |
13 | |
14 | namespace mlir { |
15 | |
16 | class DominanceInfo; |
17 | class Operation; |
18 | class Region; |
19 | class RegionBranchOpInterface; |
20 | class RegionRange; |
21 | |
22 | /// Given a list of regions, perform control flow sinking on them. For each |
23 | /// region, control-flow sinking moves operations that dominate the region but |
24 | /// whose only users are in the region into the regions so that they aren't |
25 | /// executed on paths where their results are not needed. |
26 | /// |
27 | /// TODO: For the moment, this is a *simple* control-flow sink, i.e., no |
28 | /// duplicating of ops. It should be made to accept a cost model to determine |
29 | /// whether duplicating a particular op is profitable. |
30 | /// |
31 | /// Example: |
32 | /// |
33 | /// ```mlir |
34 | /// %0 = arith.addi %arg0, %arg1 |
35 | /// scf.if %cond { |
36 | /// scf.yield %0 |
37 | /// } else { |
38 | /// scf.yield %arg2 |
39 | /// } |
40 | /// ``` |
41 | /// |
42 | /// After control-flow sink: |
43 | /// |
44 | /// ```mlir |
45 | /// scf.if %cond { |
46 | /// %0 = arith.addi %arg0, %arg1 |
47 | /// scf.yield %0 |
48 | /// } else { |
49 | /// scf.yield %arg2 |
50 | /// } |
51 | /// ``` |
52 | /// |
53 | /// Users must supply a callback `shouldMoveIntoRegion` that determines whether |
54 | /// the given operation that only has users in the given operation should be |
55 | /// moved into that region. If this returns true, `moveIntoRegion` is called on |
56 | /// the same operation and region. |
57 | /// |
58 | /// `moveIntoRegion` must move the operation into the region such that dominance |
59 | /// of the operation is preserved; for example, by moving the operation to the |
60 | /// start of the entry block. This ensures the preservation of SSA dominance of |
61 | /// the operation's results. |
62 | /// |
63 | /// Returns the number of operations sunk. |
64 | size_t |
65 | controlFlowSink(RegionRange regions, DominanceInfo &domInfo, |
66 | function_ref<bool(Operation *, Region *)> shouldMoveIntoRegion, |
67 | function_ref<void(Operation *, Region *)> moveIntoRegion); |
68 | |
69 | /// Populates `regions` with regions of the provided region branch op that are |
70 | /// executed at most once at that are reachable given the current operands of |
71 | /// the op. These regions can be passed to `controlFlowSink` to perform sinking |
72 | /// on the regions of the operation. |
73 | void getSinglyExecutedRegionsToSink(RegionBranchOpInterface branch, |
74 | SmallVectorImpl<Region *> ®ions); |
75 | |
76 | } // namespace mlir |
77 | |
78 | #endif // MLIR_TRANSFORMS_CONTROLFLOWSINKUTILS_H |
79 | |