Why print unexpected ops when I use linalg.matmul?

I’ve a question about the traversal of op with linalg.matmul. It appears unexpected ops (not in mlir context) when traversing the function to print all ops…

It’s the testcase I used:

func @matmul_tensors(%arg0: tensor<?x?xf32>, %arg1: tensor<?x?xf32>, %arg2: tensor<?x?xf32>)-> tensor<?x?xf32> {
     %0 = linalg.matmul  ins(%arg0, %arg1: tensor<?x?xf32>, tensor<?x?xf32>)
                     outs(%arg2: tensor<?x?xf32>)-> tensor<?x?xf32>
     return %0 : tensor<?x?xf32>

I print all ops using f.walk.

    f.walk([&](Operation * op){

The print result is as follows:

%1 = arith.mulf %arg3, %arg4 : f32
%2 = arith.addf %arg5, %1 : f32
linalg.yield %2 : f32
%0 = linalg.matmul ins(%arg0, %arg1 : tensor<?x?xf32>, tensor<?x?xf32>) outs(%arg2 : tensor<?x?xf32>) -> tensor<?x?xf32>
return %0 : tensor<?x?xf32>

I guess that first three ops are the implementation part of matrix multiplication due to the linalg.matmul in testcase.

But I wonder about the mechanism of linalg.matmul. Why would the first three lines (not in mlir context) be traversed when I use linalg.matmul.


This happens because linalg named ops are meant to be equivalent to a linalg generic op. So the linalg::MatmulOp behaves as:

linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d2)>, affine_map<(d0, d1, d2) -> (d2, d1)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"]} 
   ins(%b : tensor<?x?xf32>, %b : tensor<?x?xf32>) outs(%c : %in : tensor<?x?xf32>) {
        ^bb0(%arg0: f32, %arg1: f32, %arg2: f32):
          %0 = arith.mul %arg0, %arg1 : f32
          %1 = arith.add %0, %arg2 : f32
          linalg.yield %1 : f32

It is not printed for simplicity but the linalg.matmul does have a region with those operations, it also has indexing maps and iteration attributes.
When you do a walk this will go through the region of the linalg.matmul which is why you see those operations.