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
CodePudding user response:
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 analysation of the read/write semantics of thetest
variable would be possible. 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:
static int test = 0;
int abc() {
int test_ = test;
test_ ;
if (test_ > 100) \
return 123;
--test_;
return 1;
}
int main() {
return abc();
}
Where you read the variable once into a local variable and never write to it, it gets optimized away to:
main:
mov eax, 1
ret
(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.