156 lines · plain
1// RUN: mlir-opt --allow-unregistered-dialect -verify-diagnostics -ownership-based-buffer-deallocation=private-function-dynamic-ownership=false \2// RUN: --buffer-deallocation-simplification -split-input-file %s | FileCheck %s3// RUN: mlir-opt --allow-unregistered-dialect -verify-diagnostics -ownership-based-buffer-deallocation=private-function-dynamic-ownership=true \4// RUN: --buffer-deallocation-simplification -split-input-file %s | FileCheck %s --check-prefix=CHECK-DYNAMIC5 6// RUN: mlir-opt %s -buffer-deallocation-pipeline --split-input-file > /dev/null7// RUN: mlir-opt %s -buffer-deallocation-pipeline=private-function-dynamic-ownership --split-input-file > /dev/null8 9// Test Case: Existing AllocOp with no users.10// BufferDeallocation expected behavior: It should insert a DeallocOp right11// before ReturnOp.12 13func.func private @emptyUsesValue(%arg0: memref<4xf32>) {14 %0 = memref.alloc() : memref<4xf32>15 "test.read_buffer"(%0) : (memref<4xf32>) -> ()16 return17}18 19// CHECK-LABEL: func private @emptyUsesValue(20// CHECK: [[ALLOC:%.*]] = memref.alloc()21// CHECK: bufferization.dealloc ([[ALLOC]] :22// CHECK-SAME: if (%true{{[0-9_]*}}) 23// CHECK-NOT: retain24// CHECK-NEXT: return25 26// CHECK-DYNAMIC-LABEL: func private @emptyUsesValue(27// CHECK-DYNAMIC-SAME: [[ARG0:%.+]]: memref<4xf32>)28// CHECK-DYNAMIC: [[ALLOC:%.*]] = memref.alloc()29// CHECK-DYNAMIC-NEXT: "test.read_buffer"30// CHECK-DYNAMIC-NEXT: bufferization.dealloc ([[ALLOC]] :{{.*}}) if (%true{{[0-9_]*}}) 31// CHECK-DYNAMIC-NOT: retain32// CHECK-DYNAMIC-NEXT: return33 34// -----35 36func.func @emptyUsesValue(%arg0: memref<4xf32>) {37 %0 = memref.alloc() : memref<4xf32>38 "test.read_buffer"(%0) : (memref<4xf32>) -> ()39 return40}41 42// CHECK-LABEL: func @emptyUsesValue(43 44// CHECK-DYNAMIC-LABEL: func @emptyUsesValue(45// CHECK-DYNAMIC: [[ALLOC:%.*]] = memref.alloc()46// CHECK-DYNAMIC: bufferization.dealloc ([[ALLOC]] :{{.*}}) if (%true{{[0-9_]*}}) 47// CHECK-DYNAMIC-NOT: retain48// CHECK-DYNAMIC-NEXT: return49 50// -----51 52// Test Case: Dead operations in a single block.53// BufferDeallocation expected behavior: It only inserts the two missing54// DeallocOps after the last BufferBasedOp.55 56func.func private @redundantOperations(%arg0: memref<2xf32>) {57 %0 = memref.alloc() : memref<2xf32>58 test.buffer_based in(%arg0: memref<2xf32>) out(%0: memref<2xf32>)59 %1 = memref.alloc() : memref<2xf32>60 test.buffer_based in(%0: memref<2xf32>) out(%1: memref<2xf32>)61 return62}63 64// CHECK-LABEL: func private @redundantOperations65// CHECK: (%[[ARG0:.*]]: {{.*}})66// CHECK: %[[FIRST_ALLOC:.*]] = memref.alloc()67// CHECK-NEXT: test.buffer_based68// CHECK: %[[SECOND_ALLOC:.*]] = memref.alloc()69// CHECK-NEXT: test.buffer_based70// CHECK-NEXT: bufferization.dealloc (%[[FIRST_ALLOC]] : {{.*}}) if (%true{{[0-9_]*}})71// CHECK-NEXT: bufferization.dealloc (%[[SECOND_ALLOC]] : {{.*}}) if (%true{{[0-9_]*}})72// CHECK-NEXT: return73 74// CHECK-DYNAMIC-LABEL: func private @redundantOperations75// CHECK-DYNAMIC: (%[[ARG0:.*]]: memref{{.*}})76// CHECK-DYNAMIC: %[[FIRST_ALLOC:.*]] = memref.alloc()77// CHECK-DYNAMIC-NEXT: test.buffer_based78// CHECK-DYNAMIC: %[[SECOND_ALLOC:.*]] = memref.alloc()79// CHECK-DYNAMIC-NEXT: test.buffer_based80// CHECK-DYNAMIC-NEXT: bufferization.dealloc (%[[FIRST_ALLOC]] : {{.*}}) if (%true{{[0-9_]*}})81// CHECK-DYNAMIC-NEXT: bufferization.dealloc (%[[SECOND_ALLOC]] : {{.*}}) if (%true{{[0-9_]*}})82// CHECK-DYNAMIC-NEXT: return83 84// -----85 86// Test Case: buffer deallocation escaping87// BufferDeallocation expected behavior: It must not dealloc %arg1 and %x88// since they are operands of return operation and should escape from89// deallocating. It should dealloc %y after CopyOp.90 91func.func private @memref_in_function_results(92 %arg0: memref<5xf32>,93 %arg1: memref<10xf32>,94 %arg2: memref<5xf32>) -> (memref<10xf32>, memref<15xf32>) {95 %x = memref.alloc() : memref<15xf32>96 %y = memref.alloc() : memref<5xf32>97 test.buffer_based in(%arg0: memref<5xf32>) out(%y: memref<5xf32>)98 test.copy(%y, %arg2) : (memref<5xf32>, memref<5xf32>)99 return %arg1, %x : memref<10xf32>, memref<15xf32>100}101 102// CHECK-LABEL: func private @memref_in_function_results103// CHECK: (%[[ARG0:.*]]: memref<5xf32>, %[[ARG1:.*]]: memref<10xf32>,104// CHECK-SAME: %[[RESULT:.*]]: memref<5xf32>)105// CHECK: %[[X:.*]] = memref.alloc()106// CHECK: %[[Y:.*]] = memref.alloc()107// CHECK: test.copy108// CHECK-NEXT: %[[V0:.+]] = scf.if %false109// CHECK-NEXT: scf.yield %[[ARG1]]110// CHECK-NEXT: } else {111// CHECK-NEXT: %[[CLONE:.+]] = bufferization.clone %[[ARG1]]112// CHECK-NEXT: scf.yield %[[CLONE]]113// CHECK-NEXT: }114// CHECK: bufferization.dealloc (%[[Y]] : {{.*}}) if (%true{{[0-9_]*}})115// CHECK-NOT: retain116// CHECK: return %[[V0]], %[[X]]117 118// CHECK-DYNAMIC-LABEL: func private @memref_in_function_results119// CHECK-DYNAMIC: (%[[ARG0:.*]]: memref<5xf32>, %[[ARG1:.*]]: memref<10xf32>,120// CHECK-DYNAMIC-SAME: %[[RESULT:.*]]: memref<5xf32>)121// CHECK-DYNAMIC: %[[X:.*]] = memref.alloc()122// CHECK-DYNAMIC: %[[Y:.*]] = memref.alloc()123// CHECK-DYNAMIC: test.copy124// CHECK-DYNAMIC: bufferization.dealloc (%[[Y]] : {{.*}}) if (%true{{[0-9_]*}})125// CHECK-DYNAMIC-NOT: retain126// CHECK-DYNAMIC: return %[[ARG1]], %[[X]], %false, %true127 128// -----129 130// CHECK-DYNAMIC-LABEL: func private @private_callee(131// CHECK-DYNAMIC-SAME: %[[arg0:.*]]: memref<f32>) -> (memref<f32>, i1)132// CHECK-DYNAMIC: %[[true:.*]] = arith.constant true133// CHECK-DYNAMIC: %[[alloc:.*]] = memref.alloc() : memref<f32>134// CHECK-DYNAMIC-NOT: bufferization.dealloc135// CHECK-DYNAMIC: return %[[alloc]], %[[true]]136func.func private @private_callee(%arg0: memref<f32>) -> memref<f32> {137 %alloc = memref.alloc() : memref<f32>138 return %alloc : memref<f32>139}140 141// CHECK-DYNAMIC: func @caller() -> f32142// CHECK-DYNAMIC: %[[true:.*]] = arith.constant true143// CHECK-DYNAMIC: %[[alloc:.*]] = memref.alloc() : memref<f32>144// CHECK-DYNAMIC: %[[call:.*]]:2 = call @private_callee(%[[alloc]])145// CHECK-DYNAMIC: memref.load146// CHECK-DYNAMIC: %[[base:.*]], %[[offset:.*]] = memref.extract_strided_metadata %[[call]]#0147// CHECK-DYNAMIC: bufferization.dealloc (%[[alloc]], %[[base]] : {{.*}}) if (%[[true]], %[[call]]#1)148// CHECK-DYNAMIC-NOT: retain149func.func @caller() -> (f32) {150 %alloc = memref.alloc() : memref<f32>151 %ret = call @private_callee(%alloc) : (memref<f32>) -> memref<f32>152 153 %val = memref.load %ret[] : memref<f32>154 return %val : f32155}156