Reading from tensor.empty or bufferization.alloc_tensor (without copy) cannot cause a conflict because these ops do not specify the contents of their result tensors. Differential Revision: https://reviews.llvm.org/D143183
59 lines
2.4 KiB
MLIR
59 lines
2.4 KiB
MLIR
// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only" -allow-unregistered-dialect -split-input-file | FileCheck %s
|
|
|
|
// CHECK-LABEL: func @unknown_op_aliasing(
|
|
func.func @unknown_op_aliasing(%f: f32, %f2: f32, %pos: index) -> f32 {
|
|
%0 = tensor.empty() : tensor<10xf32>
|
|
// CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}
|
|
%1 = linalg.fill ins(%f : f32) outs(%0 : tensor<10xf32>) -> tensor<10xf32>
|
|
|
|
// Something must bufferize out-of-place because the op may return an alias
|
|
// of %1.
|
|
// CHECK: "dummy.dummy_op"(%{{.*}}) {__inplace_operands_attr__ = ["false"]}
|
|
%alias = "dummy.dummy_op"(%1) : (tensor<10xf32>) -> (tensor<10xf32>)
|
|
|
|
// CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}
|
|
%2 = linalg.fill ins(%f2 : f32) outs(%1 : tensor<10xf32>) -> tensor<10xf32>
|
|
%3 = tensor.extract %alias[%pos] : tensor<10xf32>
|
|
return %3 : f32
|
|
}
|
|
|
|
// -----
|
|
|
|
// CHECK-LABEL: func @unknown_op_writing(
|
|
func.func @unknown_op_writing(%f: f32, %f2: f32, %pos: index) -> f32 {
|
|
%0 = tensor.empty() : tensor<10xf32>
|
|
// CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}
|
|
%1 = linalg.fill ins(%f : f32) outs(%0 : tensor<10xf32>) -> tensor<10xf32>
|
|
|
|
// The op may bufferize to a memory write, so it must bufferize out-of-place.
|
|
// CHECK: "dummy.dummy_op"(%{{.*}}) {__inplace_operands_attr__ = ["false"]}
|
|
"dummy.dummy_op"(%1) : (tensor<10xf32>) -> ()
|
|
|
|
%3 = tensor.extract %1[%pos] : tensor<10xf32>
|
|
return %3 : f32
|
|
}
|
|
|
|
// -----
|
|
|
|
// CHECK-LABEL: func @read_of_undef_is_not_a_conflict(
|
|
func.func @read_of_undef_is_not_a_conflict(%f: f32, %idx: index) -> f32 {
|
|
%0 = tensor.empty() : tensor<10xf32>
|
|
// This can be in-place because the read below does reads undefined data.
|
|
// CHECK: tensor.insert {{.*}} {__inplace_operands_attr__ = ["none", "true", "none"]}
|
|
%1 = tensor.insert %f into %0[%idx] : tensor<10xf32>
|
|
%2 = tensor.extract %0[%idx] : tensor<10xf32>
|
|
return %2 : f32
|
|
}
|
|
|
|
// -----
|
|
|
|
// CHECK-LABEL: func @read_of_alloc_tensor_is_not_a_conflict(
|
|
func.func @read_of_alloc_tensor_is_not_a_conflict(%f: f32, %idx: index) -> f32 {
|
|
%0 = bufferization.alloc_tensor() : tensor<10xf32>
|
|
// This can be in-place because the read below does reads undefined data.
|
|
// CHECK: tensor.insert {{.*}} {__inplace_operands_attr__ = ["none", "true", "none"]}
|
|
%1 = tensor.insert %f into %0[%idx] : tensor<10xf32>
|
|
%2 = tensor.extract %0[%idx] : tensor<10xf32>
|
|
return %2 : f32
|
|
}
|