GCC 似乎無法跟蹤和優化在 C/C 中讀/寫全域變數的程式,即使它們是static,這應該允許它保證其他編譯單元不會更改變數。
編譯代碼時
static int test = 0;
int abc() {
test ;
if (test > 100) \
return 123;
--test;
return 1;
}
int main() {
return abc();
}
使用標志-Os(以生成更短且更具可讀性的程式集)和-fwhole-program/或-flto使用 GCC 11.2 版,我希望這可以優化為return 1,或以下程式集:
main:
mov eax, 1
ret
這實際上是如果test是區域變數所產生的。但是,會生成以下內容:
main:
mov eax, DWORD PTR test[rip]
mov r8d, 1
inc eax
cmp eax, 100
jle .L1
mov DWORD PTR test[rip], eax
mov r8d, 123
.L1:
mov eax, r8d
ret
示例:https ://godbolt.org/z/xzrPjanjd
This happens with both GGC and Clang, and every other compiler I tried. I would expect modern compilers to be able to trace the flow of the program and remove the check. Is there something I'm not considering that may allow something external to the program to affect the variable, or is this just not implemented in any compilers yet?
Related: Why gcc isn't optimizing the global variable? but the answer given there mentions external functions and threads, neither of which apply here
uj5u.com熱心網友回復:
我認為您對大多數編譯器的要求有點過高。雖然編譯器可能被允許根據標準中的as-if 規則優化靜態變數,但它顯然沒有在許多編譯器中實作,就像你為 GCC 和 Clang 所說的那樣。
我能想到的兩個原因是:
在您的示例中,顯然鏈接時間優化決定行內
abc函式,但沒有優化test變數。為此,需要分析test變數的讀/寫語意。以通用方式執行此操作非常復雜。在您提供的簡單情況下可能是可能的,但更復雜的情況將非常困難。這種優化的用例很少見。全域變數最常用于表示一些共享的全域狀態。我沒有意義去優化它。與大多數程式的好處相比,在編譯器/聯結器中實作這種功能的作業量會很大。
加法
顯然,如果您只讀訪問它,GCC 會優化該變數。如果您編譯以下內容:
static int test = 0;
int abc() {
int test_ = test;
test_ ;
if (test_ > 100) \
return 123;
--test_;
return 1;
}
int main() {
return abc();
}
如果您將變數一次讀入區域變數并且從不寫入它,它會被優化為:
main:
mov eax, 1
ret
(有關演示,請參見此處)
但是,使用這樣的區域變數會破壞擁有全域變數的全部意義。如果你從不寫它,你不妨定義一個常量。
uj5u.com熱心網友回復:
我在 gcc 11.2 版中遇到了速度優化問題。這可能與您的問題有關嗎?看
https://bbs.archlinux.org/viewtopic.php?pid=2029984
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/456473.html
