DispatchLinalgOnTensorsViaRegions: Lower ExtractSliceOps to FlowTenso… (#11084)

…rSliceOps

This is to ensure that DispatchLinalgOnTensorsViaRegions produces the
same number of dispatches as DispatchLinalgOnTensors.
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Conversion/TensorToFlow/Utils.cpp b/compiler/src/iree/compiler/Dialect/Flow/Conversion/TensorToFlow/Utils.cpp
index 0d78b79..16b807c 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Conversion/TensorToFlow/Utils.cpp
+++ b/compiler/src/iree/compiler/Dialect/Flow/Conversion/TensorToFlow/Utils.cpp
@@ -135,6 +135,9 @@
 
 LogicalResult convertExtractSliceOpToFlowSliceOp(
     RewriterBase &rewriter, tensor::ExtractSliceOp sliceOp) {
+  OpBuilder::InsertionGuard g(rewriter);
+  rewriter.setInsertionPoint(sliceOp);
+
   if (sliceOp->getParentOfType<Flow::DispatchWorkgroupsOp>()) {
     return failure();
   }
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Transforms/DispatchLinalgOnTensorsViaRegionOps.cpp b/compiler/src/iree/compiler/Dialect/Flow/Transforms/DispatchLinalgOnTensorsViaRegionOps.cpp
index f77661d..39e093a 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Transforms/DispatchLinalgOnTensorsViaRegionOps.cpp
+++ b/compiler/src/iree/compiler/Dialect/Flow/Transforms/DispatchLinalgOnTensorsViaRegionOps.cpp
@@ -720,6 +720,71 @@
   return wrapInWorkgroupsOp(rewriter, rootOps, generateWorkloadRegion);
 }
 
+/// Return `true` if the given op is contained in DispatchWorkgroupsOp or in a
+/// DispatchRegionOp.
+static bool isInDispatchRegion(Operation *op) {
+  return op->getParentOfType<Flow::DispatchWorkgroupsOp>() ||
+         op->getParentOfType<Flow::DispatchRegionOp>();
+}
+
+/// Rewrite top-level InsertSliceOps to FlowUpdateOps or wrap them in a
+/// dispatch region.
+LogicalResult convertInsertSliceOps(
+    TensorDimTrackingRewriter &rewriter, mlir::FunctionOpInterface funcOp,
+    SmallVector<Flow::DispatchWorkgroupsOp> &workgroupsOps,
+    bool generateWorkloadRegion) {
+  // Find eligible InsertSliceOps.
+  SmallVector<tensor::InsertSliceOp> insertSliceOps;
+  funcOp.walk([&](tensor::InsertSliceOp op) {
+    if (!isInDispatchRegion(op)) insertSliceOps.push_back(op);
+  });
+
+  // Rewrite InsertSliceOps to FlowUpdateOps.
+  SmallVector<Operation *> remainingInsertSliceOps;
+  for (tensor::InsertSliceOp insertSliceOp : insertSliceOps)
+    if (failed(
+            Flow::convertInsertSliceOpToFlowUpdateOp(rewriter, insertSliceOp)))
+      remainingInsertSliceOps.push_back(insertSliceOp);
+
+  // Create a DispatchWorkgroupsOp for every remaining InsertSliceOp.
+  FailureOr<SmallVector<Flow::DispatchWorkgroupsOp>> newWorkgroupsOps =
+      wrapInWorkgroupsOp(rewriter, remainingInsertSliceOps,
+                         generateWorkloadRegion);
+  if (failed(newWorkgroupsOps)) return failure();
+  workgroupsOps.append(newWorkgroupsOps->begin(), newWorkgroupsOps->end());
+
+  return success();
+}
+
+/// Rewrite top-level ExtractSliceOps to FlowSliceOps or wrap them in a
+/// dispatch region.
+LogicalResult convertExtractSliceOps(
+    TensorDimTrackingRewriter &rewriter, mlir::FunctionOpInterface funcOp,
+    SmallVector<Flow::DispatchWorkgroupsOp> &workgroupsOps,
+    bool generateWorkloadRegion) {
+  // Find eligible ExtractSliceOps.
+  SmallVector<tensor::ExtractSliceOp> extractSliceOps;
+  funcOp.walk([&](tensor::ExtractSliceOp op) {
+    if (!isInDispatchRegion(op)) extractSliceOps.push_back(op);
+  });
+
+  // Rewrite ExtractSliceOps to FlowSliceOps.
+  SmallVector<Operation *> remainingExtractSliceOps;
+  for (tensor::ExtractSliceOp extractSliceOp : extractSliceOps)
+    if (failed(
+            Flow::convertExtractSliceOpToFlowSliceOp(rewriter, extractSliceOp)))
+      remainingExtractSliceOps.push_back(extractSliceOp);
+
+  // Create a DispatchWorkgroupsOp for every remaining ExtractSliceOp.
+  FailureOr<SmallVector<Flow::DispatchWorkgroupsOp>> newWorkgroupsOps =
+      wrapInWorkgroupsOp(rewriter, remainingExtractSliceOps,
+                         generateWorkloadRegion);
+  if (failed(newWorkgroupsOps)) return failure();
+  workgroupsOps.append(newWorkgroupsOps->begin(), newWorkgroupsOps->end());
+
+  return success();
+}
+
 namespace {
 /// Pass declaration.
 struct DispatchLinalgOnTensorsViaRegionOpsPass
@@ -745,7 +810,7 @@
 }  // namespace
 
 void DispatchLinalgOnTensorsViaRegionOpsPass::runOnOperation() {
-  auto funcOp = getOperation();
+  mlir::FunctionOpInterface funcOp = getOperation();
   MLIRContext *context = &getContext();
 
   DominanceInfo const &dominanceInfo = getAnalysis<DominanceInfo>();
@@ -763,30 +828,20 @@
     llvm::dbgs() << "\n\n";
   });
 
-  // Step 2a: Rewrite InsertSliceOps to TensorUpdateOps.
-  SmallVector<tensor::InsertSliceOp> insertSliceOps;
-  SmallVector<Operation *> remainingInsertSliceOps;
-  funcOp.walk([&](tensor::InsertSliceOp op) {
-    if (!op->getParentOfType<Flow::DispatchRegionOp>())
-      insertSliceOps.push_back(op);
-  });
-  for (tensor::InsertSliceOp insertSliceOp : insertSliceOps)
-    if (failed(
-            Flow::convertInsertSliceOpToFlowUpdateOp(rewriter, insertSliceOp)))
-      remainingInsertSliceOps.push_back(insertSliceOp);
+  // Step 2: Rewrite InsertSliceOps to FlowUpdateOps.
+  if (failed(convertInsertSliceOps(rewriter, funcOp, workgroupsOps,
+                                   generateWorkloadRegion)))
+    return signalPassFailure();
 
-  // Step 2b: Create a DispatchWorkgroupsOp for every remaining InsertSliceOp.
+  // Step 3: Rewrite ExtractSliceOps to FlowUpdateOps.
+  if (failed(convertExtractSliceOps(rewriter, funcOp, workgroupsOps,
+                                    generateWorkloadRegion)))
+    return signalPassFailure();
+
+  // Step 4: Create a DispatchWorkgroupsOp for certain other ops.
   FailureOr<SmallVector<Flow::DispatchWorkgroupsOp>> newWorkgroupsOps =
-      wrapInWorkgroupsOp(rewriter, remainingInsertSliceOps,
-                         generateWorkloadRegion);
-  if (failed(newWorkgroupsOps)) return signalPassFailure();
-  workgroupsOps.append(newWorkgroupsOps->begin(), newWorkgroupsOps->end());
-
-  // Step 3: Create a DispatchWorkgroupsOp for certain other ops.
-  newWorkgroupsOps =
-      wrapInWorkgroupsOp<tensor::ExtractSliceOp, LinalgExt::SetEncodingOp,
-                         LinalgExt::UnsetEncodingOp>(rewriter, funcOp,
-                                                     generateWorkloadRegion);
+      wrapInWorkgroupsOp<LinalgExt::SetEncodingOp, LinalgExt::UnsetEncodingOp>(
+          rewriter, funcOp, generateWorkloadRegion);
   if (failed(newWorkgroupsOps)) return signalPassFailure();
   workgroupsOps.append(newWorkgroupsOps->begin(), newWorkgroupsOps->end());
 
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Transforms/test/dispatch_linalg_on_tensors.mlir b/compiler/src/iree/compiler/Dialect/Flow/Transforms/test/dispatch_linalg_on_tensors.mlir
index 2a3d3cf..54e6a33 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Transforms/test/dispatch_linalg_on_tensors.mlir
+++ b/compiler/src/iree/compiler/Dialect/Flow/Transforms/test/dispatch_linalg_on_tensors.mlir
@@ -2054,3 +2054,31 @@
 // CHECK-SAME:         ins(%[[LHS]], %[[RHS]] :
 // CHECK-SAME:         outs(%[[FILL]] :
 //      CHECK:     flow.dispatch.tensor.store %[[GEMM]], %[[RESULT]]
+
+// -----
+
+func.func @extract_slice1(%arg0 : tensor<5x24x48xf32>) -> tensor<4xf32> {
+  %0 = tensor.extract_slice %arg0[2, 3, 4] [1, 1, 4] [1, 1, 1]
+      : tensor<5x24x48xf32> to tensor<4xf32>
+  return %0 : tensor<4xf32>
+}
+
+// CHECK-LABEL: func.func @extract_slice1(
+//  CHECK-SAME:   %[[ARG0:.+]]: tensor<5x24x48xf32>)
+//   CHECK-DAG:   %[[C2:.+]] = arith.constant 2 : index
+//   CHECK-DAG:   %[[C3:.+]] = arith.constant 3 : index
+//   CHECK-DAG:   %[[C1:.+]] = arith.constant 1 : index
+//   CHECK-DAG:   %[[C4:.+]] = arith.constant 4 : index
+//       CHECK:   %[[SLICE:.+]] = flow.tensor.slice %[[ARG0]][%[[C2]], %[[C3]], %[[C4]] for %[[C1]], %[[C1]], %[[C4]]]
+//       CHECK:   %[[RESULT:.+]] = flow.tensor.reshape %[[SLICE]]
+//       CHECK:   return %[[RESULT]]
+
+// CHECK-VIA-REGIONS-LABEL: func.func @extract_slice1(
+//  CHECK-VIA-REGIONS-SAME:   %[[ARG0:.+]]: tensor<5x24x48xf32>)
+//   CHECK-VIA-REGIONS-DAG:   %[[C2:.+]] = arith.constant 2 : index
+//   CHECK-VIA-REGIONS-DAG:   %[[C3:.+]] = arith.constant 3 : index
+//   CHECK-VIA-REGIONS-DAG:   %[[C1:.+]] = arith.constant 1 : index
+//   CHECK-VIA-REGIONS-DAG:   %[[C4:.+]] = arith.constant 4 : index
+//       CHECK-VIA-REGIONS:   %[[SLICE:.+]] = flow.tensor.slice %[[ARG0]][%[[C2]], %[[C3]], %[[C4]] for %[[C1]], %[[C1]], %[[C4]]]
+//       CHECK-VIA-REGIONS:   %[[RESULT:.+]] = flow.tensor.reshape %[[SLICE]]
+//       CHECK-VIA-REGIONS:   return %[[RESULT]]