aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrzej WarzyƄski <andrzej.warzynski@arm.com>2023-09-27 20:58:39 +0100
committerGitHub <noreply@github.com>2023-09-27 20:58:39 +0100
commit1d5ccce12167937c83de2b1b82b4adb6f89cc511 (patch)
tree3c52f8aa1d0438d4365efc29b4951ab1d78aa541
parent0bc68ca4278269dadd91f98a3cd0de62499d3ea3 (diff)
downloadllvm-1d5ccce12167937c83de2b1b82b4adb6f89cc511.zip
llvm-1d5ccce12167937c83de2b1b82b4adb6f89cc511.tar.gz
llvm-1d5ccce12167937c83de2b1b82b4adb6f89cc511.tar.bz2
[mlir][transform] Update transform.loop.peel (#67482)
This patch updates `transform.loop.peel` so that this Op returns two rather than one handle: * one for the peeled loop, and * one for the remainder loop. Also, following this change this Op will fail if peeling fails. This is consistent with other similar Ops that also fail if no transformation takes place.
-rw-r--r--mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td19
-rw-r--r--mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp14
-rw-r--r--mlir/test/Dialect/Linalg/transform-op-fuse.mlir2
-rw-r--r--mlir/test/Dialect/SCF/transform-ops-invalid.mlir20
-rw-r--r--mlir/test/Dialect/SCF/transform-ops.mlir13
5 files changed, 47 insertions, 21 deletions
diff --git a/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td b/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td
index 207a004..3adf5f0 100644
--- a/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td
+++ b/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td
@@ -142,23 +142,22 @@ def LoopPeelOp : Op<Transform_Dialect, "loop.peel",
This operation ignores non-scf::ForOp ops and drops them in the return.
- This operation always succeeds and returns the scf::ForOp with the
- postcondition: "the loop trip count is divisible by the step".
- This operation may return the same unmodified loop handle when peeling did
- not modify the IR (i.e. the loop trip count was already divisible).
+ This operation returns two scf::ForOp, with the first Op satisfying the
+ postcondition: "the loop trip count is divisible by the step". The second
+ loop Op contains the remaining iteration. Note that even though the
+ Payload IR modification may be performed in-place, this operation consumes
+ the operand handle and produces a new one.
- Note that even though the Payload IR modification may be performed
- in-place, this operation consumes the operand handle and produces a new
- one.
+ #### Return Modes
- TODO: Return both the peeled loop and the remainder loop.
+ Produces a definite failure if peeling fails.
}];
let arguments =
(ins Transform_ScfForOp:$target,
DefaultValuedAttr<BoolAttr, "false">:$fail_if_already_divisible);
- // TODO: Return both the peeled loop and the remainder loop.
- let results = (outs TransformHandleTypeInterface:$transformed);
+ let results = (outs TransformHandleTypeInterface:$peeled_loop,
+ TransformHandleTypeInterface:$remainder_loop);
let assemblyFormat =
"$target attr-dict `:` functional-type(operands, results)";
diff --git a/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp b/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
index d7e8c38..65d503d 100644
--- a/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
+++ b/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
@@ -226,14 +226,16 @@ transform::LoopPeelOp::applyToOne(transform::TransformRewriter &rewriter,
transform::ApplyToEachResultList &results,
transform::TransformState &state) {
scf::ForOp result;
- // This helper returns failure when peeling does not occur (i.e. when the IR
- // is not modified). This is not a failure for the op as the postcondition:
- // "the loop trip count is divisible by the step"
- // is valid.
LogicalResult status =
scf::peelForLoopAndSimplifyBounds(rewriter, target, result);
- // TODO: Return both the peeled loop and the remainder loop.
- results.push_back(failed(status) ? target : result);
+ if (failed(status)) {
+ DiagnosedSilenceableFailure diag = emitSilenceableError()
+ << "failed to peel";
+ return diag;
+ }
+ results.push_back(target);
+ results.push_back(result);
+
return DiagnosedSilenceableFailure::success();
}
diff --git a/mlir/test/Dialect/Linalg/transform-op-fuse.mlir b/mlir/test/Dialect/Linalg/transform-op-fuse.mlir
index d3772e9..72c6166 100644
--- a/mlir/test/Dialect/Linalg/transform-op-fuse.mlir
+++ b/mlir/test/Dialect/Linalg/transform-op-fuse.mlir
@@ -48,7 +48,7 @@ transform.sequence failures(propagate) {
%0 = transform.structured.match ops{["linalg.elemwise_binary"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1, %loops:2 = transform.structured.fuse %0 {tile_sizes = [32, 32], tile_interchange = [0, 1]}
: (!transform.any_op) -> (!transform.any_op, !transform.op<"scf.for">, !transform.any_op)
- transform.loop.peel %loops#0 : (!transform.op<"scf.for">) -> !transform.any_op
+ transform.loop.peel %loops#0 : (!transform.op<"scf.for">) -> (!transform.any_op, !transform.any_op)
}
// -----
diff --git a/mlir/test/Dialect/SCF/transform-ops-invalid.mlir b/mlir/test/Dialect/SCF/transform-ops-invalid.mlir
index b69ea0f..e8212f5 100644
--- a/mlir/test/Dialect/SCF/transform-ops-invalid.mlir
+++ b/mlir/test/Dialect/SCF/transform-ops-invalid.mlir
@@ -59,3 +59,23 @@ transform.sequence failures(propagate) {
// expected-error @below {{failed to outline}}
transform.loop.outline %0 {func_name = "foo"} : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
}
+
+// -----
+
+func.func @test_loops_do_not_get_peeled() {
+ %lb = arith.constant 0 : index
+ %ub = arith.constant 40 : index
+ %step = arith.constant 5 : index
+ scf.for %i = %lb to %ub step %step {
+ arith.addi %i, %i : index
+ }
+ return
+}
+
+transform.sequence failures(propagate) {
+^bb1(%arg1: !transform.any_op):
+ %0 = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ %1 = transform.loop.get_parent_for %0 : (!transform.any_op) -> !transform.op<"scf.for">
+ // expected-error @below {{failed to peel}}
+ transform.loop.peel %1 : (!transform.op<"scf.for">) -> (!transform.any_op, !transform.any_op)
+}
diff --git a/mlir/test/Dialect/SCF/transform-ops.mlir b/mlir/test/Dialect/SCF/transform-ops.mlir
index 7718ebc..0439987 100644
--- a/mlir/test/Dialect/SCF/transform-ops.mlir
+++ b/mlir/test/Dialect/SCF/transform-ops.mlir
@@ -87,16 +87,18 @@ transform.sequence failures(propagate) {
// CHECK-LABEL: @loop_peel_op
func.func @loop_peel_op() {
// CHECK: %[[C0:.+]] = arith.constant 0
- // CHECK: %[[C42:.+]] = arith.constant 42
+ // CHECK: %[[C41:.+]] = arith.constant 41
// CHECK: %[[C5:.+]] = arith.constant 5
// CHECK: %[[C40:.+]] = arith.constant 40
// CHECK: scf.for %{{.+}} = %[[C0]] to %[[C40]] step %[[C5]]
// CHECK: arith.addi
- // CHECK: scf.for %{{.+}} = %[[C40]] to %[[C42]] step %[[C5]]
+ // CHECK: scf.for %{{.+}} = %[[C40]] to %[[C41]] step %[[C5]]
// CHECK: arith.addi
%0 = arith.constant 0 : index
- %1 = arith.constant 42 : index
+ %1 = arith.constant 41 : index
%2 = arith.constant 5 : index
+ // expected-remark @below {{main loop}}
+ // expected-remark @below {{remainder loop}}
scf.for %i = %0 to %1 step %2 {
arith.addi %i, %i : index
}
@@ -107,7 +109,10 @@ transform.sequence failures(propagate) {
^bb1(%arg1: !transform.any_op):
%0 = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1 = transform.loop.get_parent_for %0 : (!transform.any_op) -> !transform.op<"scf.for">
- transform.loop.peel %1 : (!transform.op<"scf.for">) -> !transform.any_op
+ %main_loop, %remainder = transform.loop.peel %1 : (!transform.op<"scf.for">) -> (!transform.op<"scf.for">, !transform.op<"scf.for">)
+ // Make sure
+ transform.test_print_remark_at_operand %main_loop, "main loop" : !transform.op<"scf.for">
+ transform.test_print_remark_at_operand %remainder, "remainder loop" : !transform.op<"scf.for">
}
// -----