이 간단한 루프를 고려하십시오.
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
왜 이것이 있으며 왜 clang과 gcc에 대해 정확히 동일합니까?
로 교체 float
하는 경우 동일한 루프의 한계 double
는 479입니다. 이는 gcc 및 clang의 경우에도 동일합니다.
업데이트 1
gcc 7 (스냅 샷)과 clang (트렁크)은 매우 다르게 동작합니다. clang은 내가 말할 수있는 한 960 미만의 모든 한계에 대해 루프를 최적화합니다. 반면에 gcc는 정확한 값에 민감하며 상한이 없습니다. 예를 들어 그것은 않는 한도가 200 인 경우 루프를 최적화 (뿐만 아니라 많은 다른 값)하지만 않는 한도 (202) 및 20002 (뿐만 아니라 많은 다른 값) 인 경우.