This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: x86_64 ABI


Hi,

On Thu, 13 Jul 2006, Maurizio Vitale wrote:

> my understanding of the x86_64 ABI is that the following structure should be
> passed in registers:

Right.

> struct data {
> 	unsigned int x;
> 	unsigned int y;
> 	unsigned long z;
> };
> 
> but when I compile:
> 
> #include <stdio.h>
> 
> struct data {
>  unsigned int  x       : 32;
>  unsigned int  y       : 32;
>  unsigned long dummy   : 64;
> } ;

Note that this contains bitfields, which sometimes is handled specially 
in the ABI.  It doesn't matter in this case, but I though I point it out.

> I get different results, depending on whether I compile it as C or C++ code.
> I'm using gcc 4.1.1 (but the same happens with 3.4.5).
> 
> In C I get:
> main:
> .LFB12:
>        subq    $8, %rsp
> .LCFI0:
>        movl    $1, d+8(%rip)
>        movl    $2, d+12(%rip)
>        movq    d(%rip), %rdi
>        movq    d+8(%rip), %rsi
>        call    foo

That doesn't match the layout in the code presented.  It should set d+0 
and d+4 (members x and y are at the start of d).  But let's ignore that.  
The value is passed just fine in registers here, as expected and as you 
said already.

> But in C++ the result is different and the data structure is passed on the
> stack.
> main:
> .LFB13:
>        subq    $24, %rsp
> .LCFI0:
>        movl    $1, d+8(%rip)
>        movq    d(%rip), %rdi
>        movl    $2, d+12(%rip)
>        movq    d+8(%rip), %rsi
>        movq    %rdi, (%rsp)
>        movq    %rsi, 8(%rsp)
>        call    foo

No, nothing is passed on the stack.  To see that you need to look from 
where 'foo' actually reads the arguments.  For a trivial foo I get this 
code:

int foo (data t)
{
  return t.x + t.y;
}

foo:
.LFB13:
        movq    %rdi, -16(%rsp)
        movl    -16(%rsp), %eax
        addl    -12(%rsp), %eax
        ret

Reading from registers, exactly right.  What confused you were the writes 
to some stack memory, which _looks_ as if they are there to pass something 
on the stack.  In reality it's simply a dead store to a dead temporary 
which happened to be placed on the stack and gcc wasn't able to optimize 
away.  To see that look at the GIMPLE code generated by the gcc and g++ 
frontends.  (from t03.gimple).  gcc:

main (argc, argv)
{
  int D.2232;
  int D.2233;

  d.x = 1;
  d.y = 2;
  D.2232 = foo (d);

g++:

int main(int, char**) (argc, argv)
{
  struct data D.2838;
  int D.2839;
  int D.2840;

  d.x = 1;
  d.y = 2;
  D.2838 = d;
  D.2839 = foo (D.2838);

Note the extra temporary D.2838.  The stack write you see correspond to 
"D.2838 = d".  GCC then later was able to optimize the use of D.2838 (as 
call argument) away to directly use d (i.e. %rsi/%rdi which happen to 
contain the value of d after the writes to x and y), but not the store to 
the stack place allocated for D.2838.

That's an artifact how calls are generated in the c++ frontend (it's too 
eagerly using temporaries), but not error.


Ciao,
Michael.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]