[llvm-dev] BUG: complete misunterstanding of the MS-ABI

Craig Topper via llvm-dev llvm-dev at lists.llvm.org
Tue Sep 8 13:19:46 PDT 2020


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

~Craig


On Tue, Sep 8, 2020 at 1:08 PM Stefan Kanthak <stefan.kanthak at nexgo.de>
wrote:

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


More information about the llvm-dev mailing list