<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/62885>62885</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[mlir][MemRef] multibuffering fails to apply when ops are hoisted outside of loop
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
qcolombet
</td>
</tr>
</table>
<pre>
The multibuffering optimization expects that all the users of a buffer are within a loop.
This creates some phase ordering issue when, for instance, loop invariant code motion is run before multibuffering.
We should make multibuffering more robust with respect to this.
In particular, for view like operations it should be possible to push them back in the loop (assuming they don't have uses outside the loop either) to be able to perform the multibuffering (or generate the right code outside of the loop).
To reproduce:
```
mlir-opt -test-transform-dialect-interpreter -allow-unregistered-dialect test.mlir -split-input-file
```
With test.mlir:
```mlir
func.func @multi_buffer_transformed(%in: memref<16xf32>) {
%tmp = memref.alloc() : memref<16xf32>
%c0 = arith.constant 0 : index
%c4 = arith.constant 4 : index
%c16 = arith.constant 16 : index
scf.for %i0 = %c0 to %c16 step %c4 {
%1 = memref.subview %in[%i0] [4] [1] : memref<16xf32> to memref<4xf32, affine_map<(d0)[s0] -> (d0 + s0)>>
// This subview is loop invariant.
%subview = memref.subview %tmp[0][4][1] : memref<16xf32> to memref<4xf32>
memref.copy %1, %subview : memref<4xf32, affine_map<(d0)[s0] -> (d0 + s0)>> to memref<4xf32>
"some_use"(%subview) : (memref<4xf32>) ->()
}
return
}
transform.sequence failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = transform.structured.match ops{["memref.alloc"]} in %arg1 : (!pdl.operation) -> !transform.op<"memref.alloc">
%1 = transform.memref.multibuffer %0 {factor = 2 : i64, skip_analysis} : (!transform.op<"memref.alloc">) -> !pdl.operation
// Verify that the returned handle is usable.
transform.test_print_remark_at_operand %1, "transformed" : !pdl.operation
}
// -----
// Notice how the subview outside of the loop is preventing the optimization
// to kick in. This code is exactly the same as `multi_buffer_transformed`
// except we ran licm before. (mlir-opt -loop-invariant-code-motion)
func.func @multi_buffer_not_transformed(%in: memref<16xf32>) {
%tmp = memref.alloc() : memref<16xf32>
%c0 = arith.constant 0 : index
%c4 = arith.constant 4 : index
%c16 = arith.constant 16 : index
// This subview is loop invariant.
%subview = memref.subview %tmp[0][4][1] : memref<16xf32> to memref<4xf32>
scf.for %i0 = %c0 to %c16 step %c4 {
%1 = memref.subview %in[%i0] [4] [1] : memref<16xf32> to memref<4xf32, affine_map<(d0)[s0] -> (d0 + s0)>>
memref.copy %1, %subview : memref<4xf32, affine_map<(d0)[s0] -> (d0 + s0)>> to memref<4xf32>
"some_use"(%subview) : (memref<4xf32>) ->()
}
return
}
transform.sequence failures(propagate) {
^bb1(%arg1: !pdl.operation):
%0 = transform.structured.match ops{["memref.alloc"]} in %arg1 : (!pdl.operation) -> !transform.op<"memref.alloc">
%1 = transform.memref.multibuffer %0 {factor = 2 : i64, skip_analysis} : (!transform.op<"memref.alloc">) -> !pdl.operation
// Verify that the returned handle is usable.
transform.test_print_remark_at_operand %1, "transformed" : !pdl.operation
}
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWE2P27wR_jX0ZSBBoix_HHyId7NAD-2hCNqjQUkji12KZMjRfvTXF6Q-bO86QAqkBd4XCQIJ5nLmeWY4z4wk4b08a8QDK4-sfFyJgTrjDt9ro0xfIa0q07wfvnUI_aBIVkPbopP6DMaS7OW_BUmjAd8s1uSBOkEglALqEAaPzoNpQcBoBsIhvErqpAYByhibsuyRZV--ddJD7VAQevCmR7Cd8AjGNSOY9H5AeO1QM_4ArXEgtSehawy_gyeQ-kU4KTRBbRqE3kRi0oMbNFTYGvcxhAl8vP4TwXdmUA304vlTsH2wdqYaPMUAwKEPEQMZoE76ydVfNFjhSNaDEm5m-iLxFZR8RjAWXcyXB0kzXIVgjfeyUhi82cF3IXs9VKJ-BqljKmOEjO-E90MfCFGH79AYzfiWoBMvMdsezEBeNnixQUkdOsb3wXeFIGYYdK1xfdz4IVbGd8bBGXUgO7py8txNeZ0RTLuAML6_SeU3Aw6tM81QIyumRbbJpv_xZ6-kS4wlSAg9JeSE9oFQ0kihsKZEakJnHRI6SIRS5jUZtMOz9IQOm3kfBPM0eIPEWyWDoR0oaaXCu8DTaYczXEw_k4yrcakddJ2GC7B1FjN1GlN1Wjhjw_iO8VJqVnyBHnuHLSse8s1bW3BWfA3ZZ9vj6A-A8ZJ6C6x4nPamIbw6-tjDD1xccY8e6iw6EE5Sl9YmioEgi-ZSN_h2vXd9b-_6_t58c29zXL3ZPdn4uk1DkYfwR0ojOTKzN09oZxaXJESw_DoJfqiiUsZElsfokZWPwMrjerrn8X43QwFxWV3HRf4Aom2lxlMvLCseGN81GeN7Vh599JwEu7gKjB_Bxz8WX5d8A-NPjD9BbE8zP-k_9Jv0JqYljLuRUW9ZeQzgU1T_dVCB8YI3AdTGvsd8hpBvOHyBX5iUu2xuKzOkgIcGfho8Ms5HYUx85vJmfPfZDd9H5FEFc_q3j7NjhzQ4PYHNy-N10WHq8fuAukZohVSDQ8_4zjpjxVkQ3qiQlV-rKh_ZCXfOR1q5bVS6NOkY97Xmxvq-giM31DQ4bNJeUN2BsT4ghNrlt9Lm4ai3j6GdT4hzJu6gzkeQX6DMeFSfvC6VepHTxWjafNXepyi2x1bUFFRbPAIflb1Zh9Lwz9KehBbq3UsfCF9Y_hSZK_K3US0so6D-gU627-PTQpwv8XSxgU7oRmHQ2ODDqJq1dQEPTftkndR0ctgL93wSdIo4urnSAL_pzhzuHvC9apoYJuHfnfW_GZI1QmdeI_FZaXemYgjCOnxBTdPAvnlkuvFKBp5lnPbp2GziqJUe8E3UpN5HLNEjCA9hPP1oDi1TbvSLbzVaglcEJzQoWffTk1AaRbjM4MA3WRpaEtCT8QFqEeOP56A29MeYhf-rUQgfqvsnx8X_c1jMmH_ucf17HP4eh7_H4a8ah_O70Ko5FM2-2IsVHvLNbr1bl9kmX3UHLNd1ljX7dsszzne4z_L9OsvLNlvXm91WrOSBZ7zISl7kvMizPN3xer_Nis0mr9pqvd-xdYa9kCpV6qVPjTuv4ov-YcN3u3KlRIXKH8YC0rGX-gHH6lm5Q7BJquHs2TpT0pO_eCFJKn7RiO9xsXH-Ffu_YxsU_eF1N4jDBy0La9V7_MYQKjd-q-hMeN1srsd7aOarwalDR2R9UEQ8w7OkbqjS2vSMPwUe0y2xzvwLa2L8KbL3jD_F6P4TAAD__4zzRvk">