<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/64072>64072</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[mlir] bug in element size calculation of memref.Copy lowering to function call
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
ubfx
</td>
</tr>
</table>
<pre>
Hi everyone,
I noticed a bug in the lowering path of memref::CopyOp that uses the function call to copyMemRef().
My testcase creates two memref<1x10xi48> and then copies one to the other, using memref::CopyOp.
```
// mlir-opt --lower-affine --convert-scf-to-cf --expand-strided-metadata --memref-expand --normalize-memrefs --convert-func-to-llvm --finalize-memref-to-llvm --arith-expand --convert-arith-to-llvm --convert-cf-to-llvm --canonicalize test.mlir | mlir-cpu-runner -shared-libs=/mnt/build_llvm/llvm-project/build/lib/libmlir_c_runner_utils.so
module {
llvm.func @printI64(i64)
llvm.func @printComma()
func.func @main() -> f32 {
%c0 = arith.constant 0 : index
%c = arith.constant 10 : index
%src = memref.alloc(%c) : memref<1x?xi48>
%dst = memref.alloc(%c) : memref<1x?xi48>
%dstview = memref.subview %dst[0, 0] [1, %c] [1, 1] : memref<1x?xi48> to memref<1x?xi48, strided<[?, 1], offset: ?>>
affine.for %i1 = 0 to %c {
%i = arith.index_cast %i1 : index to i48
memref.store %i, %src[%c0, %i1] : memref<1x?xi48>
}
memref.copy %src, %dstview : memref<1x?xi48> to memref<1x?xi48, strided<[?, 1], offset: ?>>
// dump it to console
affine.for %i1 = 0 to %c {
%loaded = memref.load %dst[%c0, %i1] : memref<1x?xi48>
%ext = arith.extsi %loaded : i48 to i64
llvm.call @printI64(%ext) : (i64) -> ()
llvm.call @printComma() : () -> ()
}
%cf = arith.constant 0.0 : f32
return %cf : f32
}
}
```
However, when printing the results, we notice that not the entire memref seems to have been copied: Only the first 8 elements have been copied and the last two show uninitialized memory.
```
$ ./debug.sh
0.000000e+00
0, 1, 2, 3, 4, 5, 6, 7, 17179869185, 93944231617456,
$
```
This is because the element size passed to copyMemRef() is calculated to be 6 bytes (derived from i48), but LLVM actually creates a 4 or 8 byte aligned array.
MLIR:
```
llvm.func @main() -> f32 {
%0 = llvm.mlir.constant(6 : index) : i64
[...]
llvm.call @memrefCopy(%0, %48, %49) : (i64, !llvm.ptr, !llvm.ptr) -> ()
```
LLVM:
```
%23 = getelementptr i48, ptr %1, i64 %22
store i48 %21, ptr %23, align 4
[...]
call void @memrefCopy(i64 6, ptr %31, ptr %32)
```
A potential fix for this could be to use size calculation via llvm.getelementptr because this way, naturally, the alignment will be accounted for. This way of calculating the size is also used in the other lowering path for memref.copy which lowers to llvm intrinsics: https://github.com/llvm/llvm-project/blob/main/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp#L955
The function to emit the IR for this calculation can be found here: https://github.com/llvm/llvm-project/blob/main/mlir/lib/Conversion/LLVMCommon/Pattern.cpp#L176
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy8V91u47oRfhr6ZiBBouS_C18kzjHOArs4xWLR24CiRjELihRIKo779MWQsi0n2UW7RRsEtEgOv-H8D4X36sUg7tjykS2fFmIMR-t2Y9O9LRrbnnd_KsBXdGdrkPE9K55Y8ZDGL2BsUBJbENCML6AMhCOCtid0yrzAIMIRbAc99g47Vj2w6mFvh_NfA4SjCDB69PFENxoZlDUghdYQLEg7nL9h_x07xjeMb3OY8_12hoA-SOERpEMRCOZkr3z25VtZvKl6w6o_QJiWeBjCVOjBGiQOxNaGIzrG9zB6uu7Ha17ZrorpP035gfED9Fq5zA4BsiyKnImuUwYhy6Q1r-hC5mWXBZvJDrIM3wZh2swHp1pssx6DaEUQkGWJ70QAWWas64VW_8Rpx88QSVMEqfVrD1nWKTOnnO0Ip8LxgjkDSOs3usu6nB-WwlijZISOqs5JVmDrfRJaDmPmRmPQQeaPwmGbadV4Vj0xfuhNYPzQjEq3z4TH-IF-ssHZf6C87tGyatJIoM_yOUE-j0Fpn3s7N3lv21EjsPVjmgMQZk7qAFYXg1MmfFnVjG8UjdufU-1t34vkVXMG0QevlL1QJtFARk7UVXzOG4DxpSyAVU8QFZpLa3wQJgAtPoAyLb7dU39GXH6gvjvjXTqVjJsLra2Mt1pKuhkdnbk8qw6Tz9-BtD78NyAJ4VXhaY7ixyYtxV22fCwojAq2fAK2fCxpEhnM5mWc_IwbheQnG3wPU8Cwak8JqjpcsOjXdp3HQKC0Uf1xvfZNAykm8846upEqoxQFsUtGmRs16kvNDBUN8ywFqXA6PFmLAOiCs7MX1QTrMJJPWvBO0s3JYaYV9WtdzMy3fnovz8SFEuQFPIHerPT_UTHMvSzmw3bsB1Ah5W_jrcbfMAPjS21Fi-3c3Wjl5mu_pcpoW3wLM-viW_DqjuED2TSadlXfHZ19x4wS69R93knwl5C6JqKUP6Zc8mucWWa6YLwD-LlnkE66T_NRnnJMV_HbaYdhdOZ6aL57A75-vCt-cfzTnqgpICucqLhGAaiIUl116EcdfNzEqUdIFd_YECnQBOVwshl4xN6T2o_iFaHBS7Fu6Wp_GX1OTYJyPsAGUGOPJvgP1JdSD5oClhoCf7QnGI0yKqhYzFpiad35vp_4UN5ryBk_tNiML7k_TrRFXsQ_ZPyxmEiLFCp8D5yGioaahiUNKxrWkWRdrreb1bbcxI1tta1rXpWrcl0vI9WV8y90_uOoPCgPDUoxekyKTMoAT5V6EN5j-1n_RMek0HLUIiSKBmEFzZlaJ8Y3LTr1ii10zvYxr_Et3aoZA3z9-vdvIGQYhdbna7sloAbrYBMhQGhqIVsQzol3uv329ct3aqk-E-u-Ov87NTeV3HiMeoarmzO-Wc1K6RRA1yhmy8c8zymj3QLwLv6SI1LTlyL5kl5SfqSP7fvIpuUyggzBfZh-Eraf2pS0-1P1EGNeRZFfMEymHoKDKW_TJ-PL6H9qVUfya5SnOkT5jJbLGT2PbhptBvVdHLxXU1TPq1XtBx0Ru9UMs5ozqPivhX6AwQZKAUJDp96AqkIg55Z21C25ZrD0OEheffFbeh-8KpEMd6-PW0QoDydxprsYEUZHPksTCpUocAyWk9KauAgp7WgoIDrrcvgxnaYny5XplNLiTZQHoX28Wnt57MQ3xLsnD8kzr9Ono5LHRBPTXOyylQlOGa-kJ686hjDQRyqlLyocxyaX9tI8f9JDa0vNcwqaAwXDtaHex5beK0s7KQv8sNHR7qe5HAbGq6_b5fI-zcweZMEC9iol7S_fZ5aaGUUKQ9rs7GhaOKLD_6lAdHOqlHHyNxECOnORpFyv5pIs2l3VbqutWOCuXG0LXiyL1XZx3DVr3q7XNZbdupH1Zsk7yRvZSmzKlq83fKF2vOBVseZ1WfGab_Oy5BKbTqy6Tdk2q4bVBfZC6Tx6o3UvC-X9iLtVXaz5QosGtY8vas4NniBuMs7pge12UfJmfPGsLrTywd9Qggo6PsWjApZPl3f1XZ6fK__6vM4pMm-OGOy7V_VidHr3H1slXtwzfoiC_SsAAP__ru_JAg">