พิจารณาลูปง่ายๆนี้:
float f(float x[]) {
float p = 1.0;
for (int i = 0; i < 959; i++)
p += 1;
return p;
}
หากคุณคอมไพล์ด้วย gcc 7 (snapshot) หรือ clang (trunk) ด้วย-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;
}
แอสเซมบลีที่ผลิตทำผลรวมลูปจริงหรือ? ตัวอย่างเสียงดังให้:
.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 (snapshot) และ clang (trunk) ทำงานแตกต่างกันมาก clang ปรับลูปให้เหมาะสมสำหรับขีด จำกัด ทั้งหมดที่น้อยกว่า 960 เท่าที่ฉันสามารถบอกได้ ในทางกลับกัน gcc มีความอ่อนไหวต่อค่าที่แน่นอนและไม่มีขีด จำกัด บน ตัวอย่างเช่นจะไม่เพิ่มประสิทธิภาพของลูปเมื่อขีด จำกัด คือ 200 (รวมถึงค่าอื่น ๆ อีกมากมาย) แต่จะทำเมื่อขีด จำกัด คือ 202 และ 20002 (รวมถึงค่าอื่น ๆ อีกมากมาย)