Stefan Kanthak via llvm-dev
2020-Aug-30 22:39 UTC
[llvm-dev] BUG: complete misunterstanding of the MS-ABI
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
Reid Kleckner via llvm-dev
2020-Sep-08 18:57 UTC
[llvm-dev] BUG: complete misunterstanding of the MS-ABI
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 >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200908/13b76b3c/attachment-0001.html>
Craig Topper via llvm-dev
2020-Sep-08 19:27 UTC
[llvm-dev] BUG: complete misunterstanding of the MS-ABI
__uint128_t isn't getting the usual x86 handling. I think the usual handling for i128 return would be 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)); ~Craig 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/d1bb1a5d/attachment.html>
Craig Topper via llvm-dev
2020-Sep-08 20:19 UTC
[llvm-dev] BUG: complete misunterstanding of the MS-ABI
__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>
Craig Topper via llvm-dev
2020-Sep-08 20:42 UTC
[llvm-dev] BUG: complete misunterstanding of the MS-ABI
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>
Craig Topper via llvm-dev
2020-Sep-08 20:57 UTC
[llvm-dev] BUG: complete misunterstanding of the MS-ABI
What if the source file was this instead. Did we follow the MSVC ABI now? #include <intrin.h> #ifndef __clang__ typedef __m128i __uint128_t; #else __attribute__((ms_abi)) #endif __uint128_t foo(__uint128_t x) { return x; } ~Craig On Tue, Sep 8, 2020 at 1:42 PM Craig Topper <craig.topper at gmail.com> wrote:> 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/1fd91cd7/attachment-0001.html>