https://llvm.org/bugs/show_bug.cgi?id=31362

            Bug ID: 31362
           Summary: ms_abi is implemented incorrectly for larger values
                    (>=16 bytes)
           Product: clang
           Version: 3.9
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: -New Bugs
          Assignee: unassignedclangb...@nondot.org
          Reporter: simonas+llvm....@kazlauskas.me
                CC: llvm-bugs@lists.llvm.org
    Classification: Unclassified

```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]: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
[msdn2]: https://msdn.microsoft.com/en-us/library/7572ztz4.aspx

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:

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

> __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.

Also from https://msdn.microsoft.com/en-us/library/ms235286.aspx:

> There is no attempt to spread a single argument across multiple registers.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to