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

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


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.

How about I just disable __uint128_t as a keyword when compiling for
Windows?

~Craig


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

> "Craig Topper" <craig.topper at gmail.com>
>
> > __uint128_t is a "builtin type" like int or short or char or float. It is
> > not a "user-defined type".
>
> ARGH!
> For MSVC it is a user-defined type. Follow the MS-ABI.
> It's all about compatibility, which LLVM states, but fails to deliver.
>
> > The user did not define the type, its part of the compiler.
>
> It's irrelevant who defined it.
>
> > 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.
>
> OUCH: every type you define, but MSVC doesn't know, is a user-defined
> type for MSVC. Just follow the MS-ABI then.
> OR REMOVE THE WRONG STATEMENT FROM THE BLOG!
>
> Stefan
>
> > 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/f0177196/attachment.html>


More information about the llvm-dev mailing list