Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does Delphi honor `inline` and when not?

I was tying to optimize a piece of code that has this construct:

while (i > 0) do begin
  Dec(i);

This looks inefficient, so I tried to do this:

while (Dec(i) >= 0) do begin

That doesn't work because Dec is a procedure and not a function.

So I rewrite it to:

procedure Withloop;
var
  ....
  function Decr(var a: integer): integer; inline;
  begin
    Dec(a);
    Result:= a;
  end;

...
  while (Decr(i) >= 0) do begin

But this gets compiled into:

SDIMAIN.pas.448: while (Decr(i) >= 0) do begin
00468EE5 8BC4             mov eax,esp
00468EE7 E8D0FEFFFF       call Decr          <<--- A call??
00468EEC 85C0             test eax,eax
00468EEE 0F8D12FFFFFF     jnl $00468e06
00468EF4 EB01             jmp $00468ef7

However in another part of the program, it inlines a function just fine.
What rule of thumb (or hard rule) can I use to know to Delphi will honor the inline directive?

like image 516
Johan Avatar asked Jun 19 '11 10:06

Johan


2 Answers

The Delphi Documentation enumerates the conditions under which inlining does or does not occur:

  • Inlining will not occur on any form of late-bound method. This includes virtual, dynamic, and message methods.
  • Routines containing assembly code will not be inlined.
  • Constructors and destructors will not be inlined.
  • The main program block, unit initialization, and unit finalization blocks cannot be inlined.
  • Routines that are not defined before use cannot be inlined.
  • Routines that take open array parameters cannot be inlined.
  • Code can be inlined within packages, however, inlining never occurs across package boundaries.
  • No inlining is done between units that are circularly dependent. This includes indirect circular dependencies, for example, unit A uses unit B, and unit B uses unit C which in turn uses unit A. In this example, when compiling unit A, no code from unit B or unit C will be inlined in unit A.
  • The compiler can inline code when a unit is in a circular dependency, as long as the code to be inlined comes from a unit outside the circular relationship. In the above example, if unit A also used unit D, code from unit D could be inlined in A, since it is not involved in the circular dependency.
  • If a routine is defined in the interface section and it accesses symbols defined in the implementation section, that routine cannot be inlined.
  • If a routine marked with inline uses external symbols from other units, all of those units must be listed in the uses statement, otherwise the routine cannot be inlined.
  • Procedures and functions used in conditional expressions in while-do and repeat-until statements cannot be expanded inline.
  • Within a unit, the body for an inline function should be defined before calls to the function are made. Otherwise, the body of the function, which is not known to the compiler when it reaches the call site, cannot be expanded inline.

In your case check this condition:

Procedures and functions used in conditional expressions in while-do and repeat-until statements cannot be expanded inline.

like image 131
RRUZ Avatar answered Nov 15 '22 09:11

RRUZ


For some reason the compiler does not inline while loop control expressions. Hallvard Vassbotn discussed the problem some time ago (read the end of the article).

like image 34
kludg Avatar answered Nov 15 '22 09:11

kludg