GCC/Clang 未优化静态全局变量
GCC 似乎无法跟踪和优化在 C/C++ 中读/写全局变量的程序,即使它们是静态的,这应该允许它保证其他编译单元不会改变变量。
编译代码时
static int test = 0;
int abc() {
test++;
if (test > 100) \
return 123;
--test;
return 1;
}
int main() {
return abc();
}
使用 GCC 版本使用标志 -Os
(以生成更短且更具可读性的程序集)和 -fwhole-program
或 -flto
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
这GGC 和 Clang 以及我尝试过的所有其他编译器都会发生这种情况。我希望现代编译器能够跟踪程序的流程并删除检查。是否有一些我没有考虑到的东西可能会允许程序外部的东西影响变量,或者这只是尚未在任何编译器中实现?
相关:为什么 gcc 不优化全局变量?那里给出的答案提到了外部函数和线程,两者都不适用于此
GCC does not seem to be able to trace and optimize programs that read/write global variables in C/C++, even if they're static
, which should allow it to guarantee that other compilation units won't change the variable.
When compiling the code
static int test = 0;
int abc() {
test++;
if (test > 100) \
return 123;
--test;
return 1;
}
int main() {
return abc();
}
with the flags -Os
(to produce shorter and more readable assembly) and -fwhole-program
or -flto
using GCC version 11.2 I would expect this to be optimized to return 1
, or the following assembly:
main:
mov eax, 1
ret
This is in fact what is produced if test
is a local variable. However, the following is produced instead:
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
Example: 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为您对大多数编译器的要求有点过高。虽然编译器可能被允许根据 as-if 规则< /a> 在标准中,它显然没有在许多编译器中实现,就像您为 GCC 和 Clang 所说的那样。
我能想到的两个原因是:
在您的示例中,显然链接时间优化决定内联
abc
函数,但没有优化掉test
变量。为此,需要对test
变量的读/写语义进行分析。以通用方式做到这一点非常复杂。在您提供的简单情况下可能是可能的,但任何更复杂的情况都会非常困难。此类优化的用例很少见。全局变量最常用于表示某些共享的全局状态。我没有任何意义去优化它。与大多数程序的好处相比,在编译器/链接器中实现此类功能的工作量会很大。
添加
显然,如果您只读访问该变量,GCC 会优化该变量。如果编译以下内容:
将变量读入局部变量一次并且从不写入它,它会被优化为:(
请参阅 此处进行演示)
然而,使用这样的局部变量会破坏全局变量的全部意义。如果你从不写它,你不妨定义一个常量。
I think you are asking a little bit too much for most of the compilers. While the compiler is probably allowed to optimize the static variable away according to the as-if rule in the standard, it is apparently not implemented in many compilers like you stated for GCC and Clang.
Two reasons I could think of are:
In your example obviously the link time optimization decided to inline the
abc
function, but did not optimize away thetest
variable. For that, an analysis of the read/write semantics of thetest
variable would be needed. This is very complex to do in a generic way. It might be possible in the simple case that you provided, but anything more complex would be really difficult.The use case of such optimizations is rare. Global variables are most often used to represent some shared global state. I makes no sense to optimize that away. The effort for implementing such a feature in a compiler/linker would be large compared to the benefit for most programs.
Addition
Apparently GCC optimizes away the variable if you read-only access it. If you compile the following:
Where you read the variable once into a local variable and never write to it, it gets optimized away to:
(See here for a demo)
However using such a local variable would defeat the whole point of having a global variable. If you never write to it, you might as well define a constant.