I recently hit an issue w.r.t to tensor_to_memref that triggered a lot of discussion internally. It might be worth just recording the discussion here for everyone’s visibility.
The canonicalizations of LoadOp here folds away LoadOp (TensorToMemrefOp $value), $indices)) to TensorExtractOp $value $indices . Specifically the following sequence of instructions
%1 = tensor_to_memref %0 : tensor<f32>
store %val, %1[] : f32, tensor<f32>
%get_val = load %1[] : tensor<f32>
will get canonicalized away to
%1 = tensor_to_memref %0 : tensor<f32>
store %val, %1[] : f32, tensor<f32>
%get_val = tensor.extract %0[] : tensor<f32>
%get_val is getting the wrong value, i.e. you would expect it to get %val and it doesnt.
One way to interpret this is that the canonicalization is wrong. It is undoing bufferization and the pattern is not considering the intermediate operations that might be updating the buffer leading to incorrect behavior. Therefore it needs to be removed (patch).
An alternative way to reason about it is that the input IR is exhibiting undefined behavior. The semantics of tensor_to_memref is that it is illegal to write to the memref that is the result of a tensor_to_memref. The instructions is meant only for use for necessary type-legalizations when going from tensors to buffers, and that any use of it outside of that is inherently undefined behavior.
- The caveat here though is that there is no way today to enforce that a memref has to be read only. So for a given memref it is impossible to reason about locally if the memref came from a
tensor_to_memrefand therefore cannot be written to. - There is not too much difference between a read-only
memrefand atensor. So there should not be atensor_to_memrefinstruction at all in the first-place. This would also imply that any bufferization pass (or sequence of passes) is not expected to convert all tensor operations to operations onmemrefs and that all backends (LLVM, and SPIR-V) must be able to handle tensors that are not converted during bufferization. This typically means that backends need to handlestd.constantnatively.- The LLVM backend does not handle any tensor operations. Instead there is a pass that converts
std.constants to globalmemrefobjects which can be used to lowerstd.constants to LLVM. - The SPIR-V backends natively handles
std.constants.
- The LLVM backend does not handle any tensor operations. Instead there is a pass that converts