| // RUN: mlir-opt -test-tensor-transform-patterns=test-tracking-listener \ |
| // RUN: -split-input-file -verify-diagnostics %s |
| |
| func.func @replace_op_with_op_of_same_type() { |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| // expected-remark @below {{replacement found}} |
| %1 = "test.foo"() {replacement_0 = 0} : () -> (tensor<5xf32>) |
| return |
| } |
| |
| // ----- |
| |
| func.func @replace_op_with_op_of_different_type() { |
| // expected-error @below {{listener could not find replacement op}} |
| %0 = tensor.empty() {replaced} : tensor<5xf32> |
| %1 = "test.foo"() {replacement_0 = 0} : () -> (tensor<5xf32>) |
| return |
| } |
| |
| // ----- |
| |
| func.func @multi_result_replacement() { |
| %0:2 = "test.foo"() {replaced} : () -> (tensor<5xf32>, tensor<6xf32>) |
| // expected-remark @below {{replacement found}} |
| %1:2 = "test.foo"() {replacement_0 = 0, replacement_1 = 1} |
| : () -> (tensor<5xf32>, tensor<6xf32>) |
| return |
| } |
| |
| // ----- |
| |
| func.func @multi_result_replacement_with_multiple_ops() { |
| // expected-error @below {{listener could not find replacement op}} |
| %0:2 = "test.foo"() {replaced} : () -> (tensor<5xf32>, tensor<6xf32>) |
| %1:2 = "test.foo"() {replacement_0 = 0} : () -> (tensor<5xf32>, tensor<6xf32>) |
| %2:2 = "test.foo"() {replacement_1 = 1} : () -> (tensor<5xf32>, tensor<6xf32>) |
| return |
| } |
| |
| // ----- |
| |
| func.func @replacement_wrapped_in_cast() { |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| // expected-remark @below {{replacement found}} |
| %1 = "test.foo"() : () -> (tensor<?xf32>) |
| %2 = tensor.cast %1 {replacement_0 = 0} : tensor<?xf32> to tensor<5xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @replacement_wrapped_in_chain_of_casts() { |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| // expected-remark @below {{replacement found}} |
| %1 = "test.foo"() : () -> (tensor<?xf32>) |
| %2 = tensor.cast %1 : tensor<?xf32> to tensor<5xf32> |
| %3 = tensor.cast %2 : tensor<5xf32> to tensor<?xf32> |
| %4 = tensor.cast %3 {replacement_0 = 0} : tensor<?xf32> to tensor<5xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @cast_like_insert_slice(%t: tensor<1x5xf32>) { |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| // expected-remark @below {{replacement found}} |
| %1 = "test.foo"() : () -> (tensor<5xf32>) |
| %2 = tensor.insert_slice %1 into %t[0, 0][1, 5][1, 1] {replacement_0 = 0} |
| : tensor<5xf32> into tensor<1x5xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @non_cast_like_insert_slice(%t: tensor<7xf32>) { |
| // expected-error @below {{listener could not find replacement op}} |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| %1 = "test.foo"() : () -> (tensor<5xf32>) |
| // This is not a cast-like insert_slice op because elements from %t are |
| // contained in %2. |
| %2 = tensor.insert_slice %1 into %t[0][5][1] {replacement_0 = 0} |
| : tensor<5xf32> into tensor<7xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @cast_like_insert_slice_dynamic( |
| %t: tensor<1x?x1xf32>, %f: f32, %pos: index) { |
| %c0 = arith.constant 0 : index |
| %0 = tensor.insert %f into %t[%c0, %pos, %c0] {replaced} : tensor<1x?x1xf32> |
| |
| // Rank reduction |
| %c1 = arith.constant 1 : index |
| %dim1 = tensor.dim %t, %c1 : tensor<1x?x1xf32> |
| %1 = tensor.extract_slice %t[0, 0, 0][1, %dim1, 1][1, 1, 1] |
| : tensor<1x?x1xf32> to tensor<?xf32> |
| // expected-remark @below {{replacement found}} |
| %2 = tensor.insert %f into %1[%c0] : tensor<?xf32> |
| // Rank expansion |
| // Throw in a wrench: Do not use %dim1 directly, but another SSA value that |
| // has the same runtime value. |
| %dim1b = tensor.dim %1, %c0 : tensor<?xf32> |
| %3 = tensor.insert_slice %2 into %t[0, 0, 0][1, %dim1b, 1][1, 1, 1] |
| {replacement_0 = 0} : tensor<?xf32> into tensor<1x?x1xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @cast_like_extract_slice() { |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| // expected-remark @below {{replacement found}} |
| %1 = "test.foo"() : () -> (tensor<1x5x1x1xf32>) |
| %2 = tensor.extract_slice %1[0, 0, 0, 0][1, 5, 1, 1][1, 1, 1, 1] |
| {replacement_0 = 0} : tensor<1x5x1x1xf32> to tensor<5xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @cast_like_extract_slice_dynamic() { |
| %0 = "test.foo"() {replaced} : () -> (tensor<?xf32>) |
| // expected-remark @below {{replacement found}} |
| %1 = "test.foo"() : () -> (tensor<1x?x1x1xf32>) |
| %c1 = arith.constant 1 : index |
| %dim = tensor.dim %1, %c1 : tensor<1x?x1x1xf32> |
| %2 = tensor.extract_slice %1[0, 0, 0, 0][1, %dim, 1, 1][1, 1, 1, 1] |
| {replacement_0 = 0} : tensor<1x?x1x1xf32> to tensor<?xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @non_cast_like_extract_slice() { |
| // expected-error @below {{listener could not find replacement op}} |
| %0 = "test.foo"() {replaced} : () -> (tensor<5xf32>) |
| %1 = "test.foo"() : () -> (tensor<1x5x1x1xf32>) |
| %2 = tensor.extract_slice %1[0, 0, 0, 0][1, 3, 1, 1][1, 1, 1, 1] |
| {replacement_0 = 0} : tensor<1x5x1x1xf32> to tensor<3xf32> |
| return |
| } |
| |
| // ----- |
| |
| func.func @non_cast_like_extract_slice_drop_non_unit_dim() { |
| // expected-error @below {{listener could not find replacement op}} |
| %0 = "test.foo"() {replaced} : () -> (tensor<f32>) |
| %1 = "test.foo"() : () -> (tensor<1x5x1x1xf32>) |
| %2 = tensor.extract_slice %1[0, 0, 0, 0][1, 1, 1, 1][1, 1, 1, 1] |
| {replacement_0 = 0} : tensor<1x5x1x1xf32> to tensor<f32> |
| return |
| } |