考虑以下 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
是在寄存器中传递给foo
和bar
,使用 中的寄存器访问foo
,并在 中完全忽略bar
。GCC 生成的代码用于foo
. 但是, in 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
(注意a
andb
被传入%rsi
and %rdi
, andc
被传入%rcx
and %rdx
。)
我可以推测的唯一原因是某种 ABI 要求(例如与 longjmp 交互)。我找不到 GCC 的任何优化 ( -f
) 选项,也找不到抑制这种行为的 GCC 特定注释。c
用注释register
没有帮助。
这也发生在不同的目标上。(值得注意的是,在 TileGXfoo
上,堆栈上已分配和释放空间,但没有存储任何内容。)我测试了 GCC 4.4.6 和 4.6.1。
这是预期的行为还是 GCC 中的错误?无论哪种方式,有没有办法解决它(除了使用引用调用或确保bar
可以是一片叶子)?