[Dispach] Clone chain of ops into dispatch (#19723)
This change modifies `cloneProducersToRegion` to iteratively clone
producers into the region. For example if ther is a chain A -> B ->
Dispatch, where A and B are cloneable. `A` is only detected as a
clonable op after `B` has been cloned.
Also traverses backwards to delete trivially dead ops so that consumers
get erased first.
Signed-off-by: Ian Wood <ianwood2024@u.northwestern.edu>
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Transforms/RegionOpUtils.cpp b/compiler/src/iree/compiler/Dialect/Flow/Transforms/RegionOpUtils.cpp
index c9f4808..4aa9142 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Transforms/RegionOpUtils.cpp
+++ b/compiler/src/iree/compiler/Dialect/Flow/Transforms/RegionOpUtils.cpp
@@ -915,17 +915,20 @@
/// Clone producers into the dispatch region.
LogicalResult cloneProducersToRegion(RewriterBase &rewriter,
IREE::Flow::DispatchRegionOp regionOp) {
- SmallVector<Operation *> cloneableOps = getCloneableOps(regionOp);
- bool sortResult = mlir::computeTopologicalSorting(cloneableOps);
- (void)sortResult;
- assert(sortResult && "could not compute topological sorting");
+ SmallVector<Operation *> cloneableOps;
+ do {
+ cloneableOps = getCloneableOps(regionOp);
+ bool sortResult = mlir::computeTopologicalSorting(cloneableOps);
+ (void)sortResult;
+ assert(sortResult && "could not compute topological sorting");
- for (Operation *producer : llvm::reverse(cloneableOps)) {
- if (failed(
- clonePrecedingOpIntoDispatchRegion(rewriter, producer, regionOp))) {
- return failure();
+ for (Operation *producer : llvm::reverse(cloneableOps)) {
+ if (failed(clonePrecedingOpIntoDispatchRegion(rewriter, producer,
+ regionOp))) {
+ return failure();
+ }
}
- }
+ } while (!cloneableOps.empty());
return success();
}
diff --git a/compiler/src/iree/compiler/DispatchCreation/CloneProducersIntoDispatchRegions.cpp b/compiler/src/iree/compiler/DispatchCreation/CloneProducersIntoDispatchRegions.cpp
index a9d4203..a64f961 100644
--- a/compiler/src/iree/compiler/DispatchCreation/CloneProducersIntoDispatchRegions.cpp
+++ b/compiler/src/iree/compiler/DispatchCreation/CloneProducersIntoDispatchRegions.cpp
@@ -8,6 +8,7 @@
#include "iree/compiler/Dialect/Flow/Transforms/RegionOpUtils.h"
#include "iree/compiler/DispatchCreation/Passes.h"
#include "mlir/Dialect/Linalg/IR/Linalg.h"
+#include "mlir/IR/Iterators.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
@@ -34,10 +35,13 @@
return signalPassFailure();
});
- funcOp->walk([&](Operation *op) {
+ funcOp->walk<WalkOrder::PostOrder, ReverseIterator>([&](Operation *op) {
if (isOpTriviallyDead(op)) {
return rewriter.eraseOp(op);
}
+ });
+
+ funcOp->walk([&](Operation *op) {
if (!IREE::Flow::isNonNullAndOutsideDispatch(op) ||
!isa<linalg::GenericOp>(op)) {
return;
diff --git a/compiler/src/iree/compiler/DispatchCreation/test/clone_producers_into_dispatch_regions.mlir b/compiler/src/iree/compiler/DispatchCreation/test/clone_producers_into_dispatch_regions.mlir
index 5741ac1..af2c5cd 100644
--- a/compiler/src/iree/compiler/DispatchCreation/test/clone_producers_into_dispatch_regions.mlir
+++ b/compiler/src/iree/compiler/DispatchCreation/test/clone_producers_into_dispatch_regions.mlir
@@ -506,3 +506,51 @@
// CHECK: %[[ATTENTION:.+]] = iree_linalg_ext.attention
// CHECK: ins({{.*}}, %[[GATHER0]], %[[GATHER1]]
// CHECK: flow.return %[[ATTENTION]]
+
+// -----
+
+util.func public @clone_bit_ext_of_gather_like(%arg0: tensor<128256x4096xf16>, %arg1: tensor<4x?xi64>, %arg2: tensor<4096xf32>) -> tensor<4x?xf32> {
+ %c1 = arith.constant 1 : index
+ %cst = arith.constant 0.000000e+00 : f32
+ %cst_0 = arith.constant 1.000000e-01 : f32
+ %dim = tensor.dim %arg1, %c1 : tensor<4x?xi64>
+ %0 = tensor.empty(%dim) : tensor<4x?x4096xf16>
+ %1 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%arg1 : tensor<4x?xi64>) outs(%0 : tensor<4x?x4096xf16>) {
+ ^bb0(%in: i64, %out: f16):
+ %7 = arith.index_cast %in : i64 to index
+ %8 = linalg.index 2 : index
+ %extracted = tensor.extract %arg0[%7, %8] : tensor<128256x4096xf16>
+ linalg.yield %extracted : f16
+ } -> tensor<4x?x4096xf16>
+ %2 = tensor.empty(%dim) : tensor<4x?x4096xf32>
+ %3 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%1 : tensor<4x?x4096xf16>) outs(%2 : tensor<4x?x4096xf32>) {
+ ^bb0(%in: f16, %out: f32):
+ %7 = arith.extf %in : f16 to f32
+ linalg.yield %7 : f32
+ } -> tensor<4x?x4096xf32>
+ %4 = tensor.empty(%dim) : tensor<4x?xf32>
+ %5 = linalg.fill ins(%cst : f32) outs(%4 : tensor<4x?xf32>) -> tensor<4x?xf32>
+ %6 = flow.dispatch.region -> (tensor<4x?xf32>{%dim}) {
+ %7 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"]} ins(%3 : tensor<4x?x4096xf32>) outs(%5 : tensor<4x?xf32>) {
+ ^bb0(%in: f32, %out: f32):
+ %8 = math.powf %in, %cst_0 : f32
+ %9 = arith.addf %8, %out : f32
+ linalg.yield %9 : f32
+ } -> tensor<4x?xf32>
+ flow.return %7 : tensor<4x?xf32>
+ }
+ util.return %6 : tensor<4x?xf32>
+}
+
+// CHECK-LABEL: util.func public @clone_bit_ext_of_gather_like
+// CHECK: %[[DISPATCH:.+]] = flow.dispatch.region
+// CHECK: %[[GATHER0:.+]] = linalg.generic
+// CHECK: %[[EXTRACT:.+]] = tensor.extract
+// CHECK: linalg.yield %[[EXTRACT]]
+// CHECK: %[[EXT:.+]] = linalg.generic
+// CHECK-SAME: ins(%[[GATHER0]] : tensor<4x?x4096xf16>)
+// CHECK: %[[EXTF:.+]] = arith.extf
+// CHECK: linalg.yield %[[EXTF]]
+// CHECK: %[[RES:.+]] = linalg.generic
+// CHECK-SAME: ins(%[[EXT]] : tensor<4x?x4096xf32>)
+// CHECK: flow.return %[[RES]]