我聽到有人說過編譯器經常將循環條件移動到循環底部。也就是說,循環像這樣:爲什麼選擇底部測試循環更好?
while (condition) {
...
}
改爲:
if (condition) {
do {
...
} while (condition);
}
關於機器無關的優化,爲什麼後者最好?
我聽到有人說過編譯器經常將循環條件移動到循環底部。也就是說,循環像這樣:爲什麼選擇底部測試循環更好?
while (condition) {
...
}
改爲:
if (condition) {
do {
...
} while (condition);
}
關於機器無關的優化,爲什麼後者最好?
沒有編譯器的優化,在第一循環進入彙編代碼是這樣的:
@@:
cmp ... ; or test ...
jz @f
...
jmp @b
而第二循環進入到這樣的事情:
jmp bottom
@@:
...
bottom:
cmp ... ; or test ...
jz @b
條件跳轉通常是預測要進行所以第一種方法可能會導致更多的流水線/指令緩存刷新。
但是,最重要的是,對於第一個循環,每個循環迭代有兩個分支可用(2N
),而在第二個循環中,每個循環迭代只有一個分支,第一個無條件跳轉(N+1
)。
有關循環優化的更多信息,請參見此assembly optimisation guide的第88頁。
+1提到分支預測器,但是,您忘記了第二個示例中的無條件跳轉。 (第二個例子是'do'循環,我們需要一個while循環。)你說第二個循環佔用更少的空間是錯誤的。 – 2012-03-20 00:30:44
@KendallFrey:很好的結果,更新了代碼。 – 2012-03-20 00:35:58
從第二個'循環結構'構造的CFG是否具有從第一個循環構造時不存在的任何好處?我的意思是,它是否更容易優化? – JohnTortugo 2012-03-20 01:24:33
你有部分錯誤。典型的優化是這樣的:
jmp $test;
$loop:
; loop statements
$test:
test <condition>;
branch-true $loop;
,而不是這樣的:
$loop:
test <condition>;
branch-false $end;
; loop statements
branch loop;
$end:
其在循環的每次迭代兩個分支。另一個優點是,初始跳轉後的部分與爲do/while
生成的代碼相同。
對於程序集視圖,循環只是跳轉代碼的跳轉指令。所以編譯器需要在循環結尾插入一個跳轉。
許多指令集,如x86,ARM,MIPS都提供了條件跳轉/分支指令。跳躍是否發生取決於指令中指定的條件。
因此編譯器更喜歡這種類型的指令,並將條件移動到循環結尾以利用指令。
實際上,第二個循環不會評估循環頂部的條件。它跳轉到while狀態,在那裏繼續,就像它剛剛完成迭代一樣。 – 2012-03-20 00:32:22