The MS x64 ABI calling convention
(http://msdn.microsoft.com/en-us/library/ms235286(VS.80).aspx) says:
    Any argument that doesn’t fit in 8 bytes, or is not 1, 2, 4, or 8 bytes,
must be passed by reference.
Clang isn't doing that for us when passing our triple,
x86_64-pc-win32-macho.
Here's a simple example program:
    struct Guid {
      unsigned int    Data1;
      unsigned short  Data2;
      unsigned short  Data3;
      unsigned char   Data4[8];
    };
    struct Guid g = { 0x8faf43c9, 0x85e9, 0x41f9, { 0xbe, 0x42, 0x99, 0x96, 0x4,
0xe0, 0x85, 0xb3 } };
    void v(int, ...);
    void byValue(void)
    {
      v(1, g);
    }
    void byReference(void)
    {
      v(1, &g);
    }
And the disassembled output:
    _byValue:
    0000000000000000	pushq	%rbp
    0000000000000001	movq	%rsp,%rbp
    0000000000000004	subq	$0x30,%rsp
    0000000000000008	movq	0x00000008(%rip),%rax
    000000000000000f	movq	%rax,0xf8(%rbp)
    0000000000000013	movq	0x00000000(%rip),%rax
    000000000000001a	movq	%rax,0xf0(%rbp)
    000000000000001e	movq	0xf0(%rbp),%rdx
    0000000000000022	movq	0xf8(%rbp),%r8
    0000000000000026	movl	$0x00000001,%ecx
    000000000000002b	callq	0x00000030
    0000000000000030	addq	$0x30,%rsp
    0000000000000034	popq	%rbp
    0000000000000035	ret
    _byReference:
    0000000000000040	pushq	%rbp
    0000000000000041	movq	%rsp,%rbp
    0000000000000044	subq	$0x20,%rsp
    0000000000000048	movl	$0x00000001,%ecx
    000000000000004d	leaq	0x00000000(%rip),%rdx
    0000000000000054	callq	0x00000059
    0000000000000059	addq	$0x20,%rsp
    000000000000005d	popq	%rbp
    000000000000005e	ret
The same program's output from MSVC:
    0000000000000000 <byValue>:
       0:   48 56                   rex.W push   %rsi
       2:   57                      push   %rdi
       3:   48 83 ec 38             sub    $0x38,%rsp
       7:   48 8d 44 24 20          lea    0x20(%rsp),%rax
       c:   48 8d 0d 00 00 00 00    lea    0x0(%rip),%rcx        # 13
<byValue+0x13>
      13:   48 8b f8                mov    %rax,%rdi
      16:   48 8b f1                mov    %rcx,%rsi
      19:   b9 10 00 00 00          mov    $0x10,%ecx
      1e:   f3 a4                   rep movsb %ds:(%rsi),%es:(%rdi)
      20:   48 8d 54 24 20          lea    0x20(%rsp),%rdx
      25:   b9 01 00 00 00          mov    $0x1,%ecx
      2a:   e8 00 00 00 00          callq  2f <byValue+0x2f>
      2f:   48 83 c4 38             add    $0x38,%rsp
      33:   5f                      pop    %rdi
      34:   5e                      pop    %rsi
    0000000000000040 <byReference>:
      40:   48 83 ec 28             sub    $0x28,%rsp
      44:   48 8d 15 00 00 00 00    lea    0x0(%rip),%rdx        # 4b
<byReference+0xb>
      4b:   b9 01 00 00 00          mov    $0x1,%ecx
      50:   e8 00 00 00 00          callq  55 <byReference+0x15>
      55:   48 83 c4 28             add    $0x28,%rsp
      59:   c3                      retq   
As you can see, MSVC is making a copy of the structure and then passing a
pointer to it in the byValue() call, whereas clang is actually stuffing the
whole structure into the parameter transfer registers and spilling over onto the
stack.  Does clang support the MSVC style calling convention?  Did I miss
something when submitting our earlier patches?
Background information - we have a printf-like function in EFI that has a
"%g" format string for printing GUIDs.  It looks like there's some
sloppy code around that calls that print function with GUIDs, rather than with
pointers to GUIDs as the print function expects.  On MSVC, because of this
calling convention detail, it works fine - clang-built ROMs crash spectacularly.
Thanks for any suggestions or ideas!  I'll happily try to come up with a
patch if someone can point me in the right general direction in the source tree!
-- Carl
NAKAMURA Takumi
2011-Feb-22  00:51 UTC
[LLVMdev] Passing structures as pointers, MSVC x64 style
Carl,
See clang/lib/CodeGen/TargetInfo.cpp.
    // FIXME: mingw64-gcc emits 128-bit struct as i128
    if (Size <= 128 &&
        (Size & (Size - 1)) == 0)
      return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
                                                          Size));
It was my workaround, sorry.
Please check to tweak the clause (128 to 64) and lemme know.
...Takumi
On Tue, Feb 22, 2011 at 7:58 AM, Carl Norum <carl.norum at apple.com>
wrote:>
> The MS x64 ABI calling convention
(http://msdn.microsoft.com/en-us/library/ms235286(VS.80).aspx) says:
>
>    Any argument that doesn’t fit in 8 bytes, or is not 1, 2, 4, or 8 bytes,
must be passed by reference.
>
> Clang isn't doing that for us when passing our triple,
x86_64-pc-win32-macho.
>
> Here's a simple example program:
>
>    struct Guid {
>      unsigned int    Data1;
>      unsigned short  Data2;
>      unsigned short  Data3;
>      unsigned char   Data4[8];
>    };
>
>    struct Guid g = { 0x8faf43c9, 0x85e9, 0x41f9, { 0xbe, 0x42, 0x99, 0x96,
0x4, 0xe0, 0x85, 0xb3 } };
>
>    void v(int, ...);
>
>    void byValue(void)
>    {
>      v(1, g);
>    }
>
>    void byReference(void)
>    {
>      v(1, &g);
>    }
>
> And the disassembled output:
>
>    _byValue:
>    0000000000000000    pushq   %rbp
>    0000000000000001    movq    %rsp,%rbp
>    0000000000000004    subq    $0x30,%rsp
>    0000000000000008    movq    0x00000008(%rip),%rax
>    000000000000000f    movq    %rax,0xf8(%rbp)
>    0000000000000013    movq    0x00000000(%rip),%rax
>    000000000000001a    movq    %rax,0xf0(%rbp)
>    000000000000001e    movq    0xf0(%rbp),%rdx
>    0000000000000022    movq    0xf8(%rbp),%r8
>    0000000000000026    movl    $0x00000001,%ecx
>    000000000000002b    callq   0x00000030
>    0000000000000030    addq    $0x30,%rsp
>    0000000000000034    popq    %rbp
>    0000000000000035    ret
>
>    _byReference:
>    0000000000000040    pushq   %rbp
>    0000000000000041    movq    %rsp,%rbp
>    0000000000000044    subq    $0x20,%rsp
>    0000000000000048    movl    $0x00000001,%ecx
>    000000000000004d    leaq    0x00000000(%rip),%rdx
>    0000000000000054    callq   0x00000059
>    0000000000000059    addq    $0x20,%rsp
>    000000000000005d    popq    %rbp
>    000000000000005e    ret
>
> The same program's output from MSVC:
>
>    0000000000000000 <byValue>:
>       0:   48 56                   rex.W push   %rsi
>       2:   57                      push   %rdi
>       3:   48 83 ec 38             sub    $0x38,%rsp
>       7:   48 8d 44 24 20          lea    0x20(%rsp),%rax
>       c:   48 8d 0d 00 00 00 00    lea    0x0(%rip),%rcx        # 13
<byValue+0x13>
>      13:   48 8b f8                mov    %rax,%rdi
>      16:   48 8b f1                mov    %rcx,%rsi
>      19:   b9 10 00 00 00          mov    $0x10,%ecx
>      1e:   f3 a4                   rep movsb %ds:(%rsi),%es:(%rdi)
>      20:   48 8d 54 24 20          lea    0x20(%rsp),%rdx
>      25:   b9 01 00 00 00          mov    $0x1,%ecx
>      2a:   e8 00 00 00 00          callq  2f <byValue+0x2f>
>      2f:   48 83 c4 38             add    $0x38,%rsp
>      33:   5f                      pop    %rdi
>      34:   5e                      pop    %rsi
>
>    0000000000000040 <byReference>:
>      40:   48 83 ec 28             sub    $0x28,%rsp
>      44:   48 8d 15 00 00 00 00    lea    0x0(%rip),%rdx        # 4b
<byReference+0xb>
>      4b:   b9 01 00 00 00          mov    $0x1,%ecx
>      50:   e8 00 00 00 00          callq  55 <byReference+0x15>
>      55:   48 83 c4 28             add    $0x28,%rsp
>      59:   c3                      retq
>
> As you can see, MSVC is making a copy of the structure and then passing a
pointer to it in the byValue() call, whereas clang is actually stuffing the
whole structure into the parameter transfer registers and spilling over onto the
stack.  Does clang support the MSVC style calling convention?  Did I miss
something when submitting our earlier patches?
>
> Background information - we have a printf-like function in EFI that has a
"%g" format string for printing GUIDs.  It looks like there's some
sloppy code around that calls that print function with GUIDs, rather than with
pointers to GUIDs as the print function expects.  On MSVC, because of this
calling convention detail, it works fine - clang-built ROMs crash spectacularly.
>
> Thanks for any suggestions or ideas!  I'll happily try to come up with
a patch if someone can point me in the right general direction in the source
tree!
>
> -- Carl
>
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
On Feb 21, 2011, at 4:51 PM, NAKAMURA Takumi wrote:> Carl, > > See clang/lib/CodeGen/TargetInfo.cpp. > > // FIXME: mingw64-gcc emits 128-bit struct as i128 > if (Size <= 128 && > (Size & (Size - 1)) == 0) > return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), > Size)); > > It was my workaround, sorry. > Please check to tweak the clause (128 to 64) and lemme know.Hi Takumi, I think you hit the nail on the head with that one. Changing that constant to 64 seems to have done the trick. Here's the new disassembled output: _byValue: 0000000000000000 pushq %rbp 0000000000000001 movq %rsp,%rbp 0000000000000004 subq $0x30,%rsp 0000000000000008 leaq 0xf0(%rbp),%rdx 000000000000000c movq 0x00000008(%rip),%rax 0000000000000013 movq %rax,0xf8(%rbp) 0000000000000017 movq 0x00000000(%rip),%rax 000000000000001e movq %rax,0xf0(%rbp) 0000000000000022 movl $0x00000001,%ecx 0000000000000027 callq 0x0000002c 000000000000002c addq $0x30,%rsp 0000000000000030 popq %rbp 0000000000000031 ret %rdx is now getting the address of a copy of the struct! Patch attached; if it looks good to you I'll commit it. -- Carl -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: msabi_patch.txt URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110221/8968ede5/attachment.txt>