<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">