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