Skip to content

Commit 2164a44

Browse files
[mlir][Transforms] Add loop-invariant subset hoisting (LISH) transformation (#70619)
Add a loop-invariant subset hoisting pass to `mlir/Interfaces`. This pass hoist loop-invariant tensor subsets (subset extraction and subset insertion ops) from loop-like ops. Extraction ops are moved before the loop. Insertion ops are moved after the loop. The loop body operates on newly added region iter_args (one per extraction-insertion pair). This new pass will be improved in subsequent commits (to support more cases/ops) and will eventually replace `Linalg/Transforms/SubsetHoisting.cpp`. In contrast to the existing Linalg subset hoisting, the new pass is op interface-based (`SubsetOpInterface` and `LoopLikeOpInterface`).
1 parent 1abd8d1 commit 2164a44

File tree

8 files changed

+556
-4
lines changed

8 files changed

+556
-4
lines changed

mlir/include/mlir/Transforms/LoopInvariantCodeMotionUtils.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,45 @@ size_t moveLoopInvariantCode(
7171
/// methods provided by the interface.
7272
size_t moveLoopInvariantCode(LoopLikeOpInterface loopLike);
7373

74+
/// Hoist loop-invariant tensor subsets (subset extraction and subset insertion
75+
/// ops) from loop-like ops. Extraction ops are moved before the loop. Insertion
76+
/// ops are moved after the loop. The loop body operates on newly added region
77+
/// iter_args (one per extraction-insertion pair).
78+
///
79+
/// A subset extraction op (`SubsetExtractionOpInterface`) extracts from a
80+
/// tensor value at a subset. The result of the op may have an arbitrary type,
81+
/// i.e., not necessarily a tensor type. Example: "tensor.extract_slice".
82+
///
83+
/// A subset insertion op (`SubsetInsertionOpInterface`) inserts into a tensor
84+
/// value ("destination") at a subset. Example: "tensor.insert_slice".
85+
///
86+
/// Matching extraction-insertion subset ops can be hoisted from a loop if there
87+
/// are no other ops within the loop that operate on the same or on an
88+
/// overlapping subset. In particular, non-subset ops can prevent hoisting
89+
/// because the analysis does not know what subset they operate on.
90+
///
91+
/// Example:
92+
/// ```
93+
/// %r = scf.for ... iter_args(%t = %a) -> (tensor<?xf32>) {
94+
/// %0 = tensor.extract_slice %t[0][5][1] : tensor<?xf32> to tensor<5xf32>
95+
/// %1 = "test.foo"(%0) : (tensor<5xf32>) -> (tensor<5xf32>)
96+
/// %2 = tensor.insert_slice %1 into %t[0][5][1]
97+
/// : tensor<5xf32> into tensor<?xf32>
98+
/// scf.yield %2 : tensor<?xf32>
99+
/// }
100+
/// ```
101+
/// Is rewritten to:
102+
/// ```
103+
/// %0 = tensor.extract_slice %a[0][5][1] : tensor<?xf32> to tensor<5xf32>
104+
/// %new_loop:2 = scf.for ... iter_args(%t = %a, %h = %0) -> (tensor<?xf32>) {
105+
/// %1 = "test.foo"(%h) : (tensor<5xf32>) -> (tensor<5xf32>)
106+
/// scf.yield %t, %2 : tensor<?xf32>, tensor<5xf32>
107+
/// }
108+
/// %r = tensor.insert_slice %new_loop#1 into %new_loop#0
109+
/// : tensor<5xf32> into tensor<?xf32>
110+
/// ```
111+
LoopLikeOpInterface hoistLoopInvariantSubsets(LoopLikeOpInterface loopLike);
112+
74113
} // end namespace mlir
75114

76115
#endif // MLIR_TRANSFORMS_LOOPINVARIANTCODEMOTIONUTILS_H

mlir/include/mlir/Transforms/Passes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ std::unique_ptr<Pass> createGenerateRuntimeVerificationPass();
7878
/// instructions out of the loop.
7979
std::unique_ptr<Pass> createLoopInvariantCodeMotionPass();
8080

81+
/// Creates a pass that hoists loop-invariant subset ops.
82+
std::unique_ptr<Pass> createLoopInvariantSubsetHoistingPass();
83+
8184
/// Creates a pass to strip debug information from a function.
8285
std::unique_ptr<Pass> createStripDebugInfoPass();
8386

mlir/include/mlir/Transforms/Passes.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@ def LoopInvariantCodeMotion : Pass<"loop-invariant-code-motion"> {
329329
let constructor = "mlir::createLoopInvariantCodeMotionPass()";
330330
}
331331

332+
def LoopInvariantSubsetHoisting : Pass<"loop-invariant-subset-hoisting"> {
333+
let summary = "Hoist loop invariant subset ops outside of the loop";
334+
let constructor = "mlir::createLoopInvariantSubsetHoistingPass()";
335+
}
336+
332337
def Mem2Reg : Pass<"mem2reg"> {
333338
let summary = "Promotes memory slots into values.";
334339
let description = [{

mlir/lib/Transforms/LoopInvariantCodeMotion.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
namespace mlir {
2020
#define GEN_PASS_DEF_LOOPINVARIANTCODEMOTION
21+
#define GEN_PASS_DEF_LOOPINVARIANTSUBSETHOISTING
2122
#include "mlir/Transforms/Passes.h.inc"
2223
} // namespace mlir
2324

@@ -29,6 +30,12 @@ struct LoopInvariantCodeMotion
2930
: public impl::LoopInvariantCodeMotionBase<LoopInvariantCodeMotion> {
3031
void runOnOperation() override;
3132
};
33+
34+
struct LoopInvariantSubsetHoisting
35+
: public impl::LoopInvariantSubsetHoistingBase<
36+
LoopInvariantSubsetHoisting> {
37+
void runOnOperation() override;
38+
};
3239
} // namespace
3340

3441
void LoopInvariantCodeMotion::runOnOperation() {
@@ -39,6 +46,19 @@ void LoopInvariantCodeMotion::runOnOperation() {
3946
[&](LoopLikeOpInterface loopLike) { moveLoopInvariantCode(loopLike); });
4047
}
4148

49+
void LoopInvariantSubsetHoisting::runOnOperation() {
50+
// Walk through all loops in a function in innermost-loop-first order. This
51+
// way, we first hoist from the inner loop, and place the ops in the outer
52+
// loop, which in turn can be further hoisted from.
53+
getOperation()->walk([&](LoopLikeOpInterface loopLike) {
54+
(void)hoistLoopInvariantSubsets(loopLike);
55+
});
56+
}
57+
4258
std::unique_ptr<Pass> mlir::createLoopInvariantCodeMotionPass() {
4359
return std::make_unique<LoopInvariantCodeMotion>();
4460
}
61+
62+
std::unique_ptr<Pass> mlir::createLoopInvariantSubsetHoistingPass() {
63+
return std::make_unique<LoopInvariantSubsetHoisting>();
64+
}

mlir/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ add_mlir_library(MLIRTransformUtils
2020
MLIRFunctionInterfaces
2121
MLIRLoopLikeInterface
2222
MLIRSideEffectInterfaces
23+
MLIRSubsetOpInterface
2324
MLIRRewrite
2425
)

0 commit comments

Comments
 (0)