考虑下面这个简单的循环:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 959; i++)
p += 1;
return p;
}
如果你用gcc 7(快照)或clang (主干)用-march=core-avx2 -Ofast
编译,你会得到非常类似的东西。
.LCPI0_0:
.long 1148190720 # float 960
f: # @f
vmovss xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
ret
换句话说,它只是在没有循环的情况下将答案设置为960。
但是,如果您将代码更改为:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 960; i++)
p += 1;
return p;
}
生成的程序集真的执行循环和吗?例如clang给出了:
.LCPI0_0:
.long 1065353216 # float 1
.LCPI0_1:
.long 1086324736 # float 6
f: # @f
vmovss xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
vxorps ymm1, ymm1, ymm1
mov eax, 960
vbroadcastss ymm2, dword ptr [rip + .LCPI0_1]
vxorps ymm3, ymm3, ymm3
vxorps ymm4, ymm4, ymm4
.LBB0_1: # =>This Inner Loop Header: Depth=1
vaddps ymm0, ymm0, ymm2
vaddps ymm1, ymm1, ymm2
vaddps ymm3, ymm3, ymm2
vaddps ymm4, ymm4, ymm2
add eax, -192
jne .LBB0_1
vaddps ymm0, ymm1, ymm0
vaddps ymm0, ymm3, ymm0
vaddps ymm0, ymm4, ymm0
vextractf128 xmm1, ymm0, 1
vaddps ymm0, ymm0, ymm1
vpermilpd xmm1, xmm0, 1 # xmm1 = xmm0[1,0]
vaddps ymm0, ymm0, ymm1
vhaddps ymm0, ymm0, ymm0
vzeroupper
ret
为什么这一点,为什么对于朗和gcc来说是完全一样的?
如果将float
替换为double
,则同一循环的限制为479。同样的道理也适用于gcc和章子怡。
更新1
事实证明,gcc 7(快照)和clang (主干)的行为非常不同。据我所知,clang为所有小于960的限制优化循环。另一方面,gcc对精确值很敏感,没有上限。例如,当限制为200时(以及许多其他值),它不会对循环进行优化,但当限制为202时和20002 (以及许多其他值)时,它会执行。
https://stackoverflow.com/questions/42159460
复制相似问题