使用指定初始化程序时的不同 gcc 程序集
Posted
技术标签:
【中文标题】使用指定初始化程序时的不同 gcc 程序集【英文标题】:Different gcc assembly when using designated initializers 【发布时间】:2018-11-26 12:22:34 【问题描述】:我正在检查一些 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 ;
我得到了following output 与 gcc -O2 -std=C11 for ARM (ARM GCC 6.3.0):
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
是否与这些常量有关?
【问题讨论】:
您没有显示.LANCHOR0
,但我认为其中包含您的两个常量。
@Jester:没错,如果我关闭“未使用标签过滤”,我可以find those values.LANCHOR0
。这是有道理的,即使我不明白为什么程序集不同。
【参考方案1】:
在将常量的负载合并到一个 ldm 之后,看起来 gcc 以额外的间接级别在脚上射击自己。
不知道为什么,但很明显是一个错过的优化错误。
x86-64 易于优化;整个 8 字节常量可以立即输入。但是 ARM 经常使用 PC 相关的负载来加载对于一个立即数来说太大的常量。
【讨论】:
更不用说将 r0 复制到 r3 并返回。我想知道是否真的为该代码和第一个代码启用了优化。编辑:是的,它正在......奇怪。 另外,如果我只是从main()
调用这些函数并添加它们的结果,gcc 将计算compile time constant and return it,因此在这种情况下它会正确优化它。也许我可以在某个地方报告这个问题,以便在未来的版本中修复。谢谢!
@Lou:是的,在gcc.gnu.org/bugzilla 报告并使用“missed-optimization”关键字。恒定传播仍然有效也就不足为奇了,但是很高兴知道这个错误的范围是有限的。以上是关于使用指定初始化程序时的不同 gcc 程序集的主要内容,如果未能解决你的问题,请参考以下文章
segueing 时的核心数据错误:无法在 NSManagedObject 类上调用指定的初始化程序