<html>
<head>
<base href="https://llvm.org/bugs/" />
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW --- - ms_abi is implemented incorrectly for larger values (>=16 bytes)"
href="https://llvm.org/bugs/show_bug.cgi?id=31362">31362</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>ms_abi is implemented incorrectly for larger values (>=16 bytes)
</td>
</tr>
<tr>
<th>Product</th>
<td>clang
</td>
</tr>
<tr>
<th>Version</th>
<td>3.9
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>-New Bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>simonas+llvm.org@kazlauskas.me
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr>
<tr>
<th>Classification</th>
<td>Unclassified
</td>
</tr></table>
<p>
<div>
<pre>```c
#include <inttypes.h>
struct i128 { uint64_t a; uint64_t b; };
__attribute__((ms_abi, noinline)) struct i128 passthrough_a_s(struct i128 a) {
return a;
}
__attribute__((ms_abi, noinline)) __int128 passthrough_a(__int128 a) {
return a;
}
```
This code compiles to assembly that looks like this:
```asm
passthrough_a_s:
mov rax, rcx
ret
passthrough_a:
mov rax, rcx
ret
```
As per these two documents:
[msdn1]: <a href="https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx">https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx</a>
[msdn2]: <a href="https://msdn.microsoft.com/en-us/library/7572ztz4.aspx">https://msdn.microsoft.com/en-us/library/7572ztz4.aspx</a>
Both of these are wrong and the generated assembly ought to look like this
instead:
```asm
passthrough_a_s:
mov rax, rcx
mov r9, QWORD PTR [rdx]
mov r10, QWORD PTR [rdx+8]
mov QWORD PTR [rcx], r9
mov QWORD PTR [rcx+8], r10
ret
passthrough_a:
mov rax, rcx
mov r9, QWORD PTR [rdx]
mov r10, QWORD PTR [rdx+8]
mov QWORD PTR [rcx], r9
mov QWORD PTR [rcx+8], r10
ret
```
The relevant excerpts:
<span class="quote">> A scalar return value that can fit into 64 bits is returned through RAX—this includes __m64 types. Non-scalar types including floats, doubles, and vector types such as __m128, __m128i, __m128d are returned in XMM0. [snip] To be returned by value in RAX, user-defined types must have a length of 1, 2, 4, 8, 16, 32, or 64 bits. [snip] Otherwise, the caller assumes the responsibility of allocating memory and passing a pointer for the return value as the first argument.</span >
<span class="quote">> __m128 types, arrays and strings are never passed by immediate value but rather a pointer is passed to memory allocated by the caller. Structs/unions of size 8, 16, 32, or 64 bits and __m64 are passed as if they were integers of the same size. Structs/unions other than these sizes are passed as a pointer to memory allocated by the caller. For these aggregate types passed as a pointer (including __m128), the caller-allocated temporary memory will be 16-byte aligned.</span >
Also from <a href="https://msdn.microsoft.com/en-us/library/ms235286.aspx">https://msdn.microsoft.com/en-us/library/ms235286.aspx</a>:
<span class="quote">> There is no attempt to spread a single argument across multiple registers.</span ></pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>