<div dir="ltr"><div dir="ltr"><div dir="ltr">> Mingw64 GCC returns i128 in XMM0</div><div dir="ltr"><br></div><div>I believe this was changed some many years ago (or possibly never true). I forget the exact version where this might have changed in mingw-w64, but I filed this as a bug some years ago based on my observation of GCC's behavior (<a href="https://bugs.llvm.org/show_bug.cgi?id=16168">https://bugs.llvm.org/show_bug.cgi?id=16168</a>) but then I only fixed part of it (the relevant parts of llvm but not of clang).</div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Sep 8, 2020 at 4:57 PM Craig Topper via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">What if the source file was this instead. Did we follow the MSVC ABI now?<div><br></div><div><div style="color:rgb(0,0,0);background-color:rgb(255,255,254);font-family:"Consolas, ""><div><span style="color:rgb(0,0,255)">#include</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">intrin.h</span><span style="color:rgb(0,0,255)">></span></div><br><div><span style="color:rgb(0,0,255)">#ifndef</span> __clang__</div><div><span style="color:rgb(0,0,255)">typedef</span> <span style="color:rgb(0,0,255)">__m128i</span>  __uint128_t;</div><div><span style="color:rgb(0,0,255)">#else</span></div><div>__attribute__((ms_abi))</div><div><span style="color:rgb(0,0,255)">#endif</span></div><div>__uint128_t foo(__uint128_t x) {</div><div>  <span style="color:rgb(0,0,255)">return</span> x;</div><div>}</div></div></div><div><br clear="all"><div><div dir="ltr">~Craig</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Sep 8, 2020 at 1:42 PM Craig Topper <<a href="mailto:craig.topper@gmail.com" target="_blank">craig.topper@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>If you used the same struct with clang as you did with MSVC instead of using a compiler defined type we would be compatible. Names starting with 2 underscores are reserved for compilers and libraries so user code shouldn't be defining a struct with that name anyway. We work fine on code that compiles with MSVC without detecting the compiler and giving different code based on the compiler.</div><div><br></div><div>How about I just disable __uint128_t as a keyword when compiling for Windows?</div><br clear="all"><div><div dir="ltr">~Craig</div></div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Sep 8, 2020 at 1:34 PM Stefan Kanthak <<a href="mailto:stefan.kanthak@nexgo.de" target="_blank">stefan.kanthak@nexgo.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">"Craig Topper" <<a href="mailto:craig.topper@gmail.com" target="_blank">craig.topper@gmail.com</a>><br>
<br>
> __uint128_t is a "builtin type" like int or short or char or float. It is<br>
> not a "user-defined type".<br>
<br>
ARGH!<br>
For MSVC it is a user-defined type. Follow the MS-ABI.<br>
It's all about compatibility, which LLVM states, but fails to deliver.<br>
<br>
> The user did not define the type, its part of the compiler.<br>
<br>
It's irrelevant who defined it.<br>
<br>
> Since MSVC does not have such a builtin type we are free to<br>
> do whatever we want with it because the type can't exist in any code<br>
> compiled with MSVC so we don't need to interoperate.<br>
<br>
OUCH: every type you define, but MSVC doesn't know, is a user-defined<br>
type for MSVC. Just follow the MS-ABI then.<br>
OR REMOVE THE WRONG STATEMENT FROM THE BLOG!<br>
<br>
Stefan<br>
<br>
> On Tue, Sep 8, 2020 at 1:08 PM Stefan Kanthak <<a href="mailto:stefan.kanthak@nexgo.de" target="_blank">stefan.kanthak@nexgo.de</a>><br>
> wrote:<br>
> <br>
>> "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<br>
>> type,<br>
>>       so the caller has to pass a pointer to a hidden first argument in<br>
>> 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<br>
>> 1, 2, 4,<br>
>> | 8, 16, 32, or 64 bits. [.] Otherwise, the caller must allocate memory<br>
>> for the<br>
>> | return value and pass a pointer to it as the first argument. The<br>
>> remaining<br>
>> | arguments are then shifted one argument to the right. The same pointer<br>
>> 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,<br>
>> are<br>
>> >> made on a case-by-case basis. No such rule exists for return values, so<br>
>> 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<br>
>> Windows,<br>
>> >> and maybe from MSVC compiled objects. I think the proper fix for your<br>
>> 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>
>><br>
</blockquote></div>
</blockquote></div>
_______________________________________________<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>
</blockquote></div>