Betrachten Sie diese einfache Schleife:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 959; i++)
p += 1;
return p;
}
Wenn Sie mit gcc 7 (Snapshot) oder clang (Trunk) kompilieren, erhalten -march=core-avx2 -Ofast
Sie etwas sehr Ähnliches.
.LCPI0_0:
.long 1148190720 # float 960
f: # @f
vmovss xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
ret
Mit anderen Worten, die Antwort wird ohne Schleife auf 960 gesetzt.
Wenn Sie den Code jedoch ändern in:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 960; i++)
p += 1;
return p;
}
Die produzierte Baugruppe führt tatsächlich die Schleifensumme aus? Zum Beispiel gibt 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
Warum ist das so und warum ist es für clang und gcc genau das gleiche?
Die Grenze für die gleiche Schleife , wenn Sie ersetzen float
mit double
ist 479. Dies ist das gleiche wieder für gcc und Klirren ist.
Update 1
Es stellt sich heraus, dass sich gcc 7 (Schnappschuss) und clang (Trunk) sehr unterschiedlich verhalten. clang optimiert die Loops für alle Limits unter 960, soweit ich das beurteilen kann. gcc hingegen reagiert empfindlich auf den genauen Wert und hat keine Obergrenze. Zum Beispiel es nicht optimiert die Schleife, wenn die Grenze 200 (wie auch viele andere Werte), aber es tut , wenn die Grenze 202 und 20002 (sowie viele andere Werte) ist.