[Mlir-commits] [mlir] [mlir][linalg] do not break outs from block argument (PR #73572)

Mehdi Amini llvmlistbot at llvm.org
Tue Nov 28 20:40:16 PST 2023


================
@@ -1818,6 +1818,11 @@ struct RemoveOutsDependency : public OpRewritePattern<GenericOp> {
         if (sparse_tensor::getSparseTensorEncoding(operandVal.getType()))
           continue;
 
+        // If outs is wired from a block argument, keep the dependency to
+        // prevent the argument from being optimized away.
----------------
joker-eph wrote:

>  "Can I use a block argument for outs?

You can (the IR is valid and has a well defined semantics), but you can't guarantee it'll stay there (this transformation that you want to block is a valid one).
Semantically there is nothing "special" about a block argument, so it's hard for me to understand what would justify this change right now.

> Do you think it is ill-defined because a tensor is not supposed to be written?

Yes, tensors are immutable object: the `outs` in linalg-on-tensor refers to two things as far as I remember: 
1) The shape of the output, in case of dynamic output.
2) The initial value in case of reduction iterators.

Here it is unused and can be eliminated: this seems like actually a desirable feature and optimization that you would be removing here!

> I had the same question for the tensor from tensor.empty().

What is your question on tensor.empty()? I see it as a tensor with a "poison value", only the shape can be used.

> Another solution is to have memref from the very early stage of the compilation process. But there might be people who prefer to optimizations with the tensor representation before going to the stages with memref.

There are many ways to implement a well defined and robust solution actually, let me make-up one for example:

IREE could express its ABI with memrefs while still using tensors in the body by converting to tensor there:

```
func.func @my_add(%a_: memref<2xf32>, %b_: memref<2xf32>, %out_: memref<2xf32>) {
  %a = iree.to_tensor %a_
  %b = iree.to_tensor %b_
  %out = iree.to_tensor %out_
  
  %r = linalg.generic ins(%a : tensor<2xf32>, %b : tensor<2xf32>) outs(%out) {
    // add op
    ...
  } -> tensor<2xf32>
  
  iree.to_memref %r, %out_ : tensor<2xf32>, memref<2xf32>
  return
}
```

Of course we wouldn't preserve the `outs` of the linalg generic (because... why?) but the `iree.to_memref` keeps it alive (the `%out` won't get removed).

> What do you mean "bufferization should recover"?

I mean that in the example above, after removing `%out` it is a matter of optimization in the buffer allocation algorithm to be able to reuse the buffer from `%out_` instead of inserting a copy.


> "How can we use a tensor operand as output?"
> Is it ill-formed?

I'm saying that the question itself is ill-formed: tensors are immutable value-based object.

> If so, do we want to introduce an attribute to mark a tensor writable?

We instead went with another type: `memref` :)

> Do we want to introduce type for tensor reference?

I can't comment on this: what would be the proposed semantic? which op would support this? (and how) 
It all depends what you mean by "tensor reference" actually.





https://github.com/llvm/llvm-project/pull/73572


More information about the Mlir-commits mailing list