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

    <tr>
        <th>Summary</th>
        <td>
            llvm.memmove intrinsic odd behaviour based on data type layout
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

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

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

<pre>
    Platforms tested;
 - Custom light weight LLVM-IR compiler based on the `release/14.x` branch using c-apis
 - `clang version 13.0.1 Target: x86_64-pc-windows-msvc Thread model: posix`
 - `clang version 10.0.0-4ubuntu1 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin`

I'm honestly not sure exactly what's happening, but from my understanding there appears to be a weird interaction between possibly unaligned privative values stored in a struct and the `llvm.memmove.p0i8.p0i8.i64` intrinsic.

I made a test case set which should print out `1.234500` four times, however it does not on the first case.
  1. Creates a local instance of the struct, populates the elements with inital data, transfers the whole struct to the correct location **via mem-move**. `0.000000`
  2. Creates a local instance of the struct, populates the elements with inital data, transfers the whole struct to the correct location **via a load then store instruction**.
  3. Creates a local instance of the struct **with the elements in reverse order**, populates the elements with inital data, transfers the whole struct to the correct location **via mem-move**.
  4. Creates a local instance of the struct **with the elements in reverse order**, populates the elements with inital data, transfers the whole struct to the correct location **via a load then store instruction**.

```llvm
; some global values for fprint and declaring the c-abi functions being used
@.str = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1
declare dso_local i32 @printf(i8*, ...)

declare dso_local void @llvm.memmove.p0i8.p0i8.i64 (i8*, i8*, i64, i1)


; a data structure which if padding is not present the 64bit float will be incorrectly aligned on some systems
%struct.Blob = type { i1, double }

; a constructor which initializes the structure locally, then memmoves the data to the correct location
define dso_local void @construct.memmove (%struct.Blob* %0) {
  %2 = alloca %struct.Blob, align 4

  %3 = getelementptr inbounds %struct.Blob, %struct.Blob* %2, i32 0, i32 1
  store double 1.2345, double* %3, align 4

  %4 = getelementptr inbounds %struct.Blob, %struct.Blob* %2, i32 0, i32 0
  store i1 1, i1* %4, align 4

  %5 = bitcast %struct.Blob* %2 to i8*
  %6 = bitcast %struct.Blob* %0 to i8*
  call void @llvm.memmove.p0i8.p0i8.i64 (i8* %6, i8* %5, i64 9, i1 0)

  ret void
}

; a constructor which does the same as previous, but instead uses load then store instructions
define dso_local void @construct.restore (%struct.Blob* %0) {
  %2 = alloca %struct.Blob, align 4

  %3 = getelementptr inbounds %struct.Blob, %struct.Blob* %2, i32 0, i32 1
  store double 1.2345, double* %3, align 4

  %4 = getelementptr inbounds %struct.Blob, %struct.Blob* %2, i32 0, i32 0
  store i1 1, i1* %4, align 4

  %5 = load %struct.Blob, %struct.Blob* %2
  store %struct.Blob %5, %struct.Blob* %0

  ret void
}

; duplicate of the earlier test cases but with the struct elements reversed so the double should now be aligned
%struct.Blob.inverse = type { double, i1 }
define dso_local void @construct.inverse.memmove (%struct.Blob.inverse* %0) {
  %2 = alloca %struct.Blob.inverse, align 4

  %3 = getelementptr inbounds %struct.Blob.inverse, %struct.Blob.inverse* %2, i32 0, i32 0
  store double 1.2345, double* %3, align 4

  %4 = getelementptr inbounds %struct.Blob.inverse, %struct.Blob.inverse* %2, i32 0, i32 1
  store i1 1, i1* %4, align 4

  %5 = bitcast %struct.Blob.inverse* %2 to i8*
  %6 = bitcast %struct.Blob.inverse* %0 to i8*
  call void @llvm.memmove.p0i8.p0i8.i64 (i8* %6, i8* %5, i64 9, i1 0)

  ret void
}

define dso_local void @construct.inverse.restore (%struct.Blob.inverse* %0) {
  %2 = alloca %struct.Blob.inverse, align 4

  %3 = getelementptr inbounds %struct.Blob.inverse, %struct.Blob.inverse* %2, i32 0, i32 0
  store double 1.2345, double* %3, align 4

  %4 = getelementptr inbounds %struct.Blob.inverse, %struct.Blob.inverse* %2, i32 0, i32 1
  store i1 1, i1* %4, align 4

  %5 = load %struct.Blob.inverse, %struct.Blob.inverse* %2
  store %struct.Blob.inverse %5, %struct.Blob.inverse* %0

  ret void
}


; Run all four test cases
define dso_local i64 @main () {
  ; case 1
  %1 = alloca %struct.Blob, align 4
  call void @construct.memmove (%struct.Blob* %1)

  %2 = getelementptr inbounds %struct.Blob, %struct.Blob* %1, i32 0, i32 1
  %3 = load double, double* %2, align 4
  %4 = call i32 (i8*, ...) @printf (i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double %3)

  ; case 2
  %5 = alloca %struct.Blob, align 4
  call void @construct.restore (%struct.Blob* %5)

  %6 = getelementptr inbounds %struct.Blob, %struct.Blob* %5, i32 0, i32 1
  %7 = load double, double* %6, align 4
  %8 = call i32 (i8*, ...) @printf (i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double %7)

  ; case 3
  %9 = alloca %struct.Blob.inverse, align 4
  call void @construct.inverse.memmove (%struct.Blob.inverse* %9)

  %10 = getelementptr inbounds %struct.Blob.inverse, %struct.Blob.inverse* %9, i32 0, i32 0
  %11 = load double, double* %10, align 4
  %12 = call i32 (i8*, ...) @printf (i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double %11)

  ; case 4
  %13 = alloca %struct.Blob.inverse, align 4
  call void @construct.inverse.restore (%struct.Blob.inverse* %13)

  %14 = getelementptr inbounds %struct.Blob.inverse, %struct.Blob.inverse* %13, i32 0, i32 0
  %15 = load double, double* %14, align 4
  %16 = call i32 (i8*, ...) @printf (i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double %15)


  ret i64 0
}
```

Output when running the compiled program (same across all three platforms mentioned):
```
0.000000
1.234500
1.234500
1.234500
```

Expected output
```
1.234500
1.234500
1.234500
1.234500
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWVlv4zYQ_jX2y8CCLl8PfsjRBRbYosWi6OuCkmiLC4oUSMpO-us7Q0m-IifOZrdNiw0CJ6LFub5vDkqZLh5Xv0vm1tpUFhy3jhej5HYU3o_CG5jAXWOdrkCKTelgx_2fT5_-_HXy8TPkuqqF5AYyZnkBWoErOYxmoeGS49Io_hClwQMuQGaYyktorFAbyCesFnavAr_PJcP1LTdWoJQoCcIggj-Y2XA3Sm7gYTH7MksndT7ZCVXonZ1UdpvDH6XhrIBKF1zSbbW2grQ9IzlEyeEkbbJGuWZYhRSqeZhsVDMsHz4q65iUvLgXhlbRy8Ya_MyE2itvPz-O4nkFpVYYVvkISjuwjeHAH1hOC7uSObzFQsnqmiuMzSi-g6xxsDYY9OoRGlWg6Y6pggKH4cXddC8zCJaGDK8IFVOAUI4bFEtuZtztOFdksBWZJDEMEVQIUm3Eljmx5bBlsuEWEF7DaTtKss40uQPU1iMp5bYKKl5VesuDOhSL9kPMUkIVdRqhrMiDE6-hYgUZRmyCHIkAliN5SoEMsKVupDdDOdDoKcqJgjhJp2FIIte6MeBExS2FotQ7jtiBcFBoNJYi2NFsLUwnvVMOEAVwh4ihWlQudc4kWkjByznotd_Vekiia1030t9L60jYiitnYSdcibsEQgwFc4xudUheu-amvXVXatkLIgxoLdfGcLwkpR6BUXyDv1vBAIM3oei1KwH5ixT0PweqQvweTSdLmKeCamnibaLNeF_nT-9Acq0DnXxv7In5yEBDYCNdtEHWt_f9i1D1rqX_A9euh7L7nIXtLxWAbim5BasrDhupM7Srqx_YOGDdpjPVjYJjxTVdsaJKnwlYN8rrsViY6JsGu0UnMw0DNANGyX1XmTjWKsUqXnxhRWHQJR9pDO30NoUHEIvR9B7yURyP4ul6NL1DGfgR-oU78FUOolZ4awqHwuovHWxJDKjSW7sexQuU1sIQBMEoXh4H4OnmrRYF7b5cEuFY5OEfrJX0JzrTcIgq8xh3YFJ_aEulWEONQaCIibb01YZb5IcP7SzNsCquEVYsrUJK6gVCdRTAkt8XfKSBR80-Ymuvuq6LwWu1BbcIpg-_e6yx4s9vvaF3WG6bTNLC_VNrPSi0G6HvTEWqCtT4V0fkgys-dvLRE5jI1wWuvc27fYG8PQxroYZQ2NvQQ0HBP3UL44-LU-TGkhzr0xmXYu8x2oUi4XxTz6L02HG_LfHbcGDo8rRG5gqVaWzSdkDMoDWepsTDsP8n6jW0edkFvu2JByS67clz9qU_xL7w1D4RQdTz2e9InzNp6k1CpmKjdhc0EgPabDnsm728L3yyj5j2mjT1iva56s3tEhaWrYsUheWpUwZHGdLRrV6XH3548YmBpQ2YpUzeCt3Yft6jakyzJpZG-1yptlenBZYKv_lnWrzbtPA4X23AibrzAt5R9wLSryNw0dRS5NSKu-kGTxtS4BS-n-et5-x-zummkP300s06BTaetsy32HWjv9I7f25p-9NQPwqEaoelk77UA-7zcm_2FZnQSbvcKPo7vikzDpu_S4Yci3vWyhcZ-c9kzBvsjd6eQcMN4lzzaxvMOR_eYaN5Be0vNoKftP-v0n6gcbzCoGcayaHyDjaUJ4x5RWPZt5fPjSJKdU969i3lAq99GqVhxYRqGXzKUZTnHzBFRzGKXjHGnOXy9aeK89PcUb68bdKILhNmn1Ie_0M_PGF4PODjntveWX8KfnL4PRyMD2XroieL4-O4d-Xk-ga6g31f5cKjf5bHx0ufkeeB7EGNnxD_jaC-NBNPh0CdfQdQp8-COn8R1NkwqIv3Cur8MqjJkf3Lb-gvF8F97Zi3HAI7Cn9AD1he7lmkMnoR_igcxj-K3ysBooH62DPgxIPkR1Dg2pEnGig-uPoj5oAoeZ4E05dJ8HQwaLfO3i0Jzuvp8aTQbjkbFfqnzse3_9a4mk6b9DzENErtny23bx_pXZLeGFaR7e3jldxoa_2M4UrDOdT795vkr9B07ETDkvNn3e3l_u2Mv9q_m3rxatD4Xx5qnjt6DOu9GLzzehUXFI75KprNwni-nKazcbFKimWyZGMnnOSr4-PJ4YUd6KLAU3jJ6CnU0Qvc9oksHbkle0Sbx42Rq9K52lK44g_4u8Fjf5MFGH688K8H2j8TxOErpzdUH4S1Db3A-zCdR1E0LlfROp9PE57OkzWPwnAeZWxWTPM0z5dsvZwtxpJlXNoVcg1ZNharOIzjcBHFYZpO02mwQH-SaJaFeRZHeRwjBzmOhDLw3mmzGRvv6CRrNpbOZMI6e_iSWUsPG3gvnzWu1GZ185UpcStk9jj2Fq-8uX8DpQ5Kjw">