blob: 742c5dcc78f608f7709d481a1ee214a830399a61 [file] [log] [blame]
// RUN: mlir-opt %s --transform-dialect-check-uses --split-input-file --verify-diagnostics
func.func @use_after_free_branching_control_flow() {
// expected-note @below {{allocated here}}
%0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
transform.test_transform_op_with_regions {
"transform.test_branching_transform_op_terminator"() : () -> ()
},
{
^bb0:
"transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> ()
^bb1:
// expected-note @below {{freed here}}
transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
"transform.test_branching_transform_op_terminator"()[^bb3] : () -> ()
^bb2:
"transform.test_branching_transform_op_terminator"()[^bb3] : () -> ()
^bb3:
// expected-warning @below {{operand #0 may be used after free}}
transform.sequence %0 : !transform.any_op failures(propagate) {
^bb0(%arg0: !transform.any_op):
}
"transform.test_branching_transform_op_terminator"() : () -> ()
}
return
}
// -----
func.func @use_after_free_in_nested_op() {
// expected-note @below {{allocated here}}
%0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
// expected-note @below {{freed here}}
transform.test_transform_op_with_regions {
"transform.test_branching_transform_op_terminator"() : () -> ()
},
{
^bb0:
"transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> ()
^bb1:
transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
"transform.test_branching_transform_op_terminator"()[^bb3] : () -> ()
^bb2:
"transform.test_branching_transform_op_terminator"()[^bb3] : () -> ()
^bb3:
"transform.test_branching_transform_op_terminator"() : () -> ()
}
// expected-warning @below {{operand #0 may be used after free}}
transform.sequence %0 : !transform.any_op failures(propagate) {
^bb0(%arg0: !transform.any_op):
}
return
}
// -----
func.func @use_after_free_recursive_side_effects() {
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-note @below {{allocated here}}
%0 = transform.sequence %arg0 : !transform.any_op -> !transform.any_op failures(propagate) attributes { ord = 1 } {
^bb1(%arg1: !transform.any_op):
yield %arg1 : !transform.any_op
}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 2 } {
^bb2(%arg2: !transform.any_op):
}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 3 } {
^bb3(%arg3: !transform.any_op):
}
// `transform.sequence` has recursive side effects so it has the same "free"
// as the child op it contains.
// expected-note @below {{freed here}}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 4 } {
^bb4(%arg4: !transform.any_op):
test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op
}
// expected-warning @below {{operand #0 may be used after free}}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 5 } {
^bb3(%arg3: !transform.any_op):
}
}
return
}
// -----
func.func @use_after_free() {
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
// expected-note @below {{allocated here}}
%0 = transform.sequence %arg0 : !transform.any_op -> !transform.any_op failures(propagate) attributes { ord = 1 } {
^bb1(%arg1: !transform.any_op):
yield %arg1 : !transform.any_op
}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 2 } {
^bb2(%arg2: !transform.any_op):
}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 3 } {
^bb3(%arg3: !transform.any_op):
}
// expected-note @below {{freed here}}
test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op
// expected-warning @below {{operand #0 may be used after free}}
transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 5 } {
^bb3(%arg3: !transform.any_op):
}
}
return
}
// -----
// In the case of a control flow cycle, the operation that uses the value may
// precede the one that frees it in the same block. Both operations should
// be reported as use-after-free.
func.func @use_after_free_self_cycle() {
// expected-note @below {{allocated here}}
%0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
transform.test_transform_op_with_regions {
"transform.test_branching_transform_op_terminator"() : () -> ()
},
{
^bb0:
"transform.test_branching_transform_op_terminator"()[^bb1] : () -> ()
^bb1:
// expected-warning @below {{operand #0 may be used after free}}
transform.sequence %0 : !transform.any_op failures(propagate) {
^bb0(%arg0: !transform.any_op):
}
// expected-warning @below {{operand #0 may be used after free}}
// expected-note @below {{freed here}}
transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
"transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> ()
^bb2:
"transform.test_branching_transform_op_terminator"() : () -> ()
}
return
}
// -----
// Check that the "free" that happens in a cycle is also reported as potential
// use-after-free.
func.func @use_after_free_cycle() {
// expected-note @below {{allocated here}}
%0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
transform.test_transform_op_with_regions {
"transform.test_branching_transform_op_terminator"() : () -> ()
},
{
^bb0:
"transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> ()
^bb1:
// expected-warning @below {{operand #0 may be used after free}}
// expected-note @below {{freed here}}
transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
"transform.test_branching_transform_op_terminator"()[^bb2, ^bb3] : () -> ()
^bb2:
"transform.test_branching_transform_op_terminator"()[^bb1] : () -> ()
^bb3:
"transform.test_branching_transform_op_terminator"() : () -> ()
}
return
}
// -----
// This should not crash.
transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op):
alternatives %arg0 : !transform.any_op {
^bb0(%arg1: !transform.any_op):
}
}