次の C99 コードを検討してください。
#include <stdio.h>
#include <stdint.h>
struct baz { uint64_t x, y; };
uint64_t foo(uint64_t a, uint64_t b, struct baz c)
{
return a + b + c.x + c.y;
}
void bar(uint64_t a, uint64_t b, struct baz c)
{
printf("%lu\n", a);
}
でコンパイルした場合、私が期待する動作は、gcc -O3
との両方にc
レジスタで渡され、 でレジスタを使用してアクセスされ、 で完全に無視されることです。GCC は、 に対してこれを行うコードを生成します。ただし、 では、レジスタからスタックにコピーされ、すぐに無視されます。foo
bar
foo
bar
foo
bar
c
.file "pbv.c"
.text
.p2align 4,,15
.globl foo
.type foo, @function
foo:
.LFB22:
.cfi_startproc
leaq (%rcx,%rdx), %rdx
leaq (%rdx,%rdi), %rdi
leaq (%rdi,%rsi), %rax
ret
.cfi_endproc
.LFE22:
.size foo, .-foo
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%lu\n"
.text
.p2align 4,,15
.globl bar
.type bar, @function
bar:
.LFB23:
.cfi_startproc
movq %rdx, -24(%rsp)
movl $.LC0, %esi
movq %rdi, %rdx
xorl %eax, %eax
movl $1, %edi
movq %rcx, -16(%rsp)
jmp __printf_chk
.cfi_endproc
.LFE23:
.size bar, .-bar
.ident "GCC: (Ubuntu/Linaro 4.4.6-11ubuntu2) 4.4.6"
.section .note.GNU-stack,"",@progbits
( and はandに渡され、 andは andにa
渡さb
れることに注意してください。)%rsi
%rdi
c
%rcx
%rdx
これについて推測できる唯一の理由は、ある種の ABI 要件 (たとえば、longjmp との対話) です。-f
GCC の最適化 ( ) オプションも、この動作を阻害する GCC 固有の注釈も見つかりません。で注釈c
を付けregister
ても役に立ちません。
これは、さまざまなターゲットでも発生します。(特に、TileGX ではfoo
、スタックに割り当てられたスペースと割り当て解除されたスペースがありますが、そこには何も格納されません。) GCC 4.4.6 と 4.6.1 の両方をテストしました。
これは予想される動作ですか、それとも GCC のバグですか? いずれにせよ、それを回避する方法はありますか (参照渡しを使用するbar
か、リーフになることができることを確認する以外に)?