Processor specific
This lists the low-level optimizations performed, on a processor per processor basis.
Intel 80x86 specific
Here follows a listing of the optimizing techniques used in the compiler:
When optimizing for a specific Processor (
-Op1, -Op2, -Op3, the following is done:In
casestatements, a check is done whether a jump table or a sequence of conditional jumps should be used for optimal performance.Determines a number of strategies when doing peephole optimization, e.g.:
movzbl (%ebp), %eaxwill be changed intoxorl %eax,%eax; movb (%ebp),%alfor Pentium and PentiumMMX.
When optimizing for speed (
-OG, the default) or size (-Os), a choice is made between using shorter instructions (for size) such asenter $4, or longer instructionssubl $4,%espfor 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.Fast optimizations (
-O1): activate the peephole optimizerSlower optimizations (
-O2): also activate the common subexpression elimination (formerly called the "reloading optimizer")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.
Remark: If uncertain optimizations are enabled, the CSE algorithm 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 both write and read local or global variables directly and through pointers (this includes
Varparameters, 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); 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
Tempboth through its nameTempand through a pointer, in this case using theBarvariable parameter, which is nothing but a pointer toTempin 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 pointer10.
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
MyRecArrayPtris not accessed directly, but only through a pointer (MyRecPtrin this case).In conclusion, one could say that you can use uncertain optimizations only when you know what you’re doing.
Motorola 680x0 specific
Using the -O2 (the default) switch does several optimizations in the code produced, the most notable being:
Sign extension from byte to long will use
EXTB.Returning of functions will use
RTD.Range checking will generate no run-time calls.
Multiplication will use the long
MULSinstruction, no runtime library call will be generated.Division will use the long
DIVSinstruction, no runtime library call will be generated.
An experiment, built from development snapshots. Not the official Free Pascal or Lazarus documentation.
