11.2.1 Intel 80x86 specific

Here follows a listing of the optimizing techniques used in the compiler:

  1. When optimizing for a specific Processor (-Op1, -Op2, -Op3, the following is done:
  2. When optimizing for speed (-OG, the default) or size (-Os), a choice is made between using shorter instructions (for size) such as enter $4, or longer instructions subl $4,%esp for speed. When smaller size is requested, data is aligned to minimal boundaries. When speed is requested, data is aligned on most efficient boundaries as much as possible.
  3. Fast optimizations (-O1): activate the peephole optimizer
  4. Slower optimizations (-O2): also activate the common subexpression elimination (formerly called the ”reloading optimizer”)
  5. Uncertain optimizations (-OoUNCERTAIN): With this switch, the common subexpression elimination algorithm can be forced into making uncertain optimizations.

    Although you can enable uncertain optimizations in most cases, for people who do not understand the following technical explanation, it might be the safest to leave them off.

    RemarkIf uncertain optimizations are enabled, the CSE algorithm assumes that

    The practical upshot of this is that you cannot use the uncertain optimizations if you both write and read local or global variables directly and through pointers (this includes Var parameters, as those are pointers too).

    The following example will produce bad code when you switch on uncertain optimizations:

    Var temp: Longint;  
    Procedure Foo(Var Bar: Longint);  
      If (Bar = temp)  
            If (Bar <> temp) then Writeln('bug!')  

    The reason it produces bad code is because you access the global variable Temp both through its name Temp and through a pointer, in this case using the Bar variable parameter, which is nothing but a pointer to Temp in the above code.

    On the other hand, you can use the uncertain optimizations if you access global/local variables or parameters through pointers, and only access them through this pointer1.

    For example:

    Type TMyRec = Record  
                    a, b: Longint;  
         PMyRec = ^TMyRec;  
         TMyRecArray = Array [1..100000] of TMyRec;  
         PMyRecArray = ^TMyRecArray;  
    Var MyRecArrayPtr: PMyRecArray;  
        MyRecPtr: PMyRec;  
        Counter: Longint;  
      For Counter := 1 to 100000 Do  
           MyRecPtr := @MyRecArrayPtr^[Counter];  
           MyRecPtr^.a := Counter;  
           MyRecPtr^.b := Counter div 2;  

    Will produce correct code, because the global variable MyRecArrayPtr is not accessed directly, but only through a pointer (MyRecPtr in this case).

    In conclusion, one could say that you can use uncertain optimizations only when you know what you’re doing.

1You can use multiple pointers to point to the same variable as well, that doesn’t matter.