Compilers have a certain degree of code optimisation, controlled by the -O flag. No optimisation means there’s no attempt at instruction reordering or performance improvements. -O or -O2 optimise on conservative assumptions. -O3 directs the compiler to be aggressive about optimisation, which may affect the proper functioning of the program.1

Dead code is eliminated, simple arithmetic is pre-calculated, etc, etc. Optimisations are done on the intermediate representation.

This is true for many compilers, including G++.

Optimisation is the most challenging part of modern compiler design compared to front-ends and back-ends, which rely on well-understood techniques. Oftentimes architectures change over time and it’s a challenge to know how to best leverage these additions.

Structure

Optimisers have two main analysis functions:

  • Control flow analysis
  • Data flow analysis

And it then takes multiple optimising passes, many of which do separate small optimisations. For example, GCC has about 100 such passes. Pass flow is not necessarily linear — sometimes it may rely on passes already done.

Footnotes

  1. From IBM’s documentation of AIX.