12 JoP Dec 07
12 JoP Dec 07
12 JoP Dec 07
Programming
The Basics of Compiler Optimisers
S.G. GANESH
It is fun to write programs that do not work and see how they fail (or work, by
chance!). In this column, we use this idea to understand the basics of the
optimiser part of a compiler.
recently read an interesting article [C++ Report, of a const variable also—enum { val = 0 }. Why? Because
I
Vol. 6, no. 3, ‘How to write buggy programs’ by enums are just constant values and are only for integral
Andrew Koenig], which is about writing incorrect values.
programs. I’ve taken the following (slightly How about this statement: const volatile int val = 0;?
modified) piece of code from that article to Yes, first, it is valid to qualify a variable with both const and
illustrate how compiler optimisers work: volatile: the volatile keyword tells the compiler optimiser
not to optimise the code involving that variable and the
extern void foo(); const keyword says that the programmer cannot
int main() { programmatically change the value of the variable. So, a
if(0) foo(); compiler will not optimise the code and the linker will give
} an unsat for this program.
What if the variable is a plain global variable (int val;)?
The foo function is just declared and is not defined in the The program will almost always result in an unsat for foo.
program. The if condition always evaluates to ‘false’. Should Why? Note that the global variables can be modified by any
this program link fine or result in a linker error complaining function in the program, which might be available from some
that the definition of foo is not found? That will depend on other translation unit (independent program file) also.
the compiler. Some smart compilers see that the statement Though it is clear from the control flow of the program that
for if(0) will never get executed, and will therefore not the value of val cannot be changed before the if condition is
generate a call to foo at all—so the linker won’t complain. executed, in general, the optimiser cannot assume anything
However, not all compilers do such smart work in default about the value of val.
compilation mode and hence we might get a linker error. Global variables put compiler optimisers into much
(Such compilers might detect the ‘unreachable function call’ trouble. Globals will require the optimisers to do extensive
at higher levels of optimisation!) The following is what I got analysis across translation units, which usually takes too
when I tried a compiler: much time. And compiler optimisers are not expected to
take unreasonable amounts of compilation time to do
$ cc foo.c runtime speedups; so, typically, optimisers do not perform
ld: Undefined symbol foo; first referenced in file foo.o much optimisation on global variables.
$ cc –O foo.c But optimisers do perform optimisation for functions
$ across translation units, which is known as Inter-Procedural
Optimisation (IPO). IPO can yield significant performance
Try it and see how your compiler behaves. Sounds improvements for the program, and it is typically invoked at
interesting, isn’t it? higher optimisation levels (usually, -O3 level and above). We
Now, what if we modify the expression in the if all know that the compiler invokes the linker for linking
condition, as shown: programs. But, since only the linker knows the details about
all translation units (the .o files) when it attempts to create
const int val = 0; the final shared library or executable, for IPO, the linker will
int main() { invoke the compiler (optimiser) again and do the actual
if(val) foo(); linking work later!
}
CMYK