llvm-project/mlir/test/Dialect/Transform/test-interpreter.mlir
Alex Zinenko 984c2c8cb3 [mlir] verify against nullptr payload in transform dialect
When establishing the correspondence between transform values and
payload operations or parameters, check that the latter are non-null and
report errors. This was previously allowed for exotic cases of partially
successfull transformations with "apply each" trait, but was dangerous.
The "apply each" implementation was reworked to remove the need for this
functionality, so this can now be hardned to avoid null pointer
dereferences.

Reviewed By: nicolasvasilache

Differential Revision: https://reviews.llvm.org/D141142
2023-01-09 14:03:35 +01:00

1043 lines
32 KiB
MLIR

// RUN: mlir-opt %s --test-transform-dialect-interpreter -allow-unregistered-dialect --split-input-file --verify-diagnostics
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-remark @below {{applying transformation}}
transform.test_transform_op
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
%0 = transform.test_produce_param_or_forward_operand 42 { foo = "bar" }
// expected-remark @below {{succeeded}}
transform.test_consume_operand_if_matches_param_or_fail %0[42]
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
%0 = transform.test_produce_param_or_forward_operand 42 { foo = "bar" }
// expected-error @below {{expected the operand to be associated with 21 got 42}}
transform.test_consume_operand_if_matches_param_or_fail %0[21]
}
// -----
// It is okay to have multiple handles to the same payload op as long
// as only one of them is consumed. The expensive checks mode is necessary
// to detect double-consumption.
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
%0 = transform.test_produce_param_or_forward_operand 42 { foo = "bar" }
%1 = transform.test_copy_payload %0
// expected-remark @below {{succeeded}}
transform.test_consume_operand_if_matches_param_or_fail %0[42]
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !pdl.operation):
sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
// expected-remark @below {{applying transformation "a"}}
test_transform_op "a"
// expected-remark @below {{applying transformation "b"}}
test_transform_op "b"
// expected-remark @below {{applying transformation "c"}}
test_transform_op "c"
}
// expected-remark @below {{applying transformation "d"}}
test_transform_op "d"
// expected-remark @below {{applying transformation "e"}}
test_transform_op "e"
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !pdl.operation):
%0 = test_produce_param_or_forward_operand 42
sequence %0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
// expected-remark @below {{succeeded}}
test_consume_operand_if_matches_param_or_fail %arg1[42]
}
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !pdl.operation):
%0 = sequence %arg0 : !pdl.operation -> !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%1 = test_produce_param_or_forward_operand 42
yield %1 : !pdl.operation
}
// expected-remark @below {{succeeded}}
test_consume_operand_if_matches_param_or_fail %0[42]
}
// -----
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
test_print_remark_at_operand %0, "matched" : !pdl.operation
}
pdl.pattern @some : benefit(1) {
%0 = pdl.operation "test.some_op"
pdl.rewrite %0 with "transform.dialect"
}
pdl.pattern @other : benefit(1) {
%0 = pdl.operation "test.other_op"
pdl.rewrite %0 with "transform.dialect"
}
}
// expected-remark @below {{matched}}
"test.some_op"() : () -> ()
"test.other_op"() : () -> ()
// expected-remark @below {{matched}}
"test.some_op"() : () -> ()
// -----
// expected-remark @below {{parent function}}
func.func @foo() {
%0 = arith.constant 0 : i32
return
}
// expected-remark @below {{parent function}}
func.func @bar() {
%0 = arith.constant 0 : i32
%1 = arith.constant 1 : i32
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @const : benefit(1) {
%r = pdl.types
%0 = pdl.operation "arith.constant" -> (%r : !pdl.range<type>)
pdl.rewrite %0 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%f = pdl_match @const in %arg1 : (!pdl.operation) -> !pdl.operation
// CHECK: %{{.+}} = get_closest_isolated_parent %{{.+}}
%m = get_closest_isolated_parent %f : (!pdl.operation) -> !pdl.operation
test_print_remark_at_operand %m, "parent function" : !pdl.operation
}
}
// -----
func.func @foo() {
%0 = arith.constant 0 : i32
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @match_func : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "func.func"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
// This is necessary to run the transformation on something other than the
// top-level module, "alternatives" cannot be run on that.
%0 = pdl_match @match_func in %arg1 : (!pdl.operation) -> !pdl.operation
transform.alternatives %0 : !pdl.operation {
^bb2(%arg2: !pdl.operation):
%1 = transform.test_produce_param_or_forward_operand 42
// This operation fails, which triggers the next alternative without
// reporting the error.
transform.test_consume_operand_if_matches_param_or_fail %1[43]
}, {
^bb2(%arg2: !pdl.operation):
%1 = transform.test_produce_param_or_forward_operand 42
// expected-remark @below {{succeeded}}
transform.test_consume_operand_if_matches_param_or_fail %1[42]
}
}
}
// -----
func.func private @bar()
func.func @foo() {
call @bar() : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @match_call : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @match_call in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = get_closest_isolated_parent %0 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{all alternatives failed}}
transform.alternatives %1 : !pdl.operation {
^bb2(%arg2: !pdl.operation):
%2 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
// expected-remark @below {{applying}}
transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase}
}
}
}
// -----
func.func private @bar()
func.func @foo() {
// expected-remark @below {{still here}}
call @bar() : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @match_call : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @match_call in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = get_closest_isolated_parent %0 : (!pdl.operation) -> !pdl.operation
transform.alternatives %1 : !pdl.operation {
^bb2(%arg2: !pdl.operation):
%2 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
// expected-remark @below {{applying}}
transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase}
}, {
^bb2(%arg2: !pdl.operation):
%2 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
transform.test_print_remark_at_operand %2, "still here" : !pdl.operation
// This alternative succeeds.
}, {
^bb2(%arg2: !pdl.operation):
// This alternative is never run, so we must not have a remark here.
%2 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
transform.test_emit_remark_and_erase_operand %2, "should not happen" {fail_after_erase}
}
}
}
// -----
func.func private @bar()
// CHECK-LABEL: @erase_call
func.func @erase_call() {
// CHECK-NOT: call @bar
call @bar() : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @match_call : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @match_call in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = get_closest_isolated_parent %0 : (!pdl.operation) -> !pdl.operation
transform.alternatives %1 : !pdl.operation {
^bb2(%arg2: !pdl.operation):
%2 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
// expected-remark @below {{applying}}
transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase}
}, {
^bb2(%arg2: !pdl.operation):
%2 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
// expected-remark @below {{applying second time}}
transform.test_emit_remark_and_erase_operand %2, "applying second time"
}
}
}
// -----
func.func private @bar()
func.func @foo() {
call @bar() : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @match_call : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @match_call in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = get_closest_isolated_parent %0 : (!pdl.operation) -> !pdl.operation
%2 = transform.alternatives %1 : !pdl.operation -> !pdl.operation {
^bb2(%arg2: !pdl.operation):
%3 = transform.pdl_match @match_call in %arg2 : (!pdl.operation) -> !pdl.operation
// expected-remark @below {{applying}}
transform.test_emit_remark_and_erase_operand %3, "applying" {fail_after_erase}
%4 = transform.test_produce_param_or_forward_operand 43
transform.yield %4 : !pdl.operation
}, {
^bb2(%arg2: !pdl.operation):
%4 = transform.test_produce_param_or_forward_operand 42
transform.yield %4 : !pdl.operation
}
// The first alternative failed, so the returned value is taken from the
// second alternative.
// expected-remark @below {{succeeded}}
transform.test_consume_operand_if_matches_param_or_fail %2[42]
}
}
// -----
// expected-note @below {{scope}}
module {
func.func @foo() {
%0 = arith.constant 0 : i32
return
}
func.func @bar() {
%0 = arith.constant 0 : i32
%1 = arith.constant 1 : i32
return
}
transform.sequence failures(propagate) {
^bb1(%arg1: !pdl.operation):
// expected-error @below {{scope must not contain the transforms being applied}}
transform.alternatives %arg1 : !pdl.operation {
^bb2(%arg2: !pdl.operation):
%0 = transform.test_produce_param_or_forward_operand 42
transform.test_consume_operand_if_matches_param_or_fail %0[43]
}, {
^bb2(%arg2: !pdl.operation):
%0 = transform.test_produce_param_or_forward_operand 42
transform.test_consume_operand_if_matches_param_or_fail %0[42]
}
}
}
// -----
func.func @foo(%arg0: index, %arg1: index, %arg2: index) {
// expected-note @below {{scope}}
scf.for %i = %arg0 to %arg1 step %arg2 {
%0 = arith.constant 0 : i32
}
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @match_const : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "arith.constant"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = transform.pdl_match @match_const in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = transform.loop.get_parent_for %0 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{only isolated-from-above ops can be alternative scopes}}
alternatives %1 : !pdl.operation {
^bb2(%arg2: !pdl.operation):
}
}
}
// -----
func.func @foo() {
// expected-note @below {{when applied to this op}}
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{applications of transform.test_wrong_number_of_results expected to produce 3 results (actually produced 1).}}
// expected-note @below {{If you need variadic results, consider a generic `apply` instead of the specialized `applyToOne`.}}
// expected-note @below {{Producing 3 null results is allowed if the use case warrants it.}}
transform.test_wrong_number_of_results %0
}
}
// -----
func.func @foo() {
"op" () : () -> ()
// expected-note @below {{when applied to this op}}
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{applications of transform.test_wrong_number_of_multi_results expected to produce 1 results (actually produced 0)}}
// expected-note @below {{If you need variadic results, consider a generic `apply` instead of the specialized `applyToOne`.}}
// expected-note @below {{Producing 1 null results is allowed if the use case warrants it.}}
transform.test_wrong_number_of_multi_results %0
}
}
// -----
func.func @foo() {
"op" () : () -> ()
"op" () : () -> ()
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// Transform matches 3 ops and produces 2 results.
%1:2 = transform.test_correct_number_of_multi_results %0
}
}
// -----
func.func @foo() {
"wrong_op_name" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// Transform fails to match any but still produces 2 results.
%1:2 = transform.test_correct_number_of_multi_results %0
}
}
// -----
func.func @foo() {
// expected-note @below {{when applied to this op}}
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{unexpected application of transform.test_mixed_null_and_non_null_results produces both null and non null results.}}
transform.test_mixed_null_and_non_null_results %0
}
}
// -----
// Expecting to match all operations by merging the handles that matched addi
// and subi separately.
func.func @foo(%arg0: index) {
// expected-remark @below {{matched}}
%0 = arith.addi %arg0, %arg0 : index
// expected-remark @below {{matched}}
%1 = arith.subi %arg0, %arg0 : index
// expected-remark @below {{matched}}
%2 = arith.addi %0, %1 : index
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @addi : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "arith.addi"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
pdl.pattern @subi : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "arith.subi"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @addi in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = pdl_match @subi in %arg1 : (!pdl.operation) -> !pdl.operation
%2 = merge_handles %0, %1 : !pdl.operation
test_print_remark_at_operand %2, "matched" : !pdl.operation
}
}
// -----
func.func @foo() {
"op" () { target_me } : () -> ()
// expected-note @below {{when applied to this op}}
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{failed to apply}}
transform.test_mixed_sucess_and_silenceable %0
}
}
// -----
func.func @foo() {
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(suppress) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// Not expecting error here because we are suppressing it.
// expected-remark @below {{foo}}
test_emit_remark_and_erase_operand %0, "foo" {fail_after_erase}
}
}
// -----
func.func @foo() {
"op" () : () -> ()
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{silenceable error}}
// expected-remark @below {{foo}}
test_emit_remark_and_erase_operand %0, "foo" {fail_after_erase}
}
}
// -----
module {
func.func private @foo()
func.func private @bar()
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @func : benefit(1) {
%0 = pdl.operands
%1 = pdl.types
%2 = pdl.operation "func.func"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
pdl.rewrite %2 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @func in %arg1 : (!pdl.operation) -> !pdl.operation
%1 = replicate num(%0) %arg1 : !pdl.operation, !pdl.operation
// expected-remark @below {{2}}
test_print_number_of_associated_payload_ir_ops %1
%2 = replicate num(%0) %1 : !pdl.operation, !pdl.operation
// expected-remark @below {{4}}
test_print_number_of_associated_payload_ir_ops %2
}
}
}
// -----
func.func @bar() {
// expected-remark @below {{transform applied}}
%0 = arith.constant 0 : i32
// expected-remark @below {{transform applied}}
%1 = arith.constant 1 : i32
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @const : benefit(1) {
%r = pdl.types
%0 = pdl.operation "arith.constant" -> (%r : !pdl.range<type>)
pdl.rewrite %0 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%f = pdl_match @const in %arg1 : (!pdl.operation) -> !pdl.operation
transform.foreach %f : !pdl.operation {
^bb2(%arg2: !pdl.operation):
// expected-remark @below {{1}}
transform.test_print_number_of_associated_payload_ir_ops %arg2
transform.test_print_remark_at_operand %arg2, "transform applied" : !pdl.operation
}
}
}
// -----
func.func @bar() {
scf.execute_region {
// expected-remark @below {{transform applied}}
%0 = arith.constant 0 : i32
scf.yield
}
scf.execute_region {
// expected-remark @below {{transform applied}}
%1 = arith.constant 1 : i32
// expected-remark @below {{transform applied}}
%2 = arith.constant 2 : i32
scf.yield
}
return
}
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @const : benefit(1) {
%r = pdl.types
%0 = pdl.operation "arith.constant" -> (%r : !pdl.range<type>)
pdl.rewrite %0 with "transform.dialect"
}
pdl.pattern @execute_region : benefit(1) {
%r = pdl.types
%0 = pdl.operation "scf.execute_region" -> (%r : !pdl.range<type>)
pdl.rewrite %0 with "transform.dialect"
}
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%f = pdl_match @execute_region in %arg1 : (!pdl.operation) -> !pdl.operation
%results = transform.foreach %f : !pdl.operation -> !pdl.operation {
^bb2(%arg2: !pdl.operation):
%g = transform.pdl_match @const in %arg2 : (!pdl.operation) -> !pdl.operation
transform.yield %g : !pdl.operation
}
// expected-remark @below {{3}}
transform.test_print_number_of_associated_payload_ir_ops %results
transform.test_print_remark_at_operand %results, "transform applied" : !pdl.operation
}
}
// -----
func.func @get_parent_for_op_no_loop(%arg0: index, %arg1: index) {
// expected-remark @below {{found muli}}
%0 = arith.muli %arg0, %arg1 : index
arith.addi %0, %arg1 : index
return
}
transform.sequence failures(propagate) {
^bb1(%arg1: !pdl.operation):
%addi = transform.structured.match ops{["arith.addi"]} in %arg1
%muli = get_producer_of_operand %addi[0] : (!pdl.operation) -> !pdl.operation
transform.test_print_remark_at_operand %muli, "found muli" : !pdl.operation
}
// -----
func.func @get_parent_for_op_no_loop(%arg0: index, %arg1: index) {
// expected-note @below {{target op}}
%0 = arith.muli %arg0, %arg1 : index
return
}
transform.sequence failures(propagate) {
^bb1(%arg1: !pdl.operation):
%muli = transform.structured.match ops{["arith.muli"]} in %arg1
// expected-error @below {{could not find a producer for operand number: 0 of}}
%bbarg = get_producer_of_operand %muli[0] : (!pdl.operation) -> !pdl.operation
}
// -----
func.func @split_handles(%a: index, %b: index, %c: index) {
%0 = arith.muli %a, %b : index
%1 = arith.muli %a, %c : index
return
}
transform.sequence failures(propagate) {
^bb1(%fun: !pdl.operation):
%muli = transform.structured.match ops{["arith.muli"]} in %fun
%h:2 = split_handles %muli in [2] : (!pdl.operation) -> (!pdl.operation, !pdl.operation)
// expected-remark @below {{1}}
transform.test_print_number_of_associated_payload_ir_ops %h#0
%muli_2 = transform.structured.match ops{["arith.muli"]} in %fun
// expected-error @below {{expected to contain 3 operation handles but it only contains 2 handles}}
%h_2:3 = split_handles %muli_2 in [3] : (!pdl.operation) -> (!pdl.operation, !pdl.operation, !pdl.operation)
}
// -----
func.func @split_handles(%a: index, %b: index, %c: index) {
%0 = arith.muli %a, %b : index
%1 = arith.muli %a, %c : index
return
}
transform.sequence failures(suppress) {
^bb1(%fun: !pdl.operation):
%muli = transform.structured.match ops{["arith.muli"]} in %fun
%h:2 = split_handles %muli in [2] : (!pdl.operation) -> (!pdl.operation, !pdl.operation)
// expected-remark @below {{1}}
transform.test_print_number_of_associated_payload_ir_ops %h#0
%muli_2 = transform.structured.match ops{["arith.muli"]} in %fun
// Silenceable failure and all handles are now empty.
%h_2:3 = split_handles %muli_2 in [3] : (!pdl.operation) -> (!pdl.operation, !pdl.operation, !pdl.operation)
// expected-remark @below {{0}}
transform.test_print_number_of_associated_payload_ir_ops %h_2#0
}
// -----
"test.some_op"() : () -> ()
"other_dialect.other_op"() : () -> ()
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operation "test.some_op"
pdl.rewrite %0 with "transform.dialect"
}
sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
%2 = transform.cast %0 : !pdl.operation to !transform.test_dialect_op
transform.cast %2 : !transform.test_dialect_op to !pdl.operation
}
}
// -----
"test.some_op"() : () -> ()
"other_dialect.other_op"() : () -> ()
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @other : benefit(1) {
%0 = pdl.operation "other_dialect.other_op"
pdl.rewrite %0 with "transform.dialect"
}
sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @other in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{expected the payload operation to belong to the 'test' dialect}}
%2 = transform.cast %0 : !pdl.operation to !transform.test_dialect_op
transform.cast %2 : !transform.test_dialect_op to !pdl.operation
}
}
// -----
"test.some_op"() : () -> ()
"other_dialect.other_op"() : () -> ()
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @some : benefit(1) {
%0 = pdl.operation "test.some_op"
pdl.rewrite %0 with "transform.dialect"
}
sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
%2 = transform.cast %0 : !pdl.operation to !transform.op<"test.some_op">
transform.cast %2 : !transform.op<"test.some_op"> to !pdl.operation
}
}
// -----
"test.some_op"() : () -> ()
// expected-note @below {{payload operation}}
"other_dialect.other_op"() : () -> ()
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
pdl.pattern @other : benefit(1) {
%0 = pdl.operation "other_dialect.other_op"
pdl.rewrite %0 with "transform.dialect"
}
sequence %arg0 : !pdl.operation failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @other in %arg1 : (!pdl.operation) -> !pdl.operation
// expected-error @below {{incompatible payload operation name}}
%2 = transform.cast %0 : !pdl.operation to !transform.op<"test.some_op">
transform.cast %2 : !transform.op<"test.some_op"> to !pdl.operation
}
}
// -----
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
transform.sequence %arg0 : !pdl.operation failures(propagate) {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @some in %arg1 : (!pdl.operation) -> !pdl.operation
// here, the handles nested under are {%arg0, %arg1, %0}
// expected-remark @below {{3 handles nested under}}
transform.test_report_number_of_tracked_handles_nested_under %arg1
// expected-remark @below {{erased}}
transform.test_emit_remark_and_erase_operand %0, "erased"
// here, the handles nested under are only {%arg0, %arg1}
// expected-remark @below {{2 handles nested under}}
transform.test_report_number_of_tracked_handles_nested_under %arg1
}
pdl.pattern @some : benefit(1) {
%0 = pdl.operation "test.some_op"
pdl.rewrite %0 with "transform.dialect"
}
}
"test.some_op"() : () -> ()
// -----
func.func @split_handles(%a: index, %b: index, %c: index) {
%0 = arith.muli %a, %b : index
%1 = arith.muli %a, %c : index
return
}
transform.sequence -> !pdl.operation failures(propagate) {
^bb1(%fun: !pdl.operation):
%muli = transform.structured.match ops{["arith.muli"]} in %fun
// expected-error @below {{expected to contain 3 operation handles but it only contains 2 handles}}
%h_2:3 = split_handles %muli in [3] : (!pdl.operation) -> (!pdl.operation, !pdl.operation, !pdl.operation)
/// Test that yield does not crash in the presence of silenceable error in
/// propagate mode.
yield %fun : !pdl.operation
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
%0 = transform.test_produce_integer_param_with_type i32 : !transform.test_dialect_param
// expected-remark @below {{0 : i32}}
transform.test_print_param %0 : !transform.test_dialect_param
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-error @below {{expected the type of the parameter attribute ('i32') to match the parameter type ('i64')}}
transform.test_produce_integer_param_with_type i32 : !transform.param<i64>
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
%0 = transform.test_add_to_param 40
%1 = transform.test_add_to_param %0, 2
// expected-remark @below {{42 : i32}}
transform.test_print_param %1 : !transform.test_dialect_param
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !pdl.operation):
%0 = transform.structured.match ops{["func.func"]} in %arg0
%1 = transform.test_produce_param_with_number_of_test_ops %0 : !pdl.operation
// expected-remark @below {{1 : i32, 3 : i32}}
transform.test_print_param %1 : !transform.test_dialect_param
%2 = transform.test_add_to_param %1, 100
// expected-remark @below {{101 : i32, 103 : i32}}
transform.test_print_param %2 : !transform.test_dialect_param
}
func.func private @one_test_op(%arg0: i32) {
"test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
return
}
func.func private @three_test_ops(%arg0: i32) {
"test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
"test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
"test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
return
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-error @below {{expected to produce an Operation * for result #0}}
transform.test_produce_transform_param_or_forward_operand %arg0
{ first_result_is_param }
: (!transform.any_op) -> (!transform.any_op, !transform.param<i64>)
}
// -----
// expected-note @below {{when applied to this op}}
module {
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-error @below {{produces both null and non null results}}
transform.test_produce_transform_param_or_forward_operand %arg0
{ first_result_is_null }
: (!transform.any_op) -> (!transform.any_op, !transform.param<i64>)
}
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-error @below {{expected to produce an Attribute for result #1}}
transform.test_produce_transform_param_or_forward_operand %arg0
{ second_result_is_handle }
: (!transform.any_op) -> (!transform.any_op, !transform.param<i64>)
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-error @below {{attempting to assign a null payload op to this transform value}}
%0 = transform.test_produce_null_payload : !transform.any_op
}
// -----
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-error @below {{attempting to assign a null parameter to this transform value}}
%0 = transform.test_produce_null_param : !transform.param<i64>
}