BUG: complete misunterstanding of the MS-ABI

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
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!


Microsoft's CL.EXE -c -Ox generates the following (of course)
CONFORMANT code:

__unopti4 proc public
; Line 10
        test    r9, r9
        je      SHORT $LN1@unopti4
; 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@unopti4:
; 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
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
--- llvm-bug.c ---
#ifndef __clang__
typedef struct {
    unsigned __int64 low;
    unsigned __int64 high;
} __uint128_t;
#else
__attribute__((ms_abi))
#endif
These are different types. __uint128_t is not a struct of two 64-bit integers. If you'd modify the source so it would pass / return struct of two 64 bit integers, then you will see that clang will generate the same code as MSVC.
  
NOT A BUG. USER ERROR.

--
With best regards, Anton Korobeynikov
Department of Statistical Modelling, Saint Petersburg State University

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
"Anton Korobeynikov" <[hidden email]> wrote:

>> --- llvm-bug.c ---Any argument
            that doesn't fit in 8 bytes, or isn't 1, 2, 4, or 8 bytes, must be
            passed by reference.

>> #ifndef __clang__
>> typedef struct {
>>     unsigned __int64 low;
>>     unsigned __int64 high;
>> } __uint128_t;
>> #else
>> __attribute__((ms_abi))
>> #endif
>>
> These are different types. __uint128_t is not a struct of two 64-bit
> integers.

This is irrelavent here: clang's builtin type __uint128_t doesn't fit in
64-bit, so it MUST be returned by reference through a hidden first argument!
Please read the specification of the Microsoft ABI
<https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention>

| User-defined types can be returned by value from global functions and
| static member functions. 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.

Since MSVC does NOT support an (unsigned) __int128 data type, __uint128_t
is a user-defined type there, for which the cited specs clearly state how
to return it.

> If you'd modify the source so it would pass / return struct of two 64 bit
> integers, then you will see that clang will generate the same code as MSVC.

Who said "these are different types"? See above!

Additionally I recommend to take a thorough look into the SystemV ABI for
the AMD64 platform:

| For classification purposes __int128 is treated as if it were implemented as:
| typedef struct {
| long low, high;
| } __int128;

> NOT A BUG. USER ERROR.

WRONG: interoperability and developer error!
<https://blog.llvm.org/2018/03/clang-is-now-used-to-build-chrome-for.html>
puts up the FALSE claim:

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

Due to clang's non-conforming parameter and return value passing this does
NOT hold for code which uses __uint128_t: either fix the compiler and the
functions shipped in clang_rt.builtins-x86_64.lib, or remove the claim
"ABI-compatible" from the blog post.

Stefan
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
Since MSVC does NOT support an (unsigned) __int128 data type, __uint128_t
is a user-defined type there, for which the cited specs clearly state how
to return it.
WRONG USER INTERPRETATION:  __uint128_t is not a user-defined type.
 
| For classification purposes __int128 is treated as if it were implemented as:
| typedef struct {
| long low, high;
| } __int128;
WRONG USER INTERPRETATION:  Classification rules of System V ABI is irrelevant here.

--
With best regards, Anton Korobeynikov
Department of Statistical Modelling, Saint Petersburg State University

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
"Anton Korobeynikov" <[hidden email]> wrote:

>> Since MSVC does NOT support an (unsigned) __int128 data type, __uint128_t
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> is a user-defined type there, for which the cited specs clearly state how
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> to return it.
>>
> WRONG USER INTERPRETATION:  __uint128_t is not a user-defined type.

OUCH!
Which part of my underlined words are not understood?
In the MS-ABI, it is an user-defined type.
clang claims to be ABI-compatible, but it's implementations fails
to support that claim!

Stefan
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev


> Le 3 sept. 2020 à 23:25, Stefan Kanthak via cfe-dev <[hidden email]> a écrit :
>
> "Anton Korobeynikov" <[hidden email]> wrote:
>
>>> Since MSVC does NOT support an (unsigned) __int128 data type, __uint128_t
>   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> is a user-defined type there, for which the cited specs clearly state how
>   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> to return it.
>>>
>> WRONG USER INTERPRETATION:  __uint128_t is not a user-defined type.
>
> OUCH!
> Which part of my underlined words are not understood?
> In the MS-ABI, it is an user-defined type.
> clang claims to be ABI-compatible, but it's implementations fails
> to support that claim!
>

If MSVC does not support __int128, how could compile code that use it in the first place ? You probably define a custom type (user defined).

The fact that you choose to use an other (incompatible) type when compiling with clang (a compiler define __int128) can hardly be considered a compiler bug.

Just use the same user defined type with clang, and you will get the right behaviour.

That the kind of issue you get when defining custom type using compiler reserved name (double underscore).

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
"Jean-Daniel" <[hidden email]> wrote:

>> Le 3 sept. 2020 à 23:25, Stefan Kanthak via cfe-dev <[hidden email]> a écrit :
>>
>> "Anton Korobeynikov" <[hidden email]> wrote:
>>
>>>> Since MSVC does NOT support an (unsigned) __int128 data type, __uint128_t
>>   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>> is a user-defined type there, for which the cited specs clearly state how
>>   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>> to return it.
>>>>
>>> WRONG USER INTERPRETATION:  __uint128_t is not a user-defined type.
>>
>> OUCH!
>> Which part of my underlined words are not understood?
>> In the MS-ABI, it is an user-defined type.
>> clang claims to be ABI-compatible, but it's implementations fails
>> to support that claim!
>>
>
> If MSVC does not support __int128, how could compile code that use it in the first place ?

Please read my initial post, CAREFULLY: it shows the source I used.

>> You probably define a custom type (user defined).

Yes, with MSVC: see above!

> The fact that you choose to use an other (incompatible) type when compiling with
> clang (a compiler define __int128) can hardly be considered a compiler bug.

Don't try to make up any "facts": READ the source I posted!

LLVM/clang CLAIMS(!) to be ABI-compatible with MSVC, for example there
<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.

Now read the specification of the Microsoft ABI
<https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention>

| User-defined types can be returned by value from global functions and
| static member functions. 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.

> Just use the same user defined type with clang, and you will get the right behaviour.

Again: start to read what I already posted!
I use clang's own __uint128_t data type and show the assembly it generates,
which is but INCOMPATIBEL with the MS-ABI.

> That the kind of issue you get when defining custom type using compiler
> reserved name (double underscore).

OUCH: read again what I wrote, CAREFUL, especially the source I posted.
I don't use a compiler reserved name!

Stefan

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev


Le 5 sept. 2020 à 23:42, Stefan Kanthak <[hidden email]> a écrit :

"Jean-Daniel" <[hidden email]> wrote:

Le 3 sept. 2020 à 23:25, Stefan Kanthak via cfe-dev <[hidden email]> a écrit :

"Anton Korobeynikov" <[hidden email]> wrote:

Since MSVC does NOT support an (unsigned) __int128 data type, __uint128_t
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
is a user-defined type there, for which the cited specs clearly state how
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
to return it.

WRONG USER INTERPRETATION:  __uint128_t is not a user-defined type.

OUCH!
Which part of my underlined words are not understood?
In the MS-ABI, it is an user-defined type.
clang claims to be ABI-compatible, but it's implementations fails
to support that claim!


If MSVC does not support __int128, how could compile code that use it in the first place ?

Please read my initial post, CAREFULLY: it shows the source I used.

You probably define a custom type (user defined).

Yes, with MSVC: see above!


The clang version is fine, this the the MSVC version that define a type using a compiler reserved name and make assumptions about it.

The fact that you choose to use an other (incompatible) type when compiling with
clang (a compiler define __int128) can hardly be considered a compiler bug.

Don't try to make up any "facts": READ the source I posted!

LLVM/clang CLAIMS(!) to be ABI-compatible with MSVC, for example there
<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.

Now read the specification of the Microsoft ABI
<https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention>

| User-defined types can be returned by value from global functions and
| static member functions. 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.

Just use the same user defined type with clang, and you will get the right behaviour.

Again: start to read what I already posted!
I use clang's own __uint128_t data type and show the assembly it generates,
which is but INCOMPATIBEL with the MS-ABI.

And this is perfectly legit. As the MS-ABI does not support the __int128 type, using it with MSVC is an undefined behaviour.



That the kind of issue you get when defining custom type using compiler
reserved name (double underscore).

OUCH: read again what I wrote, CAREFUL, especially the source I posted.
I don't use a compiler reserved name!

How do you call that then ?

typedef struct {
   unsigned __int64 low;
   unsigned __int64 high;
} __uint128_t;



_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
STOP POSTING HTML!

> Le 5 sept. 2020 à 23:42, Stefan Kanthak <[hidden email]> a écrit :

[...]

> The clang version is fine,

WRONG: it violates the MS-ABI!
Remember: it's clang that claims to be compatible with a specification
written and implemented by Microsoft!

> this the the MSVC version that define a type using a compiler reserved name and make
> assumptions about it.

ARGH, again: MSVC is not the problem here, but clang!
It doesn't matter whether the user-defined type is named __uint128_t or dummy,
MSVC generates exactly the same code, ALWAYS:

--- clang-bug-demo.c ---
#ifndef __clang__
typedef struct {
    unsigned __int64 low;
    unsigned __int64 high;
} dummy;
#else
#define dummy __uint128_t
__attribute__((ms_abi))
#endif
dummy __udivmodti4(dummy dividend, dummy divisor, dummy *remainder) {
    if (remainder != 0)
        *remainder = divisor;
    return dividend;
}
--- EOF ---

>> Again: start to read what I already posted!
>> I use clang's own __uint128_t data type and show the assembly it generates,
>> which is but INCOMPATIBEL with the MS-ABI.
>
> And this is perfectly legit.

WRONG!

> As the MS-ABI does not support the __int128 type, using it with MSVC is an undefined behaviour.

The MS-ABI supports user-defined types. And specifies EXPLICITLY how to
handle them when used as return value that doesn't fit in RAX..
clang claims to be compatible, but this is a BLATANT LIE!

Stefan

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
In reply to this post by Hollman, Daisy Sophia via cfe-dev

Bug reports are appreciated, but the hyperbole (eg: "complete misunderstanding"), demands, condescension, and antagonism are not acceptable in this forum. You've been repeatedly asked to adjust your tone/writing style/approach - please do so.
http://lists.llvm.org/pipermail/llvm-dev/2018-December/128333.html
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144548.html
http://lists.llvm.org/pipermail/llvm-dev/2018-November/127960.html
http://lists.llvm.org/pipermail/llvm-dev/2018-November/127994.html
http://lists.llvm.org/pipermail/llvm-dev/2018-December/128206.html
http://lists.llvm.org/pipermail/llvm-dev/2018-December/128295.html
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144513.html
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144507.html
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144503.html
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144489.html
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144479.html

On Thu, Sep 3, 2020 at 9:51 AM Stefan Kanthak via cfe-dev <[hidden email]> 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!


Microsoft's CL.EXE -c -Ox generates the following (of course)
CONFORMANT code:

__unopti4 proc public
; Line 10
        test    r9, r9
        je      SHORT $LN1@unopti4
; 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@unopti4:
; 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
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: BUG: complete misunterstanding of the MS-ABI

Hollman, Daisy Sophia via cfe-dev
In reply to this post by Hollman, Daisy Sophia via cfe-dev
On Sun, 6 Sep 2020 at 12:30, Stefan Kanthak via cfe-dev <[hidden email]> wrote:
STOP POSTING HTML!

Please don't come into our mailing list and post rude messages and demand that we conform to your expectations of mailing list etiquette. HTML mails are fine here. Your repeated rude comments are not. Please take a minute to decide whether you want to participate in our community or not; if you do, please try to follow our communication norms.

> Le 5 sept. 2020 à 23:42, Stefan Kanthak <[hidden email]> a écrit :

[...]

> The clang version is fine,

WRONG: it violates the MS-ABI!

No, it doesn't. The __int128 type is a clang extension, and as such the MS ABI specification does not cover its ABI. If you want ABI compatibility between two compilers, you need to use the same types in both cases. You didn't -- you used __int128 on the Clang side and a struct on the MS ABI side -- so you broke the rules, and you can't expect ABI compatibility.
 
Remember: it's clang that claims to be compatible with a specification
written and implemented by Microsoft!

> this the the MSVC version that define a type using a compiler reserved name and make
> assumptions about it.

ARGH, again: MSVC is not the problem here, but clang!
It doesn't matter whether the user-defined type is named __uint128_t or dummy,
MSVC generates exactly the same code, ALWAYS:

--- clang-bug-demo.c ---
#ifndef __clang__
typedef struct {
    unsigned __int64 low;
    unsigned __int64 high;
} dummy;
#else
#define dummy __uint128_t
__attribute__((ms_abi))
#endif
dummy __udivmodti4(dummy dividend, dummy divisor, dummy *remainder) {
    if (remainder != 0)
        *remainder = divisor;
    return dividend;
}
--- EOF ---

>> Again: start to read what I already posted!
>> I use clang's own __uint128_t data type and show the assembly it generates,
>> which is but INCOMPATIBEL with the MS-ABI.
>
> And this is perfectly legit.

WRONG!

> As the MS-ABI does not support the __int128 type, using it with MSVC is an undefined behaviour.

The MS-ABI supports user-defined types.

As has been explained, __int128 is not a user-defined type. It's a scalar integer type.
 
And specifies EXPLICITLY how to
handle them when used as return value that doesn't fit in RAX..
clang claims to be compatible, but this is a BLATANT LIE!

Stefan

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev