<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/60742>60742</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Failure to recognise partially unrolled memcpy loops
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            missed-optimization
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          RKSimon
      </td>
    </tr>
</table>

<pre>
    https://simd.godbolt.org/z/rvvEzW971

```
using T  = int __attribute__((ext_vector_type(4)));
void copyme(T* __restrict dst, const T* __restrict src, unsigned N) {
    while(N--) {
 *dst++ = *src++;
    }
}
```
is recognized as a memcpy loop:
```
define void @copyme(ptr noalias nocapture noundef writeonly %dst, ptr noalias nocapture noundef readonly %src, i32 noundef %N) {
entry:
  %tobool.not2 = icmp eq i32 %N, 0
  br i1 %tobool.not2, label %while.end, label %while.body.preheader
while.body.preheader: ; preds = %entry
  %0 = zext i32 %N to i64
  %1 = shl nuw nsw i64 %0, 4
  tail call void @llvm.memcpy.p0.p0.i64(ptr align 16 %dst, ptr align 16 %src, i64 %1, i1 false), !tbaa !6
  br label %while.end
while.end:                                        ; preds = %while.body.preheader, %entry
  ret void
}
```
But this fails if the loop has been partially unrolled:
```
using T  = int __attribute__((ext_vector_type(4)));
void copyme2(T* __restrict dst, const T* __restrict src, unsigned N) {
    while(N--) {
      *dst++ = *src++;
      *dst++ = *src++;
    }
}
```
```
define void @copyme2(ptr noalias nocapture noundef writeonly %dst, ptr noalias nocapture noundef readonly %src, i32 noundef %N) {
entry:
  %tobool.not6 = icmp eq i32 %N, 0
  br i1 %tobool.not6, label %while.end, label %while.body

while.body:                                       ; preds = %entry, %while.body
  %N.addr.09 = phi i32 [ %dec, %while.body ], [ %N, %entry ]
  %src.addr.08 = phi ptr [ %incdec.ptr2, %while.body ], [ %src, %entry ]
  %dst.addr.07 = phi ptr [ %incdec.ptr3, %while.body ], [ %dst, %entry ]
  %dec = add i32 %N.addr.09, -1
  %incdec.ptr = getelementptr inbounds <4 x i32>, ptr %src.addr.08, i64 1
  %0 = load <4 x i32>, ptr %src.addr.08, align 16, !tbaa !6
  %incdec.ptr1 = getelementptr inbounds <4 x i32>, ptr %dst.addr.07, i64 1
  store <4 x i32> %0, ptr %dst.addr.07, align 16, !tbaa !6
  %incdec.ptr2 = getelementptr inbounds <4 x i32>, ptr %src.addr.08, i64 2
  %1 = load <4 x i32>, ptr %incdec.ptr, align 16, !tbaa !6
  %incdec.ptr3 = getelementptr inbounds <4 x i32>, ptr %dst.addr.07, i64 2
  store <4 x i32> %1, ptr %incdec.ptr1, align 16, !tbaa !6
  %tobool.not = icmp eq i32 %dec, 0
  br i1 %tobool.not, label %while.end, label %while.body, !llvm.loop !9

while.end: ; preds = %while.body, %entry
  ret void
}
```
vs:
```
define void @copyme(ptr noalias nocapture noundef writeonly %dst, ptr noalias nocapture noundef readonly %src, i32 noundef %N) {
entry:
  %tobool.not2 = icmp eq i32 %N, 0
  br i1 %tobool.not2, label %while.end, label %while.body.preheader
while.body.preheader:                             ; preds = %entry
  %0 = zext i32 %N to i64
  %1 = shl nuw nsw i64 %0, 5
  tail call void @llvm.memcpy.p0.p0.i64(ptr align 16 %dst, ptr align 16 %src, i64 %1, i1 false), !tbaa !6
  br label %while.end
while.end: ; preds = %while.body.preheader, %entry
 ret void
}
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWE9v6rgX_TRmc0WUOATIggWUx-YndfGbJ80SOfEFPHLsjO3QRz_9yE4IUCil1XujGWmqqIB9_xyfax9fYNaKrUKckWxBsuWANW6nzez___tNVFoNCs0Ps51ztSXpnNAVoSsrKh5tNS-0dJE2W0JXr4SuzH7_7fX3fJKQeEniefd_HHdP-NhYobbwHYCkSxDKwXrNnDOiaByu14ROCZ3iD7feY-m0WbtDjYROR4Tm3ZMu2kB7LTiUuj5U3uA7oXNYrw1aZ0TpgFtH6BOUWlkHbyetKf1ko8K6OTwTmgOZdIEBAF52Qvqwz8Ph5Ryh8xB6QegiLIHQeQjnB3psPgSZLDsC-jeXTAgLBku9VeIVOTALDCqsyvoAUuvac33Li-NGKISwejKKewJqZ0BpJgWzoHTJatcYBKUbxXEDL0Y41EoegNCs4-a-h0HGjw4dXyKl_TSh2SVrqJw59KDBGzhdaC0jpR1tq11WNeCfIU7r_wTx0b4wIJI3Xt5AsgKlHw8liVDxG6N-i0a1wR0yjqYNeXMmnQNJF1Ab5LYrX9YiP8GOw8Qr_nA9UnAaxHh0ZpQEI7uToJoXUPbFzwdvD6-3dExIKJmUfcGk3FdRW-eojv3jA7f1Y1JsFSTjN0U6Hz6Wok2WhPcJbJi0GM7HExCauIIx_zo-I_cGj2c0-Y9p2LaP_F1ReJPrgOWSXYMuEHH_YCwaB24nLGyYkBbEBtwOw6GAHbNQICqomXGCSXmARhktJfL3DsyvEBz6NypOy_jDsvMZ2w8l6hHtof908Rl_SXzGnxKf8wvvbPThI_WOKLVH6G2asL7niHFuojgPHvVOtCvLFoFkLK98gWTLMNiaPJ-fzzB3im1N2UWf9tF9wTpXoUqOZVQ7Qz_K0hXvnTzcui7P5H6e9KM83a56Lw-WIT7jvK__kT7vNkzOjE9Zg88WHUqsUDk_IlTh96Av09MIfvhoJP123NCX1B11Orm6W6Rm_NEIR_F_T9ovECdfgXxWhSvI1mmDl579JXfb_VN46U-imF7dzHcpPgH4NOL0JzFMP2A4uQk3eRDvScZuaV-nDvfU73Pi1wIJnU24pQlN8mtF7HqMO83D11uGvf2vX_5F_fIXrq2f2ktn_9Je-qtN8kcbfsBnKc_TnA1wlown43SaZqN8sJslRYab8XSaFVOK8SSblsh5kucxy8uSZ2wgZjSmaUyTUTKKs1EeJcUE6YTjhk43Wc5LMoqxYkJGgVhttgNhbYOzcTwZ0UFYtQ0_ElBaCWuRD3XtRCVemRNaEUpJthyYmfceFs3W-hIJ6-wpnhNO4mzFhPRnx-njN2CLNzr686_DdtAY-eZXiK1wu6aISl0RuvIpupdhbfQfWDpCVwG_JXQVlvBXAAAA__8RGdzP">