// RUN: mlir-opt %s --transform-interpreter -allow-unregistered-dialect --split-input-file --verify-diagnostics | FileCheck %s // UNSUPPORTED: target=aarch64-pc-windows-msvc module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-remark @below {{applying transformation}} transform.test_transform_op transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_self_handle_or_forward_operand { foo = "bar" } : () -> !transform.any_op // expected-remark @below {{succeeded}} transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_self_handle_or_forward_operand { foo = "bar" } : () -> !transform.any_op // expected-error @below {{expected the operand to be associated a payload op of kind transform.sequence got transform.test_produce_self_handle_or_forward_operand}} transform.test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op transform.yield } } // ----- // 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. module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_self_handle_or_forward_operand { foo = "bar" } : () -> !transform.any_op %1 = transform.test_copy_payload %0 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{succeeded}} transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): // 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"}} transform.test_transform_op "d" // expected-remark @below {{applying transformation "e"}} transform.test_transform_op "e" transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op transform.sequence %0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): // expected-remark @below {{succeeded}} test_consume_operand_of_op_kind_or_fail %arg1, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op } transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.sequence %arg0 : !transform.any_op -> !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %1 = test_produce_self_handle_or_forward_operand : () -> !transform.any_op yield %1 : !transform.any_op } // expected-remark @below {{succeeded}} transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op transform.yield } } // ----- // 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 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @const : benefit(1) { %r = pdl.types %0 = pdl.operation "arith.constant" -> (%r : !pdl.range) pdl.rewrite %0 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %f = pdl_match @const in %arg1 : (!transform.any_op) -> !transform.any_op %m = get_parent_op %f {isolated_from_above} : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %m, "parent function" : !transform.any_op } } transform.yield } } // ----- func.func @test_get_nth_parent() { "test.foo"() ({ // expected-remark @below{{2nd parent}} "test.foo"() ({ "test.qux"() ({ // expected-remark @below{{1st parent}} "test.foo"() ({ "test.bar"() : () -> () }) : () -> () }) : () -> () }) : () -> () }) : () -> () } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %f = transform.structured.match ops{["test.bar"]} in %arg0 : (!transform.any_op) -> !transform.any_op %parent = transform.get_parent_op %f {nth_parent = 1, op_name = "test.foo"} : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %parent, "1st parent" : !transform.any_op %parent2 = transform.get_parent_op %f {nth_parent = 2, op_name = "test.foo"} : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %parent2, "2nd parent" : !transform.any_op transform.yield } } // ----- func.func @foo() { %0 = arith.constant 0 : i32 return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @match_func : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "func.func"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): // 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 : (!transform.any_op) -> !transform.any_op transform.alternatives %0 : !transform.any_op { ^bb2(%arg2: !transform.any_op): %1 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op // This operation fails, which triggers the next alternative without // reporting the error. transform.test_consume_operand_of_op_kind_or_fail %1, "transform.sequence" : !transform.any_op }, { ^bb2(%arg2: !transform.any_op): %1 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op // expected-remark @below {{succeeded}} transform.test_consume_operand_of_op_kind_or_fail %1, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op } } } transform.yield } } // ----- func.func private @bar() func.func @foo() { call @bar() : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @match_call : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "func.call"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op // expected-error @below {{all alternatives failed}} transform.alternatives %1 : !transform.any_op { ^bb2(%arg2: !transform.any_op): %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{applying}} transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase} : !transform.any_op } } } transform.yield } } // ----- func.func private @bar() func.func @foo() { // expected-remark @below {{still here}} call @bar() : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @match_call : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "func.call"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op transform.alternatives %1 : !transform.any_op { ^bb2(%arg2: !transform.any_op): %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{applying}} transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase} : !transform.any_op }, { ^bb2(%arg2: !transform.any_op): %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %2, "still here" : !transform.any_op // This alternative succeeds. }, { ^bb2(%arg2: !transform.any_op): // This alternative is never run, so we must not have a remark here. %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op transform.test_emit_remark_and_erase_operand %2, "should not happen" {fail_after_erase} : !transform.any_op } } } transform.yield } } // ----- func.func private @bar() func.func @erase_call() { call @bar() : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @match_call : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "func.call"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op transform.alternatives %1 : !transform.any_op { ^bb2(%arg2: !transform.any_op): %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{applying}} transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase} : !transform.any_op }, { ^bb2(%arg2: !transform.any_op): %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{applying second time}} transform.test_emit_remark_and_erase_operand %2, "applying second time" : !transform.any_op } } } transform.yield } } // ----- func.func private @bar() func.func @foo() { call @bar() : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @match_call : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "func.call"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op %2 = transform.alternatives %1 : !transform.any_op -> !transform.any_op { ^bb2(%arg2: !transform.any_op): %3 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{applying}} transform.test_emit_remark_and_erase_operand %3, "applying" {fail_after_erase} : !transform.any_op %4 = transform.test_produce_self_handle_or_forward_operand %3 : (!transform.any_op) -> !transform.any_op transform.yield %4 : !transform.any_op }, { ^bb2(%arg2: !transform.any_op): %4 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op transform.yield %4 : !transform.any_op } // The first alternative failed, so the returned value is taken from the // second alternative, associated test_produce_self_handle_or_forward_operand rather // than pdl_match. // expected-remark @below {{succeeded}} transform.test_consume_operand_of_op_kind_or_fail %2, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op } } transform.yield } } // ----- // expected-note @below {{scope}} module attributes {transform.with_named_sequence} { func.func @foo() { %0 = arith.constant 0 : i32 return } func.func @bar() { %0 = arith.constant 0 : i32 %1 = arith.constant 1 : i32 return } transform.named_sequence @__transform_main(%arg1: !transform.any_op) { // expected-error @below {{scope must not contain the transforms being applied}} transform.alternatives %arg1 : !transform.any_op { ^bb2(%arg2: !transform.any_op): %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op transform.test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op }, { ^bb2(%arg2: !transform.any_op): %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op } transform.yield } } // ----- 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 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @match_const : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "arith.constant"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = transform.pdl_match @match_const in %arg1 : (!transform.any_op) -> !transform.any_op %1 = transform.get_parent_op %0 {op_name = "scf.for"} : (!transform.any_op) -> !transform.any_op // expected-error @below {{only isolated-from-above ops can be alternative scopes}} alternatives %1 : !transform.any_op { ^bb2(%arg2: !transform.any_op): } } } transform.yield } } // ----- func.func @foo() { // expected-note @below {{when applied to this op}} "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{application 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`.}} transform.test_wrong_number_of_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op) } } transform.yield } } // ----- func.func @foo() { "op" () : () -> () // expected-note @below {{when applied to this op}} "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{application 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`.}} transform.test_wrong_number_of_multi_results %0 : (!transform.any_op) -> (!transform.any_op) } } transform.yield } } // ----- func.func @foo() { "op" () : () -> () "op" () : () -> () "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // Transform matches 3 ops and produces 2 results. %1:2 = transform.test_correct_number_of_multi_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op) } } transform.yield } } // ----- func.func @foo() { "wrong_op_name" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // Transform fails to match any but still produces 2 results. %1:2 = transform.test_correct_number_of_multi_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op) } } transform.yield } } // ----- // This should not fail. func.func @foo() { "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op transform.test_mixed_null_and_non_null_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op) } } transform.yield } } // ----- // 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 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @addi : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "arith.addi"(%0 : !pdl.range) -> (%1 : !pdl.range) 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) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @addi in %arg1 : (!transform.any_op) -> !transform.any_op %1 = pdl_match @subi in %arg1 : (!transform.any_op) -> !transform.any_op %2 = merge_handles %0, %1 : !transform.any_op transform.debug.emit_remark_at %2, "matched" : !transform.any_op } } transform.yield } } // ----- func.func @foo(%arg0: index) { %0 = arith.addi %arg0, %arg0 : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @addi : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "arith.addi"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @addi in %arg1 : (!transform.any_op) -> !transform.any_op %1 = pdl_match @addi in %arg1 : (!transform.any_op) -> !transform.any_op %2 = merge_handles deduplicate %0, %1 : !transform.any_op %3 = num_associations %2 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %3 : !transform.param } } transform.yield } } // ----- func.func @foo() { "op" () { target_me } : () -> () // expected-note @below {{when applied to this op}} "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{failed to apply}} transform.test_mixed_success_and_silenceable %0 : !transform.any_op } } transform.yield } } // ----- func.func @foo() { "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(suppress) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // Not expecting error here because we are suppressing it. // expected-remark @below {{foo}} test_emit_remark_and_erase_operand %0, "foo" {fail_after_erase} : !transform.any_op } } transform.yield } } // ----- func.func @foo() { "op" () : () -> () return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "op"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{silenceable error}} // expected-remark @below {{foo}} test_emit_remark_and_erase_operand %0, "foo" {fail_after_erase} : !transform.any_op } } transform.yield } } // ----- module attributes {transform.with_named_sequence} { func.func private @foo() func.func private @bar() transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @func : benefit(1) { %0 = pdl.operands %1 = pdl.types %2 = pdl.operation "func.func"(%0 : !pdl.range) -> (%1 : !pdl.range) pdl.rewrite %2 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @func in %arg1 : (!transform.any_op) -> !transform.any_op %1 = replicate num(%0) %arg1 : !transform.any_op, !transform.any_op %p = num_associations %1 : (!transform.any_op) -> !transform.param // expected-remark @below {{2}} transform.debug.emit_param_as_remark %p : !transform.param %2 = replicate num(%0) %1 : !transform.any_op, !transform.any_op %p2 = num_associations %2 : (!transform.any_op) -> !transform.param // expected-remark @below {{4}} transform.debug.emit_param_as_remark %p2 : !transform.param } } transform.yield } } // ----- func.func @bar() { // expected-remark @below {{transform applied}} %0 = arith.constant 0 : i32 // expected-remark @below {{transform applied}} %1 = arith.constant 1 : i32 return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @const : benefit(1) { %r = pdl.types %0 = pdl.operation "arith.constant" -> (%r : !pdl.range) pdl.rewrite %0 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %f = pdl_match @const in %arg1 : (!transform.any_op) -> !transform.any_op transform.foreach %f : !transform.any_op { ^bb2(%arg2: !transform.any_op): %p = transform.num_associations %arg2 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p : !transform.param transform.debug.emit_remark_at %arg2, "transform applied" : !transform.any_op } } } transform.yield } } // ----- // CHECK-LABEL: func @consume_in_foreach() // CHECK-NEXT: return func.func @consume_in_foreach() { %0 = arith.constant 0 : index %1 = arith.constant 1 : index %2 = arith.constant 2 : index %3 = arith.constant 3 : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %f = transform.structured.match ops{["arith.constant"]} in %arg1 : (!transform.any_op) -> !transform.any_op transform.foreach %f : !transform.any_op { ^bb2(%arg2: !transform.any_op): // expected-remark @below {{erasing}} transform.test_emit_remark_and_erase_operand %arg2, "erasing" : !transform.any_op } transform.yield } } // ----- 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 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @const : benefit(1) { %r = pdl.types %0 = pdl.operation "arith.constant" -> (%r : !pdl.range) pdl.rewrite %0 with "transform.dialect" } pdl.pattern @execute_region : benefit(1) { %r = pdl.types %0 = pdl.operation "scf.execute_region" -> (%r : !pdl.range) pdl.rewrite %0 with "transform.dialect" } transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %f = pdl_match @execute_region in %arg1 : (!transform.any_op) -> !transform.any_op %results = transform.foreach %f : !transform.any_op -> !transform.any_op { ^bb2(%arg2: !transform.any_op): %g = transform.pdl_match @const in %arg2 : (!transform.any_op) -> !transform.any_op transform.yield %g : !transform.any_op } %p = transform.num_associations %results : (!transform.any_op) -> !transform.param // expected-remark @below {{3}} transform.debug.emit_param_as_remark %p : !transform.param transform.debug.emit_remark_at %results, "transform applied" : !transform.any_op } } transform.yield } } // ----- 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 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %muli = transform.get_producer_of_operand %addi[0] : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %muli, "found muli" : !transform.any_op transform.yield } } // ----- func.func @get_parent_for_op_no_loop(%arg0: index, %arg1: index) { // expected-note @below {{target op}} %0 = arith.muli %arg0, %arg1 : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{could not find a producer for operand number: 0 of}} %bbarg = transform.get_producer_of_operand %muli[0] : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- func.func @get_consumer(%arg0: index, %arg1: index) { %0 = arith.muli %arg0, %arg1 : index // expected-remark @below {{found addi}} arith.addi %0, %arg1 : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op %addi = transform.get_consumers_of_result %muli[0] : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %addi, "found addi" : !transform.any_op transform.yield } } // ----- func.func @get_consumer_fail_1(%arg0: index, %arg1: index) { %0 = arith.muli %arg0, %arg1 : index %1 = arith.muli %arg0, %arg1 : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{handle must be mapped to exactly one payload op}} %bbarg = transform.get_consumers_of_result %muli[0] : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- func.func @get_consumer_fail_2(%arg0: index, %arg1: index) { %0 = arith.muli %arg0, %arg1 : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{result number overflow}} %bbarg = transform.get_consumers_of_result %muli[1] : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- func.func @split_handle(%a: index, %b: index, %c: index) { %0 = arith.muli %a, %b : index %1 = arith.muli %a, %c : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%fun: !transform.any_op) { %muli = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op %h:2 = transform.split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op) %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p : !transform.param %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op // expected-error @below {{expected to contain 3 payload ops but it contains 2 payload ops}} %h_2:3 = transform.split_handle %muli_2 : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op) transform.yield } } // ----- func.func @split_handle(%a: index, %b: index, %c: index) { %0 = arith.muli %a, %b : index %1 = arith.muli %a, %c : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.sequence %root : !transform.any_op failures(suppress) { ^bb1(%fun: !transform.any_op): %muli = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op %h:2 = split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op) %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p : !transform.param %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op // Silenceable failure and all handles are now empty. %h_2:3 = split_handle %muli_2 : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op) %p2 = transform.num_associations %h_2#0 : (!transform.any_op) -> !transform.param // expected-remark @below {{0}} transform.debug.emit_param_as_remark %p2 : !transform.param } transform.yield } } // ----- func.func @split_handle(%a: index, %b: index, %c: index) { %0 = arith.muli %a, %b : index %1 = arith.muli %a, %c : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%fun: !transform.any_op) { %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op // No error, last result handle is empty. %h:3 = transform.split_handle %muli_2 {fail_on_payload_too_small = false} : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op) %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p : !transform.param %p2 = transform.num_associations %h#1 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p2 : !transform.param %p3 = transform.num_associations %h#2 : (!transform.any_op) -> !transform.param // expected-remark @below {{0}} transform.debug.emit_param_as_remark %p3 : !transform.param transform.yield } } // ----- func.func @split_handle(%a: index, %b: index, %c: index) { %0 = arith.muli %a, %b : index %1 = arith.muli %a, %c : index %2 = arith.muli %a, %c : index %3 = arith.muli %a, %c : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%fun: !transform.any_op) { %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op %h:2 = transform.split_handle %muli_2 {overflow_result = 0} : (!transform.any_op) -> (!transform.any_op, !transform.any_op) %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param // expected-remark @below {{3}} transform.debug.emit_param_as_remark %p : !transform.param %p2 = transform.num_associations %h#1 : (!transform.any_op) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p2 : !transform.param transform.yield } } // ----- "test.some_op"() : () -> () "other_dialect.other_op"() : () -> () module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operation "test.some_op" pdl.rewrite %0 with "transform.dialect" } sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op %2 = transform.cast %0 : !transform.any_op to !transform.test_dialect_op transform.cast %2 : !transform.test_dialect_op to !transform.any_op } } transform.yield } } // ----- "test.some_op"() : () -> () "other_dialect.other_op"() : () -> () module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @other : benefit(1) { %0 = pdl.operation "other_dialect.other_op" pdl.rewrite %0 with "transform.dialect" } sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @other in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{expected the payload operation to belong to the 'test' dialect}} %2 = transform.cast %0 : !transform.any_op to !transform.test_dialect_op transform.cast %2 : !transform.test_dialect_op to !transform.any_op } } transform.yield } } // ----- "test.some_op"() : () -> () "other_dialect.other_op"() : () -> () module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @some : benefit(1) { %0 = pdl.operation "test.some_op" pdl.rewrite %0 with "transform.dialect" } sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op %2 = transform.cast %0 : !transform.any_op to !transform.op<"test.some_op"> transform.cast %2 : !transform.op<"test.some_op"> to !transform.any_op } } transform.yield } } // ----- "test.some_op"() : () -> () // expected-note @below {{payload operation}} "other_dialect.other_op"() : () -> () module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): pdl.pattern @other : benefit(1) { %0 = pdl.operation "other_dialect.other_op" pdl.rewrite %0 with "transform.dialect" } sequence %arg0 : !transform.any_op failures(propagate) { ^bb1(%arg1: !transform.any_op): %0 = pdl_match @other in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{incompatible payload operation name}} %2 = transform.cast %0 : !transform.any_op to !transform.op<"test.some_op"> transform.cast %2 : !transform.op<"test.some_op"> to !transform.any_op } } transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.with_pdl_patterns %root : !transform.any_op { ^bb0(%arg0: !transform.any_op): transform.sequence %arg0 : !transform.any_op failures(propagate) { ^bb0(%arg1: !transform.any_op): %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op // here, the handles nested under are {%root, %arg0, %arg1, %0} // expected-remark @below {{4 handles nested under}} transform.test_report_number_of_tracked_handles_nested_under %arg1 : !transform.any_op // expected-remark @below {{erased}} transform.test_emit_remark_and_erase_operand %0, "erased" : !transform.any_op // here, the handles nested under are only {%root, %arg0, %arg1} // expected-remark @below {{3 handles nested under}} transform.test_report_number_of_tracked_handles_nested_under %arg1 : !transform.any_op } pdl.pattern @some : benefit(1) { %0 = pdl.operation "test.some_op" pdl.rewrite %0 with "transform.dialect" } } transform.yield } } "test.some_op"() : () -> () // ----- func.func @split_handle(%a: index, %b: index, %c: index) { %0 = arith.muli %a, %b : index %1 = arith.muli %a, %c : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.sequence %root : !transform.any_op -> !transform.any_op failures(propagate) { ^bb1(%fun: !transform.any_op): %muli = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op // expected-error @below {{expected to contain 3 payload ops but it contains 2 payload ops}} %h_2:3 = split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op) /// Test that yield does not crash in the presence of silenceable error in /// propagate mode. yield %fun : !transform.any_op } transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.sequence %root : !transform.any_op -> !transform.any_op failures(suppress) { ^bb0(%arg0: !transform.any_op): %muli = transform.structured.match ops{["arith.muli"]} in %arg0 : (!transform.any_op) -> !transform.any_op // Edge case propagating empty handles in splitting. %0:3 = split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op) // Test does not crash when accessing the empty handle. yield %0#0 : !transform.any_op } transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_param (0 : i32) : !transform.test_dialect_param // expected-remark @below {{0 : i32}} transform.debug.emit_param_as_remark %0 : !transform.test_dialect_param transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{expected the type of the parameter attribute ('i32') to match the parameter type ('i64')}} transform.test_produce_param (0 : i32) : !transform.param transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%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.debug.emit_param_as_remark %1 : !transform.test_dialect_param transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op %1 = transform.test_produce_param_with_number_of_test_ops %0 : !transform.any_op // expected-remark @below {{1 : i32, 3 : i32}} transform.debug.emit_param_as_remark %1 : !transform.test_dialect_param %2 = transform.test_add_to_param %1, 100 // expected-remark @below {{101 : i32, 103 : i32}} transform.debug.emit_param_as_remark %2 : !transform.test_dialect_param transform.yield } } 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 } // ----- // expected-note @below {{when applied to this op}} module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%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) transform.yield } } // ----- // Should not fail. module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.test_produce_transform_param_or_forward_operand %arg0 { first_result_is_null } : (!transform.any_op) -> (!transform.any_op, !transform.param) transform.yield } } // ----- // expected-note @below {{when applied to this op}} module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%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) transform.yield } } // ----- // expected-note @below {{when applied to this op}} module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{expected to produce a Value for result #0}} transform.test_produce_transform_param_or_forward_operand %arg0 { second_result_is_handle } : (!transform.any_op) -> (!transform.any_value, !transform.param) transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%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.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%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 transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{attempting to assign a null payload value to this transform handle}} %0 = transform.test_produce_null_value : !transform.any_value transform.yield } } // ----- // expected-error @below {{could not find a nested named sequence with name: __transform_main}} // expected-error @below {{could not find transform entry point: __transform_main in either payload or transform module}} module { } // ----- module attributes {transform.with_named_sequence} { // expected-remark @below {{value handle}} // expected-note @below {{value handle points to a block argument #0 in block #0 in region #0}} transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_value_handle_to_self_operand %arg0 : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %0, "value handle" : !transform.any_value transform.yield } } // ----- // expected-remark @below {{result handle}} // expected-note @below {{value handle points to an op result #1}} %0:2 = "test.get_two_results"() : () -> (i32, i32) // expected-remark @below {{result handle}} // expected-note @below {{value handle points to an op result #1}} %1:3 = "test.get_three_results"() : () -> (i32, i32, f32) module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %2 = transform.structured.match ops{["test.get_two_results", "test.get_three_results"]} in %arg0 : (!transform.any_op) -> !transform.any_op %3 = transform.test_produce_value_handle_to_result %2, 1 : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %3, "result handle" : !transform.any_value transform.yield } } // ----- "test.op_with_regions"() ({ ^bb0: "test.regon_terminator"() : () -> () }, { ^bb1: "test.regon_terminator"() : () -> () // expected-remark @below {{block argument handle}} // expected-note @below {{value handle points to a block argument #2 in block #1 in region #1}} ^bb2(%arg0: i32, %arg1: f64, %arg3: index): "test.match_anchor"() : () -> () "test.regon_terminator"() : () -> () }) : () -> () module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %2 = transform.structured.match ops{["test.match_anchor"]} in %arg0 : (!transform.any_op) -> !transform.any_op %3 = transform.test_produce_value_handle_to_argument_of_parent_block %2, 2 : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %3, "block argument handle" : !transform.any_value transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-note @below {{value defined here with type '!transform.test_dialect_param'}} %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op // expected-error @below {{unexpectedly consumed a value that is not a handle as operand #0}} transform.test_consume_operand %0 : !transform.test_dialect_param transform.yield } } // ----- // expected-remark @below {{addi operand}} // expected-note @below {{value handle points to a block argument #0}} func.func @get_operand_of_op(%arg0: index, %arg1: index) -> index { %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %operand = transform.get_operand %addi[0] : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %operand, "addi operand" : !transform.any_value transform.yield } } // ----- func.func @get_out_of_bounds_operand_of_op(%arg0: index, %arg1: index) -> index { // expected-note @below {{while considering positions of this payload operation}} %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{position overflow 2 (updated from 2) for maximum 2}} %operand = transform.get_operand %addi[2] : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %operand, "addi operand" : !transform.any_value transform.yield } } // ----- // expected-remark @below {{addi operand}} // expected-note @below {{value handle points to a block argument #1}} func.func @get_inverted_operand_of_op(%arg0: index, %arg1: index) -> index { %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %operand = transform.get_operand %addi[except(0)] : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %operand, "addi operand" : !transform.any_value transform.yield } } // ----- func.func @get_multiple_operands_of_op(%arg0: index, %arg1: index) -> index { %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addui = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %operands = transform.get_operand %addui[all] : (!transform.any_op) -> !transform.any_value %p = transform.num_associations %operands : (!transform.any_value) -> !transform.param // expected-remark @below {{2}} transform.debug.emit_param_as_remark %p : !transform.param transform.yield } } // ----- func.func @get_result_of_op(%arg0: index, %arg1: index) -> index { // expected-remark @below {{addi result}} // expected-note @below {{value handle points to an op result #0}} %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %result = transform.get_result %addi[0] : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %result, "addi result" : !transform.any_value transform.yield } } // ----- func.func @get_out_of_bounds_result_of_op(%arg0: index, %arg1: index) -> index { // expected-note @below {{while considering positions of this payload operation}} %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{position overflow 1 (updated from 1) for maximum 1}} %result = transform.get_result %addi[1] : (!transform.any_op) -> !transform.any_value transform.debug.emit_remark_at %result, "addi result" : !transform.any_value transform.yield } } // ----- func.func @get_result_of_op(%arg0: index, %arg1: index) -> index { // expected-remark @below {{matched}} %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %result = transform.get_result %addi[0] : (!transform.any_op) -> !transform.any_value %op = transform.get_defining_op %result : (!transform.any_value) -> !transform.any_op transform.debug.emit_remark_at %op, "matched" : !transform.any_op transform.yield } } // ----- func.func @get_multiple_result_of_op(%arg0: index, %arg1: index) -> (index, i1) { %r, %b = arith.addui_extended %arg0, %arg1 : index, i1 return %r, %b : index, i1 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addui = transform.structured.match ops{["arith.addui_extended"]} in %arg1 : (!transform.any_op) -> !transform.any_op %results = transform.get_result %addui[all] : (!transform.any_op) -> !transform.any_value %p = transform.num_associations %results : (!transform.any_value) -> !transform.param // expected-remark @below {{2}} transform.debug.emit_param_as_remark %p : !transform.param transform.yield } } // ----- // expected-note @below {{target value}} func.func @get_result_of_op_bbarg(%arg0: index, %arg1: index) -> index { %r = arith.addi %arg0, %arg1 : index return %r : index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op %bbarg = transform.test_produce_value_handle_to_argument_of_parent_block %addi, 0 : (!transform.any_op) -> !transform.any_value // expected-error @below {{cannot get defining op of block argument}} %op = transform.get_defining_op %bbarg : (!transform.any_value) -> !transform.any_op transform.debug.emit_remark_at %op, "matched" : !transform.any_op transform.yield } } // ----- module @named_inclusion attributes { transform.with_named_sequence } { transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}) -> () { // expected-remark @below {{applying transformation "a"}} transform.test_transform_op "a" transform.yield } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.include @foo failures(propagate) (%arg0) : (!transform.any_op) -> () transform.yield } } // ----- module @named_inclusion_in_named attributes { transform.with_named_sequence } { transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}) -> () { // expected-remark @below {{applying transformation "a"}} transform.test_transform_op "a" transform.yield } transform.named_sequence @bar(%arg0: !transform.any_op {transform.readonly}) -> () { // expected-remark @below {{applying transformation "b"}} transform.test_transform_op "b" transform.include @foo failures(propagate) (%arg0) : (!transform.any_op) -> () transform.yield } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.include @bar failures(suppress) (%arg0) : (!transform.any_op) -> () transform.yield } } // ----- // expected-remark @below {{operation}} module @named_operands attributes { transform.with_named_sequence } { transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}, %arg1: !transform.any_value {transform.readonly}) -> () { transform.debug.emit_remark_at %arg0, "operation" : !transform.any_op transform.debug.emit_remark_at %arg1, "value" : !transform.any_value transform.yield } // expected-remark @below {{value}} // expected-note @below {{value handle points to a block argument #0 in block #0 in region #0}} transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.test_produce_value_handle_to_self_operand %arg0 : (!transform.any_op) -> !transform.any_value transform.include @foo failures(propagate) (%arg0, %0) : (!transform.any_op, !transform.any_value) -> () transform.yield } } // ----- // expected-remark @below {{operation}} module @named_return attributes { transform.with_named_sequence } { // expected-remark @below {{value}} // expected-note @below {{value handle points to a block argument #0 in block #0 in region #0}} transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}) -> (!transform.any_op, !transform.any_value) { %0 = transform.test_produce_value_handle_to_self_operand %arg0 : (!transform.any_op) -> !transform.any_value transform.yield %arg0, %0 : !transform.any_op, !transform.any_value } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0:2 = transform.include @foo failures(propagate) (%arg0) : (!transform.any_op) -> (!transform.any_op, !transform.any_value) transform.debug.emit_remark_at %0#0, "operation" : !transform.any_op transform.debug.emit_remark_at %0#1, "value" : !transform.any_value transform.yield } } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @match1(%current: !transform.any_op {transform.readonly}) -> (!transform.any_op) { transform.test_succeed_if_operand_of_op_kind %current, "test.some_op" : !transform.any_op transform.yield %current : !transform.any_op } transform.named_sequence @match2(%current: !transform.any_op {transform.readonly}) -> (!transform.any_op) { transform.test_succeed_if_operand_of_op_kind %current, "func.func" : !transform.any_op transform.yield %current : !transform.any_op } transform.named_sequence @action1(%current: !transform.any_op {transform.readonly}) { transform.debug.emit_remark_at %current, "matched1" : !transform.any_op transform.yield } transform.named_sequence @action2(%current: !transform.any_op {transform.readonly}) { transform.debug.emit_remark_at %current, "matched2" : !transform.any_op transform.yield } transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.foreach_match in %root @match1 -> @action1, @match2 -> @action2 : (!transform.any_op) -> (!transform.any_op) transform.yield } // expected-remark @below {{matched2}} func.func private @foo() // expected-remark @below {{matched2}} func.func private @bar() "test.testtest"() : () -> () // expected-remark @below {{matched1}} "test.some_op"() : () -> () } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @match(!transform.any_op {transform.readonly}) transform.named_sequence @action() transform.named_sequence @__transform_main(%root: !transform.any_op) { // expected-error @below {{unresolved external symbol @match}} transform.foreach_match in %root @match -> @action : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @match(%arg: !transform.any_op {transform.readonly}) { transform.yield } transform.named_sequence @action() transform.named_sequence @__transform_main(%root: !transform.any_op) { // expected-error @below {{unresolved external symbol @action}} transform.foreach_match in %root @match -> @action : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @match(%arg: !transform.any_op {transform.readonly}) { // expected-error @below {{expected operations in the match part to implement MatchOpInterface}} "test.unknown_op"() : () -> () transform.yield } transform.named_sequence @action() { transform.yield } transform.named_sequence @__transform_main(%root: !transform.any_op) { transform.foreach_match in %root @match -> @action : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @match_func(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @print_func(%arg0: !transform.any_op {transform.readonly}) { transform.debug.emit_remark_at %arg0, "matched func" : !transform.any_op transform.yield } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.foreach_match in %arg0 @match_func -> @print_func : (!transform.any_op) -> !transform.any_op transform.yield } // expected-remark @below {{matched func}} func.func @payload() { return } // expected-remark @below {{matched func}} func.func private @declaration() "test.something_else"() : () -> () } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @eq_1(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param transform.match.param.cmpi eq %0, %1 : !transform.test_dialect_param transform.debug.emit_remark_at %arg0, "matched == 1" : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @ne_0(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op %1 = transform.param.constant 0 : i32 -> !transform.test_dialect_param transform.match.param.cmpi ne %0, %1 : !transform.test_dialect_param transform.debug.emit_remark_at %arg0, "matched != 0" : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @gt_m1(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op %1 = transform.param.constant -1 : i32 -> !transform.test_dialect_param transform.match.param.cmpi gt %0, %1 : !transform.test_dialect_param transform.debug.emit_remark_at %arg0, "matched > -1" : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @ge_1(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param transform.match.param.cmpi ge %0, %1 : !transform.test_dialect_param transform.debug.emit_remark_at %arg0, "matched >= 1" : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @lt_1(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param transform.match.param.cmpi lt %0, %1 : !transform.test_dialect_param transform.debug.emit_remark_at %arg0, "matched < 1" : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @le_1(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["func.func"] : !transform.any_op %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param transform.match.param.cmpi le %0, %1 : !transform.test_dialect_param transform.debug.emit_remark_at %arg0, "matched <= 1" : !transform.any_op transform.yield %arg0 : !transform.any_op } transform.named_sequence @do_nothing(%arg0: !transform.any_op {transform.readonly}) { transform.yield } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.foreach_match in %arg0 @eq_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op %1 = transform.foreach_match in %0 @ne_0 -> @do_nothing : (!transform.any_op) -> !transform.any_op %2 = transform.foreach_match in %1 @gt_m1 -> @do_nothing : (!transform.any_op) -> !transform.any_op %3 = transform.foreach_match in %2 @ge_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op %4 = transform.foreach_match in %3 @lt_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op %5 = transform.foreach_match in %4 @le_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op transform.yield } // expected-remark @below {{matched > -1}} // expected-remark @below {{matched < 1}} // expected-remark @below {{matched <= 1}} func.func private @declaration() // expected-remark @below {{matched == 1}} // expected-remark @below {{matched != 0}} // expected-remark @below {{matched > -1}} // expected-remark @below {{matched >= 1}} // expected-remark @below {{matched <= 1}} func.func @definition() { "test.something"() : () -> () return } } // ----- // CHECK-LABEL: func @test_tracked_rewrite() { // CHECK-NEXT: transform.test_dummy_payload_op {new_op} : () -> i1 // CHECK-NEXT: transform.test_dummy_payload_op {new_op} : () -> i1 // CHECK-NEXT: return // CHECK-NEXT: } func.func @test_tracked_rewrite() { %0 = transform.test_dummy_payload_op {replace_me} : () -> (i1) %1 = transform.test_dummy_payload_op {erase_me} : () -> (i1) %2 = transform.test_dummy_payload_op {replace_me} : () -> (i1) func.return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %0 = transform.structured.match ops{["transform.test_dummy_payload_op"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{2 iterations}} transform.test_tracked_rewrite %0 : (!transform.any_op) -> () // One replacement op (test.drop_mapping) is dropped from the mapping. %p = transform.num_associations %0 : (!transform.any_op) -> !transform.param // expected-remark @below {{2}} transform.debug.emit_param_as_remark %p : !transform.param transform.yield } } // ----- // Parameter deduplication happens by value module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %1 = transform.param.constant 1 -> !transform.param %2 = transform.param.constant 1 -> !transform.param %3 = transform.param.constant 2 -> !transform.param %4 = transform.merge_handles %1, %2 { deduplicate } : !transform.param %p = transform.num_associations %4 : (!transform.param) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p : !transform.param %5 = transform.merge_handles %1, %1 { deduplicate } : !transform.param %p2 = transform.num_associations %5 : (!transform.param) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p2 : !transform.param %6 = transform.merge_handles %1, %3 { deduplicate } : !transform.param %p3 = transform.num_associations %6 : (!transform.param) -> !transform.param // expected-remark @below {{2}} transform.debug.emit_param_as_remark %p3 : !transform.param %7 = transform.merge_handles %1, %1, %2, %3 : !transform.param %p4 = transform.num_associations %7 : (!transform.param) -> !transform.param // expected-remark @below {{4}} transform.debug.emit_param_as_remark %p4 : !transform.param transform.yield } } // ----- %0:3 = "test.get_two_results"() : () -> (i32, i32, f32) module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %1 = transform.structured.match ops{["test.get_two_results"]} in %arg0 : (!transform.any_op) -> !transform.any_op %2 = transform.test_produce_value_handle_to_result %1, 0 : (!transform.any_op) -> !transform.any_value %3 = transform.test_produce_value_handle_to_result %1, 1 : (!transform.any_op) -> !transform.any_value %4 = transform.merge_handles %2, %2 { deduplicate } : !transform.any_value %p = transform.num_associations %4 : (!transform.any_value) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p : !transform.param %5 = transform.merge_handles %2, %3 { deduplicate } : !transform.any_value %p2 = transform.num_associations %5 : (!transform.any_value) -> !transform.param // expected-remark @below {{2}} transform.debug.emit_param_as_remark %p2 : !transform.param %6 = transform.test_produce_value_handle_to_result %1, 0 : (!transform.any_op) -> !transform.any_value %7 = transform.merge_handles %2, %6 { deduplicate } : !transform.any_value %p3 = transform.num_associations %6 : (!transform.any_value) -> !transform.param // expected-remark @below {{1}} transform.debug.emit_param_as_remark %p3 : !transform.param %8 = transform.merge_handles %2, %2, %3, %4 : !transform.any_value %p4 = transform.num_associations %8 : (!transform.any_value) -> !transform.param // expected-remark @below {{4}} transform.debug.emit_param_as_remark %p4 : !transform.param transform.yield } } // ----- // CHECK-LABEL: func @test_annotation() // CHECK-NEXT: "test.annotate_me"() // CHECK-SAME: any_attr = "example" // CHECK-SAME: broadcast_attr = 2 : i64 // CHECK-SAME: new_attr = 1 : i32 // CHECK-SAME: unit_attr // CHECK-NEXT: "test.annotate_me"() // CHECK-SAME: any_attr = "example" // CHECK-SAME: broadcast_attr = 2 : i64 // CHECK-SAME: existing_attr = "test" // CHECK-SAME: new_attr = 1 : i32 // CHECK-SAME: unit_attr // CHECK-NEXT: "test.annotate_me"() // CHECK-SAME: any_attr = "example" // CHECK-SAME: broadcast_attr = 2 : i64 // CHECK-SAME: new_attr = 1 : i32 // CHECK-SAME: unit_attr func.func @test_annotation() { %0 = "test.annotate_me"() : () -> (i1) %1 = "test.annotate_me"() {existing_attr = "test"} : () -> (i1) %2 = "test.annotate_me"() {new_attr = 0} : () -> (i1) } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.structured.match ops{["test.annotate_me"]} in %arg0 : (!transform.any_op) -> !transform.any_op %1 = transform.test_produce_param_with_number_of_test_ops %0 : !transform.any_op transform.annotate %0 "new_attr" = %1 : !transform.any_op, !transform.test_dialect_param %2 = transform.param.constant 2 -> !transform.param transform.annotate %0 "broadcast_attr" = %2 : !transform.any_op, !transform.param transform.annotate %0 "unit_attr" : !transform.any_op %3 = transform.param.constant "example" -> !transform.any_param transform.annotate %0 "any_attr" = %3 : !transform.any_op, !transform.any_param transform.yield } } // ----- func.func @notify_payload_op_replaced(%arg0: index, %arg1: index) { %0 = arith.muli %arg0, %arg1 {original} : index // expected-remark @below{{updated handle}} %1 = arith.muli %arg0, %arg1 {replacement} : index return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %0 = transform.structured.match attributes{original} in %arg1 : (!transform.any_op) -> !transform.any_op %1 = transform.structured.match attributes{replacement} in %arg1 : (!transform.any_op) -> !transform.any_op transform.test_notify_payload_op_replaced %0, %1 : (!transform.any_op, !transform.any_op) -> () transform.debug.emit_remark_at %0, "updated handle" : !transform.any_op transform.yield } } // ----- // CHECK-LABEL: func @test_apply_cse() // CHECK: %[[const:.*]] = arith.constant 0 : index // CHECK: %[[ex1:.*]] = scf.execute_region -> index { // CHECK: scf.yield %[[const]] // CHECK: } // CHECK: %[[ex2:.*]] = scf.execute_region -> index { // CHECK: scf.yield %[[const]] // CHECK: } // CHECK: return %[[const]], %[[ex1]], %[[ex2]] func.func @test_apply_cse() -> (index, index, index) { // expected-remark @below{{eliminated 1}} // expected-remark @below{{eliminated 2}} %0 = arith.constant 0 : index %1 = scf.execute_region -> index { %2 = arith.constant 0 : index scf.yield %2 : index } {first} %3 = scf.execute_region -> index { %4 = arith.constant 0 : index scf.yield %4 : index } {second} return %0, %1, %3 : index, index, index } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %0 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op %first = transform.structured.match attributes{first} in %0 : (!transform.any_op) -> !transform.any_op %elim_first = transform.structured.match ops{["arith.constant"]} in %first : (!transform.any_op) -> !transform.any_op %second = transform.structured.match attributes{first} in %0 : (!transform.any_op) -> !transform.any_op %elim_second = transform.structured.match ops{["arith.constant"]} in %first : (!transform.any_op) -> !transform.any_op // There are 3 arith.constant ops. %all = transform.structured.match ops{["arith.constant"]} in %0 : (!transform.any_op) -> !transform.any_op %p = transform.num_associations %all : (!transform.any_op) -> !transform.param // expected-remark @below{{3}} transform.debug.emit_param_as_remark %p : !transform.param // "deduplicate" has no effect because these are 3 different ops. %merged_before = transform.merge_handles deduplicate %all : !transform.any_op %p2 = transform.num_associations %merged_before : (!transform.any_op) -> !transform.param // expected-remark @below{{3}} transform.debug.emit_param_as_remark %p2 : !transform.param // Apply CSE. transform.apply_cse to %0 : !transform.any_op // The handle is still mapped to 3 arith.constant ops. %p3 = transform.num_associations %all : (!transform.any_op) -> !transform.param // expected-remark @below{{3}} transform.debug.emit_param_as_remark %p3 : !transform.param // But they are all the same op. %merged_after = transform.merge_handles deduplicate %all : !transform.any_op %p4 = transform.num_associations %merged_after : (!transform.any_op) -> !transform.param // expected-remark @below{{1}} transform.debug.emit_param_as_remark %p4 : !transform.param // The other handles were also updated. transform.debug.emit_remark_at %elim_first, "eliminated 1" : !transform.any_op %p5 = transform.num_associations %elim_first : (!transform.any_op) -> !transform.param // expected-remark @below{{1}} transform.debug.emit_param_as_remark %p5 : !transform.param transform.debug.emit_remark_at %elim_second, "eliminated 2" : !transform.any_op %p6 = transform.num_associations %elim_second : (!transform.any_op) -> !transform.param // expected-remark @below{{1}} transform.debug.emit_param_as_remark %p6 : !transform.param transform.yield } } // ----- // CHECK-LABEL: func @test_licm( // CHECK: arith.muli // CHECK: scf.for {{.*}} { // CHECK: vector.print // CHECK: } func.func @test_licm(%arg0: index, %arg1: index, %arg2: index) { scf.for %iv = %arg0 to %arg1 step %arg2 { %0 = arith.muli %arg0, %arg1 : index vector.print %0 : index } return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %0 = transform.structured.match ops{["scf.for"]} in %arg1 : (!transform.any_op) -> !transform.any_op transform.apply_licm to %0 : !transform.any_op transform.yield } } // ----- // expected-note @below{{when applied to this op}} module attributes {transform.with_named_sequence} { func.func @test_licm_invalid() { return } transform.named_sequence @__transform_main(%arg1: !transform.any_op) { // expected-error @below{{transform applied to the wrong op kind}} transform.apply_licm to %arg1 : !transform.any_op transform.yield } } // ----- func.func @get_parent_op() { // expected-remark @below{{found test.foo parent}} "test.foo"() ({ // expected-remark @below{{direct parent}} "test.bar"() ({ "test.qux"() : () -> () "test.qux"() : () -> () }) : () -> () }) : () -> () } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %0 = transform.structured.match ops{["test.qux"]} in %arg1 : (!transform.any_op) -> !transform.any_op // Get parent by name. %1 = transform.get_parent_op %0 {op_name = "test.foo"} : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %1, "found test.foo parent" : !transform.any_op // Get immediate parent. %2 = transform.get_parent_op %0 : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %2, "direct parent" : !transform.any_op %p = transform.num_associations %2 : (!transform.any_op) -> !transform.param // expected-remark @below{{2}} transform.debug.emit_param_as_remark %p : !transform.param // Deduplicate results. %3 = transform.structured.match ops{["test.qux"]} in %arg1 : (!transform.any_op) -> !transform.any_op %4 = transform.get_parent_op %3 {deduplicate} : (!transform.any_op) -> !transform.any_op %p2 = transform.num_associations %4 : (!transform.any_op) -> !transform.param // expected-remark @below{{1}} transform.debug.emit_param_as_remark %p2 : !transform.param transform.yield } } // ----- // expected-note @below {{target op}} module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below{{could not find a parent op that matches all requirements}} %3 = transform.get_parent_op %arg0 {op_name = "builtin.module"} : (!transform.any_op) -> !transform.any_op transform.yield } } // ----- func.func @cast(%arg0: f32) -> f64 { // expected-remark @below{{f64}} %0 = arith.extf %arg0 : f32 to f64 return %0 : f64 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.structured.match ops{["arith.extf"]} in %arg0 : (!transform.any_op) -> !transform.op<"arith.extf"> %1 = transform.get_result %0[0] : (!transform.op<"arith.extf">) -> !transform.any_value %2 = transform.get_type %1 : (!transform.any_value) -> !transform.type transform.debug.emit_param_as_remark %2 at %0 : !transform.type, !transform.op<"arith.extf"> transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{expected type attribute, got 0 : i32}} transform.test_produce_param (0 : i32) : !transform.type transform.yield } } // ----- module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{expected affine map attribute, got 0 : i32}} transform.test_produce_param (0 : i32) : !transform.affine_map transform.yield } } // ----- // CHECK-LABEL: @type_param_anchor func.func private @type_param_anchor() module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // CHECK: test_produce_param(f32) : !transform.type transform.test_produce_param(f32) : !transform.type transform.yield } } // ----- // CHECK-LABEL: @affine_map_param_anchor func.func private @affine_map_param_anchor() module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // CHECK: test_produce_param(#{{.*}}) : !transform.affine_map transform.test_produce_param(affine_map<(d0) -> ()>) : !transform.affine_map transform.yield } } // ----- func.func @verify_success(%arg0: f64) -> f64 { return %arg0 : f64 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op transform.verify %0 : !transform.any_op transform.yield } } // ----- // expected-error @below{{fail_to_verify is set}} // expected-note @below{{payload op}} func.func @verify_failure(%arg0: f64) -> f64 { return %arg0 : f64 } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op transform.test_produce_invalid_ir %0 : !transform.any_op // expected-error @below{{failed to verify payload op}} transform.verify %0 : !transform.any_op transform.yield } } // ----- func.func @select() { // expected-remark @below{{found foo}} "test.foo"() : () -> () // expected-remark @below{{found bar}} "test.bar"() : () -> () // expected-remark @below{{found foo}} "test.foo"() : () -> () func.return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // Match all ops inside the function (including the function itself). %func_op = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op %0 = transform.structured.match in %func_op : (!transform.any_op) -> !transform.any_op %p = transform.num_associations %0 : (!transform.any_op) -> !transform.param // expected-remark @below{{5}} transform.debug.emit_param_as_remark %p : !transform.param // Select "test.foo". %foo = transform.select "test.foo" in %0 : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %foo, "found foo" : !transform.any_op // Select "test.bar". %bar = transform.select "test.bar" in %0 : (!transform.any_op) -> !transform.any_op transform.debug.emit_remark_at %bar, "found bar" : !transform.any_op transform.yield } } // ----- // CHECK-LABEL: func @apply_dce( // CHECK-NEXT: memref.store // CHECK-NEXT: return func.func @apply_dce(%f: f32, %m: memref<5xf32>, %idx: index) { // Two dead ops, interleaved with a non-dead op. %0 = tensor.empty() : tensor<5xf32> memref.store %f, %m[%idx] : memref<5xf32> %1 = tensor.insert %f into %0[%idx] : tensor<5xf32> return } module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { %func_op = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op %empty_op = transform.structured.match ops{["tensor.empty"]} in %func_op : (!transform.any_op) -> !transform.any_op transform.apply_dce to %func_op : !transform.any_op %p = transform.num_associations %empty_op : (!transform.any_op) -> !transform.param // expected-remark @below{{0}} transform.debug.emit_param_as_remark %p : !transform.param transform.yield } } // ----- func.func @no_constant_under_loop(%lb: index, %ub: index, %step: index) { scf.for %i= %lb to %ub step %step { arith.constant 0 : index } return } module @named_inclusion attributes { transform.with_named_sequence } { // Match `arith.constant`s that are not nested under a `scf.for` and ensure // there are none in the program transform.named_sequence @print(%root: !transform.any_op {transform.readonly}) { transform.debug.emit_remark_at %root, "matched func" : !transform.any_op transform.yield } transform.named_sequence @match_constant_not_under_scf_for(%root: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %root ["arith.constant"] : !transform.any_op %for = transform.get_parent_op %root { op_name = "scf.for", allow_empty_results } : (!transform.any_op) -> (!transform.any_op) transform.match.operation_empty %for : !transform.any_op transform.yield %root : !transform.any_op } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.foreach_match in %arg0 @match_constant_not_under_scf_for -> @print : (!transform.any_op) -> (!transform.any_op) transform.yield } } // ----- func.func @no_constant_under_loop(%lb: index, %ub: index, %step: index) { // expected-remark @below {{no parent scf.for}} arith.constant 0 : index return } module @named_inclusion attributes { transform.with_named_sequence } { // Match `arith.constant`s that are not nested under a `scf.for` and ensure // there are none in the program transform.named_sequence @print(%root: !transform.any_op {transform.readonly}) { transform.debug.emit_remark_at %root, "no parent scf.for" : !transform.any_op transform.yield } transform.named_sequence @match_constant_not_under_scf_for(%root: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %root ["arith.constant"] : !transform.any_op %for = transform.get_parent_op %root { op_name = "scf.for", allow_empty_results } : (!transform.any_op) -> (!transform.any_op) transform.match.operation_empty %for : !transform.any_op transform.yield %root : !transform.any_op } transform.named_sequence @__transform_main(%arg0: !transform.any_op) { transform.foreach_match in %arg0 @match_constant_not_under_scf_for -> @print : (!transform.any_op) -> (!transform.any_op) transform.yield } } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{result #0, associated with 2 payload objects, expected 1}} transform.collect_matching @matcher in %arg0 : (!transform.any_op) -> !transform.any_op transform.yield } transform.named_sequence @matcher(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { %0 = transform.merge_handles %arg0, %arg0 : !transform.any_op transform.yield %0 : !transform.any_op } } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-error @below {{unresolved external symbol @matcher}} transform.collect_matching @matcher in %arg0 : (!transform.any_op) -> !transform.any_op transform.yield } transform.named_sequence @matcher(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op } // ----- module attributes { transform.with_named_sequence } { transform.named_sequence @__transform_main(%arg0: !transform.any_op) { // expected-remark @below {{matched}} %0 = transform.collect_matching @matcher in %arg0 : (!transform.any_op) -> !transform.any_op // expected-remark @below {{matched}} transform.debug.emit_remark_at %0, "matched" : !transform.any_op transform.yield } transform.named_sequence @matcher(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op { transform.match.operation_name %arg0 ["transform.debug.emit_remark_at", "transform.collect_matching"] : !transform.any_op transform.yield %arg0 : !transform.any_op } }