Hãy xem xét vòng lặp đơn giản này:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 959; i++)
p += 1;
return p;
}
Nếu bạn biên dịch với gcc 7 (ảnh chụp nhanh) hoặc clang (thân cây) với -march=core-avx2 -Ofast
bạn sẽ nhận được một cái gì đó rất giống với.
.LCPI0_0:
.long 1148190720 # float 960
f: # @f
vmovss xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
ret
Nói cách khác, nó chỉ đặt câu trả lời là 960 mà không lặp.
Tuy nhiên nếu bạn thay đổi mã thành:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 960; i++)
p += 1;
return p;
}
Việc lắp ráp sản xuất thực sự thực hiện tổng vòng lặp? Ví dụ clang cho:
.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
Tại sao điều này và tại sao nó giống hệt nhau cho clang và gcc?
Giới hạn cho cùng một vòng lặp nếu bạn thay thế float
bằng double
479. Điều này giống với gcc và tiếng kêu một lần nữa.
Cập nhật 1
Hóa ra gcc 7 (ảnh chụp nhanh) và tiếng kêu (thân cây) hành xử rất khác nhau. clang tối ưu hóa các vòng lặp cho tất cả các giới hạn nhỏ hơn 960 theo như tôi có thể nói. gcc mặt khác nhạy cảm với giá trị chính xác và không có giới hạn trên. Ví dụ, nó không tối ưu hóa vòng lặp khi giới hạn là 200 (cũng như nhiều giá trị khác) nhưng nó thực hiện khi giới hạn là 202 và 20002 (cũng như nhiều giá trị khác).