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.