<div dir="ltr">__uint128_t is a "builtin type" like int or short or char or float. It is not a "user-defined type". The user did not define the type, its part of the compiler. Since MSVC does not have such a builtin type we are free to do whatever we want with it because the type can't exist in any code compiled with MSVC so we don't need to interoperate.<div><br clear="all"><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">~Craig</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Sep 8, 2020 at 1:08 PM Stefan Kanthak <<a href="mailto:stefan.kanthak@nexgo.de">stefan.kanthak@nexgo.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">"Craig Topper" <<a href="mailto:craig.topper@gmail.com" target="_blank">craig.topper@gmail.com</a>> wrote:<br>
<br>
> __uint128_t isn't getting the usual x86 handling.<br>
<br>
Correct.<br>
That's why I posted this bug, and referred the misleading/wrong statement <br>
<<a href="https://blog.llvm.org/2018/03/clang-is-now-used-to-build-chrome-for.html" rel="noreferrer" target="_blank">https://blog.llvm.org/2018/03/clang-is-now-used-to-build-chrome-for.html</a>><br>
<br>
| Clang is the first-ever open-source C++ compiler that's ABI-compatible<br>
| with Microsoft Visual C++ (MSVC) - meaning you can build some parts of<br>
| your program (for example, system libraries) with the MSVC compiler<br>
| ("cl.exe"), other parts with Clang, and when linked together (either by<br>
| MSVC's linker, "link.exe", or LLD, the LLVM project's linker - see below)<br>
| the parts will form a working program.<br>
<br>
> I think the usual handling for i128 return would be rdx:rax.<br>
<br>
For the SysV-ABI, but not the MS-ABI, which uses ONLY rax, not the register<br>
pair rdx:rax<br>
<br>
> Instead I believe it's being coerced to v2i64 by this code in<br>
> clang/lib/CodeGen/TargetInfo.cpp<br>
> <br>
> // Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that.<br>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
> // Clang matches them for compatibility.<br>
> return ABIArgInfo::getDirect(llvm::FixedVectorType::get(<br>
> llvm::Type::getInt64Ty(getVMContext()), 2));<br>
<br>
I underlined the culprit.<br>
Now please remove that wrong statement cited above from the blog.<br>
<br>
JFTR: for MSVC, __uint128_t (or however you name it) is a USER-DEFINED type,<br>
so the caller has to pass a pointer to a hidden first argument in RCX,<br>
which the callee needs to return in RAX<br>
<br>
<<a href="https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx" rel="noreferrer" target="_blank">https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx</a>><br>
<br>
| To return a user-defined type by value in RAX, it must have a length of 1, 2, 4,<br>
| 8, 16, 32, or 64 bits. [.] Otherwise, the caller must allocate memory for the<br>
| return value and pass a pointer to it as the first argument. The remaining<br>
| arguments are then shifted one argument to the right. The same pointer must be<br>
| returned by the callee in RAX.<br>
<br>
So Reid Kleckner is wrong with his statement "no rule".<br>
<br>
regards<br>
Stefan<br>
<br>
> On Tue, Sep 8, 2020 at 11:57 AM Reid Kleckner via llvm-dev <<br>
> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br>
> <br>
>> The code that you have has a large `#ifndef __clang__` block in it, and<br>
>> IMO that explains the ABI difference.<br>
>><br>
>> As you note, MSVC does not have native support for 128 bit integers, so<br>
>> there is no reason for Clang to attempt to be ABI compatible.<br>
>><br>
>> The __uint128_t arguments are passed indirectly because MSVC has a rule<br>
>> that requires arguments larger than 64 bits to be passed indirectly by<br>
>> address. I believe exceptions to that rule, such as vector arguments, are<br>
>> made on a case-by-case basis. No such rule exists for return values, so we<br>
>> get the usual i128 handling for x86 instead.<br>
>><br>
>> ---<br>
>><br>
>> I see that you are interested in using compiler-rt, presumably on Windows,<br>
>> and maybe from MSVC compiled objects. I think the proper fix for your use<br>
>> case is to change compiler-rt to use a union when passing these types by<br>
>> value.<br>
>><br>
>> On Thu, Sep 3, 2020 at 5:35 PM Stefan Kanthak via llvm-dev <<br>
>> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br>
>><br>
>>> Objects compiled for the MS-ABI don't conform to it!<br>
>>><br>
>>> Data types beyond 64 bit MUST BE returned by the callee via the<br>
>>> hidden first argument allocated by the caller, NOT in XMM0!<br>
>>><br>
>>> Demo/proof: from this source<br>
>>><br>
>>> --- llvm-bug.c ---<br>
>>> #ifndef __clang__<br>
>>> typedef struct {<br>
>>> unsigned __int64 low;<br>
>>> unsigned __int64 high;<br>
>>> } __uint128_t;<br>
>>> #else<br>
>>> __attribute__((ms_abi))<br>
>>> #endif<br>
>>> __uint128_t __udivmodti4(__uint128_t dividend, __uint128_t divisor,<br>
>>> __uint128_t *remainder) {<br>
>>> if (remainder != 0)<br>
>>> *remainder = divisor;<br>
>>> return dividend;<br>
>>> }<br>
>>> --- EOF ---<br>
>>><br>
>>> clang -c -O1 generates the following INCOMPATIBLE and WRONG code:<br>
>>><br>
>>> __udivmodti4 proc public<br>
>>> movaps xmm0, xmmword ptr [rcx]<br>
>>> test r8, r8<br>
>>> jz 0f<br>
>>> movaps xmm1, xmmword ptr [rdx]<br>
>>> movaps xmmword ptr [r8], xmm1<br>
>>> 0: ret<br>
>>> __udivmodti4 endp<br>
>>><br>
>>><br>
>>> clang's misunderstanding of the MS-ABI can be clearly seen here:<br>
>>><br>
>>> - RCX holds the address of the return value, NOT the address<br>
>>> of the dividend;<br>
>>><br>
>>> - RDX holds the address of the dividend, NOT the address of<br>
>>> the divisor;<br>
>>><br>
>>> - R8 holds the address of the divisor, NOT the address of the<br>
>>> remainder;<br>
>>><br>
>>> - R9 holds the address of the remainder;<br>
>>><br>
>>> - aggregate data types are NOT returned in XMM0, but via the<br>
>>> hidden first argument addressed by RCX;<br>
>>><br>
>>> - the address of the hidden first argument is returned in RAX!<br>
>>><br>
>>> JFTR: an 128-bit integer data type is not supported by MS.<br>
>>> clang is also rather confused here: why is the return<br>
>>> value mapped to an XMM register, but not the arguments?<br>
>>><br>
>>><br>
>>> Microsoft's CL.EXE -c -Ox generates the following (of course)<br>
>>> CONFORMANT code:<br>
>>><br>
>>> __udivmodti4 proc public<br>
>>> ; Line 10<br>
>>> test r9, r9<br>
>>> je SHORT $LN1@udivmodti4<br>
>>> ; Line 11<br>
>>> mov rax, QWORD PTR [r8]<br>
>>> mov QWORD PTR [r9], rax<br>
>>> mov rax, QWORD PTR [r8+8]<br>
>>> mov QWORD PTR [r9+8], rax<br>
>>> $LN1@udivmodti4:<br>
>>> ; Line 12<br>
>>> mov rax, QWORD PTR [rdx]<br>
>>> mov QWORD PTR [rcx], rax<br>
>>> mov rax, QWORD PTR [rdx+8]<br>
>>> mov QWORD PTR [rcx+8], rax<br>
>>> mov rax, rcx<br>
>>> ; Line 13<br>
>>> ret 0<br>
>>> __udivmodti4 endp<br>
>>><br>
>>><br>
>>> NOT AMUSED<br>
>>> Stefan<br>
>>> _______________________________________________<br>
>>> LLVM Developers mailing list<br>
>>> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
>>> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
>>><br>
>> _______________________________________________<br>
>> LLVM Developers mailing list<br>
>> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
>> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
>><br>
</blockquote></div>