1// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 " -drop-equivalent-buffer-results -split-input-file | FileCheck %s 2// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 " -split-input-file | FileCheck %s --check-prefix=NO-DROP 3 4// Run fuzzer with different seeds. 5// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23" -split-input-file -o /dev/null 6// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=59" -split-input-file -o /dev/null 7// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91" -split-input-file -o /dev/null 8 9// Test bufferization using memref types that have no layout map. 10// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 unknown-type-conversion=identity-layout-map function-boundary-type-conversion=identity-layout-map" -split-input-file -o /dev/null 11 12// Make sure that the returned buffer is not deallocated. 13// TODO: Such buffers currently leak. We need buffer hoisting / ref counting for 14// this in the future. 15 16// CHECK-LABEL: func @create_tensor() -> memref<10xf32> { 17// CHECK: %[[alloc:.*]] = memref.alloc 18// CHECK: return %[[alloc]] 19func.func @create_tensor() -> tensor<10xf32> { 20 %0 = bufferization.alloc_tensor() : tensor<10xf32> 21 return %0 : tensor<10xf32> 22} 23 24// CHECK: func @caller( 25// CHECK: %[[call:.*]] = call @create_tensor() : () -> memref<10xf32> 26// CHECK: %[[extracted:.*]] = memref.load %[[call]] 27// CHECK: return %[[extracted]] 28func.func @caller(%idx: index) -> f32 { 29 %0 = call @create_tensor() : () -> (tensor<10xf32>) 30 %1 = tensor.extract %0[%idx] : tensor<10xf32> 31 return %1 : f32 32} 33 34// ----- 35 36// return_slice returns an aliasing tensor. In main, %t is overwritten (but not 37// read). This is a conflict because %0 is aliasing with %t. An alloc + copy is 38// needed. 39 40// CHECK-LABEL: func @return_slice( 41// CHECK-NOT: alloc 42// CHECK-NOT: copy 43// CHECK: memref.subview 44func.func @return_slice(%t: tensor<?xf32>, %sz: index) -> (tensor<?xf32>) { 45 %0 = tensor.extract_slice %t[4][%sz][1] : tensor<?xf32> to tensor<?xf32> 46 return %0 : tensor<?xf32> 47} 48 49// CHECK-LABEL: func @main( 50// CHECK-SAME: %[[t:.*]]: memref<?xf32 51// CHECK: %[[call:.*]] = call @return_slice(%[[t]] 52// CHECK: %[[alloc:.*]] = memref.alloc 53// CHECK: memref.copy %[[call]], %[[alloc]] 54// CHECK: linalg.fill ins({{.*}}) outs(%[[t]] 55// CHECK: memref.load %[[alloc]] 56// CHECK: memref.load %[[t]] 57func.func @main(%t: tensor<?xf32>, %sz: index, %idx: index) -> (f32, f32) { 58 %cst = arith.constant 1.0 : f32 59 %0 = call @return_slice(%t, %sz) : (tensor<?xf32>, index) -> (tensor<?xf32>) 60 %filled = linalg.fill ins(%cst : f32) outs(%t : tensor<?xf32>) -> tensor<?xf32> 61 %r1 = tensor.extract %0[%idx] : tensor<?xf32> 62 %r2 = tensor.extract %filled[%idx] : tensor<?xf32> 63 return %r1, %r2 : f32, f32 64} 65 66// ----- 67 68func.func @return_arg(%A: tensor<?xf32>) -> tensor<?xf32> { 69 func.return %A : tensor<?xf32> 70} 71// CHECK-LABEL: func @return_arg 72// CHECK-SAME: %[[A:.*]]: memref<?xf32 73// CHECK-NOT: return %[[A]] 74 75// NO-DROP-LABEL: func @return_arg 76// NO-DROP-SAME: %[[A:.*]]: memref<?xf32 77// NO-DROP: return %[[A]] 78