Optimizing at level 2

Benefits at level 2

After successfully compiling, executing, and debugging your application using -O0, recompiling at -O2 opens your application to a set of comprehensive low-level transformations that apply to subprogram or compilation unit scopes and can include some inlining. Optimizations at -O2 are a relative balance between increasing performance while limiting the impact on compilation time and system resources. You can increase the memory available to some of the optimizations in the -O2 portfolio by providing a larger value for the -qmaxmem option. Specifying -qmaxmem=-1 allows the optimizer to use memory as needed without checking for limits but does not change the transformations the optimizer applies to your application at -O2.

In C, compile with -qlibansi unless your application defines functions with names identical to those of library functions. If you encounter problems with -O2, consider using -qalias=noansi rather than turning off optimization.

Also, ensure that pointers in your C code follow these type restrictions:
  • Generic pointers can be char* or void*
  • Mark all shared variables and pointers to shared variables volatile

Starting to tune at O2

Choosing the right hardware architecture target or family of targets becomes even more important at -O2 and higher. By targeting the proper hardware, the optimizer can make the best use of the hardware facilities available. If you choose a family of hardware targets, the -qtune option can direct the compiler to emit code consistent with the architecture choice, but executes optimally on the chosen tuning hardware target. With this option, you can compile for a general set of targets but have the code run best on a particular target.

See the Tuning for your system architecture section for details on the -qarch and -qtune options.

The -O2 option can perform a number of additional optimizations, including:
  • Common subexpression elimination: Eliminates redundant instructions.
  • Constant propagation: Evaluates constant expressions at compile-time.
  • Dead code elimination: Eliminates instructions that a particular control flow does not reach, or that generate an unused result.
  • Dead store elimination: Eliminates unnecessary variable assignments.
  • Graph coloring register allocation: Globally assigns user variables to registers.
  • Value numbering: Simplifies algebraic expressions, by eliminating redundant computations.
  • Instruction scheduling for the target machine.
  • Loop unrolling and software pipelining.
  • Moves invariant code out of loops.
  • Simplifies control flow.
  • Strength reduction and effective use of addressing modes.

Even with -O2 optimizations, some useful information about your source code is made available to the debugger if you specify -g. Conversely, higher optimization levels can transform code to an extent to which debug information is no longer accurate. Use that information with discretion.