101334d1aSMartin Erhart// RUN: mlir-opt -verify-diagnostics -ownership-based-buffer-deallocation \
201334d1aSMartin Erhart// RUN:   --buffer-deallocation-simplification -split-input-file %s | FileCheck %s
36a651c7fSMartin Erhart// RUN: mlir-opt -verify-diagnostics -ownership-based-buffer-deallocation=private-function-dynamic-ownership=true -split-input-file %s > /dev/null
401334d1aSMartin Erhart
508b7a71bSMartin Erhart// RUN: mlir-opt %s -buffer-deallocation-pipeline --split-input-file > /dev/null
608b7a71bSMartin Erhart
701334d1aSMartin Erhart// Test Case: Dead operations in a single block.
801334d1aSMartin Erhart// BufferDeallocation expected behavior: It only inserts the two missing
901334d1aSMartin Erhart// DeallocOps after the last BufferBasedOp.
1001334d1aSMartin Erhart
1101334d1aSMartin Erhart// CHECK-LABEL: func @redundantOperations
1201334d1aSMartin Erhartfunc.func @redundantOperations(%arg0: memref<2xf32>) {
1301334d1aSMartin Erhart  %0 = memref.alloc() : memref<2xf32>
1401334d1aSMartin Erhart  test.buffer_based in(%arg0: memref<2xf32>) out(%0: memref<2xf32>)
1501334d1aSMartin Erhart  %1 = memref.alloc() : memref<2xf32>
1601334d1aSMartin Erhart  test.buffer_based in(%0: memref<2xf32>) out(%1: memref<2xf32>)
1701334d1aSMartin Erhart  return
1801334d1aSMartin Erhart}
1901334d1aSMartin Erhart
2001334d1aSMartin Erhart//      CHECK: (%[[ARG0:.*]]: {{.*}})
2101334d1aSMartin Erhart//      CHECK: %[[FIRST_ALLOC:.*]] = memref.alloc()
2201334d1aSMartin Erhart//  CHECK-NOT: bufferization.dealloc
2301334d1aSMartin Erhart//      CHECK: test.buffer_based in(%[[ARG0]]{{.*}}out(%[[FIRST_ALLOC]]
2401334d1aSMartin Erhart//  CHECK-NOT: bufferization.dealloc
2501334d1aSMartin Erhart//      CHECK: %[[SECOND_ALLOC:.*]] = memref.alloc()
2601334d1aSMartin Erhart//  CHECK-NOT: bufferization.dealloc
2701334d1aSMartin Erhart//      CHECK: test.buffer_based in(%[[FIRST_ALLOC]]{{.*}}out(%[[SECOND_ALLOC]]
2801334d1aSMartin Erhart//      CHECK: bufferization.dealloc (%[[FIRST_ALLOC]] :{{.*}}) if (%true{{[0-9_]*}})
2901334d1aSMartin Erhart//      CHECK: bufferization.dealloc (%[[SECOND_ALLOC]] :{{.*}}) if (%true{{[0-9_]*}})
3001334d1aSMartin Erhart// CHECK-NEXT: return
3101334d1aSMartin Erhart
3201334d1aSMartin Erhart// TODO: The dealloc could be split in two to avoid runtime aliasing checks
3301334d1aSMartin Erhart// since we can be sure at compile time that they will never alias.
3401334d1aSMartin Erhart
3501334d1aSMartin Erhart// -----
3601334d1aSMartin Erhart
3701334d1aSMartin Erhart// CHECK-LABEL: func @allocaIsNotDeallocated
3801334d1aSMartin Erhartfunc.func @allocaIsNotDeallocated(%arg0: memref<2xf32>) {
3901334d1aSMartin Erhart  %0 = memref.alloc() : memref<2xf32>
4001334d1aSMartin Erhart  test.buffer_based in(%arg0: memref<2xf32>) out(%0: memref<2xf32>)
4101334d1aSMartin Erhart  %1 = memref.alloca() : memref<2xf32>
4201334d1aSMartin Erhart  test.buffer_based in(%0: memref<2xf32>) out(%1: memref<2xf32>)
4301334d1aSMartin Erhart  return
4401334d1aSMartin Erhart}
4501334d1aSMartin Erhart
4601334d1aSMartin Erhart//      CHECK: (%[[ARG0:.*]]: {{.*}})
4701334d1aSMartin Erhart//      CHECK: %[[FIRST_ALLOC:.*]] = memref.alloc()
4801334d1aSMartin Erhart// CHECK-NEXT: test.buffer_based in(%[[ARG0]]{{.*}}out(%[[FIRST_ALLOC]]
4901334d1aSMartin Erhart// CHECK-NEXT: %[[SECOND_ALLOC:.*]] = memref.alloca()
5001334d1aSMartin Erhart// CHECK-NEXT: test.buffer_based in(%[[FIRST_ALLOC]]{{.*}}out(%[[SECOND_ALLOC]]
5101334d1aSMartin Erhart//      CHECK: bufferization.dealloc (%[[FIRST_ALLOC]] :{{.*}}) if (%true{{[0-9_]*}})
5201334d1aSMartin Erhart// CHECK-NEXT: return
5301334d1aSMartin Erhart
5401334d1aSMartin Erhart// -----
5501334d1aSMartin Erhart
5601334d1aSMartin Erhart// Test Case: Inserting missing DeallocOp in a single block.
5701334d1aSMartin Erhart
5801334d1aSMartin Erhart// CHECK-LABEL: func @inserting_missing_dealloc_simple
5901334d1aSMartin Erhartfunc.func @inserting_missing_dealloc_simple(
6001334d1aSMartin Erhart  %arg0 : memref<2xf32>,
6101334d1aSMartin Erhart  %arg1: memref<2xf32>) {
6201334d1aSMartin Erhart  %0 = memref.alloc() : memref<2xf32>
6301334d1aSMartin Erhart  test.buffer_based in(%arg0: memref<2xf32>) out(%0: memref<2xf32>)
6401334d1aSMartin Erhart  test.copy(%0, %arg1) : (memref<2xf32>, memref<2xf32>)
6501334d1aSMartin Erhart  return
6601334d1aSMartin Erhart}
6701334d1aSMartin Erhart
6801334d1aSMartin Erhart//      CHECK: %[[ALLOC0:.*]] = memref.alloc()
6901334d1aSMartin Erhart//      CHECK: test.copy
7001334d1aSMartin Erhart//      CHECK: bufferization.dealloc (%[[ALLOC0]] :{{.*}}) if (%true{{[0-9_]*}})
7101334d1aSMartin Erhart
7201334d1aSMartin Erhart// -----
7301334d1aSMartin Erhart
7401334d1aSMartin Erhart// Test Case: The ownership indicator is set to false for alloca
7501334d1aSMartin Erhart
7601334d1aSMartin Erhart// CHECK-LABEL: func @alloca_ownership_indicator_is_false
7701334d1aSMartin Erhartfunc.func @alloca_ownership_indicator_is_false() {
7801334d1aSMartin Erhart  %0 = memref.alloca() : memref<2xf32>
7901334d1aSMartin Erhart  cf.br ^bb1(%0: memref<2xf32>)
8001334d1aSMartin Erhart^bb1(%arg0 : memref<2xf32>):
8101334d1aSMartin Erhart  return
8201334d1aSMartin Erhart}
8301334d1aSMartin Erhart
8401334d1aSMartin Erhart//      CHECK:  %[[ALLOC0:.*]] = memref.alloca()
8501334d1aSMartin Erhart// CHECK-NEXT:   cf.br ^bb1(%[[ALLOC0]], %false :
8601334d1aSMartin Erhart// CHECK-NEXT: ^bb1([[A0:%.+]]: memref<2xf32>, [[COND0:%.+]]: i1):
8701334d1aSMartin Erhart//      CHECK:   [[BASE:%[a-zA-Z0-9_]+]]{{.*}} = memref.extract_strided_metadata [[A0]]
8801334d1aSMartin Erhart//      CHECK:   bufferization.dealloc ([[BASE]] : {{.*}}) if ([[COND0]])
8901334d1aSMartin Erhart// CHECK-NEXT:   return
9001334d1aSMartin Erhart
9101334d1aSMartin Erhart// -----
9201334d1aSMartin Erhart
9301334d1aSMartin Erhartfunc.func @dealloc_existing_clones(%arg0: memref<?x?xf64>, %arg1: memref<?x?xf64>) -> memref<?x?xf64> {
9401334d1aSMartin Erhart  %0 = bufferization.clone %arg0 : memref<?x?xf64> to memref<?x?xf64>
9501334d1aSMartin Erhart  %1 = bufferization.clone %arg1 : memref<?x?xf64> to memref<?x?xf64>
9601334d1aSMartin Erhart  return %0 : memref<?x?xf64>
9701334d1aSMartin Erhart}
9801334d1aSMartin Erhart
9901334d1aSMartin Erhart// CHECK-LABEL: func @dealloc_existing_clones
10001334d1aSMartin Erhart//       CHECK: (%[[ARG0:.*]]: memref<?x?xf64>, %[[ARG1:.*]]: memref<?x?xf64>)
10101334d1aSMartin Erhart//       CHECK: %[[RES0:.*]] = bufferization.clone %[[ARG0]]
10201334d1aSMartin Erhart//       CHECK: %[[RES1:.*]] = bufferization.clone %[[ARG1]]
1036a651c7fSMartin Erhart//  CHECK-NEXT: bufferization.dealloc (%[[RES1]] :{{.*}}) if (%true{{[0-9_]*}})
10401334d1aSMartin Erhart//   CHECK-NOT: retain
10501334d1aSMartin Erhart//  CHECK-NEXT: return %[[RES0]]
10601334d1aSMartin Erhart
10701334d1aSMartin Erhart// TODO: The retain operand could be dropped to avoid runtime aliasing checks
10801334d1aSMartin Erhart// since We can guarantee at compile-time that it will never alias with the
10901334d1aSMartin Erhart// dealloc operand
1106a651c7fSMartin Erhart
1116a651c7fSMartin Erhart// -----
1126a651c7fSMartin Erhart
1136a651c7fSMartin Erhartmemref.global "private" constant @__constant_4xf32 : memref<4xf32> = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]>
1146a651c7fSMartin Erhart
1156a651c7fSMartin Erhartfunc.func @op_without_aliasing_and_allocation() -> memref<4xf32> {
1166a651c7fSMartin Erhart  %0 = memref.get_global @__constant_4xf32 : memref<4xf32>
1176a651c7fSMartin Erhart  return %0 : memref<4xf32>
1186a651c7fSMartin Erhart}
1196a651c7fSMartin Erhart
1206a651c7fSMartin Erhart// CHECK-LABEL: func @op_without_aliasing_and_allocation
1216a651c7fSMartin Erhart//       CHECK:   [[GLOBAL:%.+]] = memref.get_global @__constant_4xf32
1226a651c7fSMartin Erhart//       CHECK:   [[RES:%.+]] = scf.if %false
1236a651c7fSMartin Erhart//       CHECK:     scf.yield [[GLOBAL]] :
1246a651c7fSMartin Erhart//       CHECK:     [[CLONE:%.+]] = bufferization.clone [[GLOBAL]]
1256a651c7fSMartin Erhart//       CHECK:     scf.yield [[CLONE]] :
1266a651c7fSMartin Erhart//       CHECK:   return [[RES]] :
127*4d80eff8SMatthias Springer
128*4d80eff8SMatthias Springer// -----
129*4d80eff8SMatthias Springer
130*4d80eff8SMatthias Springer// Allocations with "bufferization.manual_deallocation" are assigned an
131*4d80eff8SMatthias Springer// ownership of "false".
132*4d80eff8SMatthias Springer
133*4d80eff8SMatthias Springerfunc.func @manual_deallocation(%c: i1, %f: f32, %idx: index) -> f32 {
134*4d80eff8SMatthias Springer  %0 = memref.alloc() {bufferization.manual_deallocation} : memref<5xf32>
135*4d80eff8SMatthias Springer  linalg.fill ins(%f : f32) outs(%0 : memref<5xf32>)
136*4d80eff8SMatthias Springer  %1 = memref.alloc() : memref<5xf32>
137*4d80eff8SMatthias Springer  linalg.fill ins(%f : f32) outs(%1 : memref<5xf32>)
138*4d80eff8SMatthias Springer  %2 = arith.select %c, %0, %1 : memref<5xf32>
139*4d80eff8SMatthias Springer  %3 = memref.load %2[%idx] : memref<5xf32>
140*4d80eff8SMatthias Springer
141*4d80eff8SMatthias Springer  // Only buffers that are under "manual deallocation" are allowed to be
142*4d80eff8SMatthias Springer  // deallocated with memref.dealloc. For consistency reasons, the
143*4d80eff8SMatthias Springer  // manual_deallocation attribute must also be specified. A runtime insertion
144*4d80eff8SMatthias Springer  // is inserted to ensure that we do not have ownership. (This is not a
145*4d80eff8SMatthias Springer  // bulletproof check, but covers some cases of invalid IR.)
146*4d80eff8SMatthias Springer  memref.dealloc %0 {bufferization.manual_deallocation} : memref<5xf32>
147*4d80eff8SMatthias Springer
148*4d80eff8SMatthias Springer  return %3 : f32
149*4d80eff8SMatthias Springer}
150*4d80eff8SMatthias Springer
151*4d80eff8SMatthias Springer// CHECK-LABEL: func @manual_deallocation(
152*4d80eff8SMatthias Springer//       CHECK:   %[[true:.*]] = arith.constant true
153*4d80eff8SMatthias Springer//       CHECK:   %[[manual_alloc:.*]] = memref.alloc() {bufferization.manual_deallocation} : memref<5xf32>
154*4d80eff8SMatthias Springer//       CHECK:   %[[managed_alloc:.*]] = memref.alloc() : memref<5xf32>
155*4d80eff8SMatthias Springer//       CHECK:   %[[selected:.*]] = arith.select
156*4d80eff8SMatthias Springer//       CHECK:   cf.assert %[[true]], "expected that the block does not have ownership"
157*4d80eff8SMatthias Springer//       CHECK:   memref.dealloc %[[manual_alloc]]
158*4d80eff8SMatthias Springer//       CHECK:   bufferization.dealloc (%[[managed_alloc]] : memref<5xf32>) if (%[[true]])
159