I have some questions about BufferizableOpInterface

I’m doing the bufferlize thing right now and I’m implementing BufferizableOpInterface,but I’m having problems and I’d like to ask for advice.
Here are specific questions about bufferizesToMemoryRead, bufferizesToMemoryWrite.My understanding of these two functions is purely that the memref after bufferize may be read or written.So I set them to return true.But I generated the following code.

    %0 = bufferization.to_memref %arg4 : memref<2x3x8xf32>
     ......
    %alloc = memref.alloc() {alignment = 64 : i64} : memref<2x3x8xf32>
    memref.copy %0, %alloc : memref<2x3x8xf32> to memref<2x3x8xf32>
    %1 = my.op %alloc : (memref<2x3x8xf32>) -> memref<2x3x8xf32>
    %2 = bufferization.to_tensor %1 : memref<2x3x8xf32>

After my testing, if I only set bufferizesToMemoryWrite returns true.The following code will be generated.

    // You can see that there is no more memref.copy operation here, but there is still alloc.
    %alloc = memref.alloc() {alignment = 64 : i64} : memref<2x3x8xf32>
    %0 = my.op %alloc : (memref<2x3x8xf32>) -> memref<2x3x8xf32>
    %1 = bufferization.to_tensor %0 : memref<2x3x8xf32>

If I set both settings to return false, then the following code is generated.

 %0 = bufferization.to_memref %arg4 : memref<2x3x8xf32>
 %1 = my.op %0 (memref<2x3x8xf32>) -> memref<2x3x8xf32>
 %2 = bufferization.to_tensor %1 : memref<2x3x8xf32>

Here’s what I want to say.

  • I actually didn’t understand the above behavior.I think the memref after bufferization.to_memref is read and written, so I set it to return true, but the generated code I can’t understand, and I think the operations alloc,copy are redundant.But the BufferizableOpInterfacedocumentation describes the function, and if you look at it according to the documentation, it should still return true, but actually false is the best, or am I misunderstanding.
  • Another thing is that I don’t understand why bufferizesToMemoryWrite returning true does alloc and bufferizesToMemoryRead returning true does copy.

I hope you can help me, I would appreciate it. Really thank you all. :kissing_heart:

I found a good example, tensor.insert.

module {
  func.func @write_to_select_op_source(%arg0: tensor<?xf32> {bufferization.writable = true}, %arg1: tensor<?xf32> {bufferization.writable = true}, %arg2: i1) -> (tensor<?xf32>, tensor<?xf32>) {
    %cst = arith.constant 0.000000e+00 : f32
    %c0 = arith.constant 0 : index
    %inserted = tensor.insert %cst into %arg0[%c0] : tensor<?xf32>
    %0 = arith.select %arg2, %arg0, %arg1 : tensor<?xf32>
    return %0, %inserted : tensor<?xf32>, tensor<?xf32>
  }
}
./mlir-opt tensor_insert.mlir -one-shot-bufferize
module {
  func.func @write_to_select_op_source(%arg0: tensor<?xf32> {bufferization.writable = true}, %arg1: tensor<?xf32> {bufferization.writable = true}, %arg2: i1) -> (tensor<?xf32>, tensor<?xf32>) {
    %0 = bufferization.to_memref %arg1 : memref<?xf32, strided<[?], offset: ?>>
    %1 = bufferization.to_memref %arg0 : memref<?xf32, strided<[?], offset: ?>>
    %2 = bufferization.to_memref %arg0 : memref<?xf32, strided<[?], offset: ?>>
    %cst = arith.constant 0.000000e+00 : f32
    %c0 = arith.constant 0 : index
    %c0_0 = arith.constant 0 : index
    %dim = memref.dim %2, %c0_0 : memref<?xf32, strided<[?], offset: ?>>
    %alloc = memref.alloc(%dim) {alignment = 64 : i64} : memref<?xf32>
    memref.copy %2, %alloc : memref<?xf32, strided<[?], offset: ?>> to memref<?xf32>
    memref.store %cst, %alloc[%c0] : memref<?xf32>
    %3 = bufferization.to_tensor %alloc : memref<?xf32>
    %c0_1 = arith.constant 0 : index
    %dim_2 = memref.dim %1, %c0_1 : memref<?xf32, strided<[?], offset: ?>>
    %alloc_3 = memref.alloc(%dim_2) {alignment = 64 : i64} : memref<?xf32>
    memref.copy %1, %alloc_3 : memref<?xf32, strided<[?], offset: ?>> to memref<?xf32>
    %c0_4 = arith.constant 0 : index
    %dim_5 = memref.dim %0, %c0_4 : memref<?xf32, strided<[?], offset: ?>>
    %alloc_6 = memref.alloc(%dim_5) {alignment = 64 : i64} : memref<?xf32>
    memref.copy %0, %alloc_6 : memref<?xf32, strided<[?], offset: ?>> to memref<?xf32>
    %4 = arith.select %arg2, %alloc_3, %alloc_6 : memref<?xf32>
    %5 = bufferization.to_tensor %4 : memref<?xf32>
    return %5, %3 : tensor<?xf32>, tensor<?xf32>
  }
}

In this case, bufferize read and write are both true.Here memref.alloc and memref.copy are also performed, and I don’t understand why this is necessary. It can’t be done directly in %0 = bufferization.to_memref %arg1 : memref<?xf32, strided<[?] , offset: ? >> on the memref directly to store?

This issue has now been resolved. The following explains my thought process in solving this problem. At the beginning, I wrote a pass, and then bufferize the dialect that I needed to bufferize separately, and then the problem I encountered above appeared, and now my approach is to insert the bufferize interface of other dialect in the pass, such as func dialect ,arith dialect,tensor dialect… :wink: