next up previous contents
Up: Free Pascal programmers guide Previous: Compiler limits

Optimizing techniques used in the compiler.

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

  1. When optimizing for a specific Processor (-O3, -O4, -O5 -O6, the following is done: Cyrix 6x86 processor owners should optimize with -O4 instead of -O5, because -O5 leads to larger code, and thus to smaller speed, according to the Cyrix developers FAQ.
  2. When optimizing for speed (-OG) or size (-Og), 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, things aren't aligned on 4-byte boundaries. When speed is requested, things are aligned on 4-byte boundaries as much as possible.
  3. Simple optimization (-Oa) makes sure the peephole optimizer is used, as well as the reloading optimizer.
  4. Maximum optimization (-Ox) avoids creation of stack frames if they aren't required, and unnecessary loading of registers is avoided as much as possible. (buggy at the moment (version 0.99.0).
  5. Uncertain optimizations (-Oz): With this switch, the reloading optimizer (enabled with -Oa) can be forced into making uncertain optimizations.

    You can enable uncertain optimizations only in certain cases, otherwise you will produce a bug; the following technical description tells you when to use them:

    If uncertain optimizations are enabled, the reloading optimizer assumes that
    • If something is written to a local/global register or a procedure/function parameter, this value doesn't overwrite the value to which a pointer points.
    • If something is written to memory pointed to by a pointer variable, this value doesn't overwrite the value of a local/global variable or a procedure/function parameter.
    The practical upshot of this is that you cannot use the uncertain optimizations if you access any local or global variables through pointers. In theory, this includes Var parameters, but it is all right if you don't both read the variable once through its Var reference and then read it using it's name.

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

    Var temp: Longint;
    
    Procedure Foo(Var Bar: Longint);
    Begin
      If (Bar = temp)
        Then
          Begin
            Inc(Bar);
            If (Bar <> temp) then Writeln('bug!')
          End
    End;
    
    Begin
      Foo(Temp);
    End.
    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 pointergif.

    For example:

    Type TMyRec = Record
                    a, b: Longint;
                  End;
         PMyRec = ^TMyRec;
    
    
         TMyRecArray = Array [1..100000] of TMyRec;
         PMyRecArray = ^TMyRecArray;
    
    Var MyRecArrayPtr: PMyRecArray;
        MyRecPtr: PMyRec;
        Counter: Longint;
    
    Begin
      New(MyRecArrayPtr);
      For Counter := 1 to 100000 Do
        Begin
           MyRecPtr := @MyRecArrayPtr^[Counter];
           MyRecPtr^.a := Counter;
           MyRecPtr^.b := Counter div 2;
        End;
    End.
    Will produce correct code, because the global variable MyRecArrayPtr is not accessed directly, but 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.


next up previous contents
Up: Free Pascal programmers guide Previous: Compiler limits

Michael Van Canneyt
Tue Mar 31 16:50:06 CEST 1998