Hi here,
I’m experimenting with linalg.generic on tensor and I didn’t understand the semantic of some requirement.
First I didn’t understand why the outs argument is mandatory as the tensor are value based, so I understand when we use the memref that allows to make the operation in place.
Then I add the outs argument to satisfy to the verifier of linalg.generic, so I write the following code and artificially add the %c to make mlir-opt happy.
func @test(%a : tensor<64x64xi64>, %b : tensor<64x64xi64>, %c : tensor<64x64xi64>) -> tensor<64x64xi64> {
%res = linalg.generic #op_trait
ins(%a, %b : tensor<64x64xi64>, tensor<64x64xi64>)
outs(%c: tensor<64x64xi64>)
{
^bb0(%aa: i64, %bb: i64, %cc: i64) :
%ee = addi %aa, %bb: i64
linalg.yield %ee : i64
} -> tensor<64x64xi64>
return %res : tensor<64x64xi64>
}
When I bufferize this mlir program the %c is just ignored and the %res is transformed to an memref.alloc and the outs argument is replaced by %res.
// mlir-opt test.mlir -linalg-bufferize -func-bufferize -finalizing-bufferize
#map = affine_map<(d0, d1) -> (d0, d1)>
module {
func @test(%arg0: memref<64x64xi64>, %arg1: memref<64x64xi64>, %arg2: memref<64x64xi64>) -> memref<64x64xi64> {
%0 = memref.alloc() : memref<64x64xi64>
linalg.generic {doc = "C(a, b) = op(A(a, c), B(a, c))", indexing_maps = [#map, #map, #map], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1 : memref<64x64xi64>, memref<64x64xi64>) outs(%0 : memref<64x64xi64>) {
^bb0(%arg3: i64, %arg4: i64, %arg5: i64): // no predecessors
%1 = addi %arg3, %arg4 : i64
linalg.yield %1 : i64
}
return %0 : memref<64x64xi64>
}
}
So I guess that the wrong behavior is that the verifier of linal.generic complains about no outs arguments if we use tensors?
What do you think?