我正在检查一些 gcc 为 ARM 生成的程序集并注意到如果我使用指定的初始化程序我会得到奇怪的结果:
例如如果我有这段代码:
struct test
{
int x;
int y;
};
__attribute__((noinline))
struct test get_struct_1(void)
{
struct test x;
x.x = 123456780;
x.y = 123456781;
return x;
}
__attribute__((noinline))
struct test get_struct_2(void)
{
return (struct test){ .x = 123456780, .y = 123456781 };
}
我使用 gcc -O2 -std=C11 for ARM (ARM GCC 6.3.0) 获得了 following output:
get_struct_1:
ldr r1, .L2
ldr r2, .L2+4
stm r0, {r1, r2}
bx lr
.L2:
.word 123456780
.word 123456781
get_struct_2: // <--- what is happening here
mov r3, r0
ldr r2, .L5
ldm r2, {r0, r1}
stm r3, {r0, r1}
mov r0, r3
bx lr
.L5:
.word .LANCHOR0
我可以看到第一个函数的常量,但我不明白 get_struct_2
是如何工作的。
如果我为 x86 编译,两个函数只会在一条指令中加载相同的单个 64 位值。
get_struct_1:
movabs rax, 530242836987890956
ret
get_struct_2:
movabs rax, 530242836987890956
ret
我是在引发一些未定义的行为,还是这个 .LANCHOR0
与这些常量有某种关联?
最佳答案
在将常量的负载合并到 ldm 之后,看起来 gcc 用额外的间接级别射击自己。
不知道为什么,但很明显是遗漏了一个优化错误。
x86-64 很容易优化;整个 8 字节常量可以放在一个立即数中。但是 ARM 经常使用 PC 相对负载来处理对于一个立即数来说太大的常量。
关于c - 使用指定初始值设定项时不同的 gcc 程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53481048/