Skip to content

Optimizing out and var parameters

Summary

In this sample code, compiler does not put A and B in registers and it slows the result code. In complicated codebases, this slowdown is significant. The same issue can happen if the parameter is out or var, but var is even slower.

System Information

Lazarus 4.99 (rev 4feac3a6f1) FPC 3.3.1 x86_64-win64-win32/win64

Example Project

program project1;

{$MODE Delphi}

uses
  SysUtils;

  procedure NextOut(I: integer; out A, B: integer); inline;
  begin
    A := I + 1;
    B := I + 2;
  end;

  procedure TestOut;
  var
    I, A, B: integer;
  begin
    for I := 1 to 1000 * 1000 * 1000 do
      NextOut(I, A, B);
  end;

  procedure NextVar(I: integer; var A, B: integer); inline;
  begin
    A := I + 1;
    B := I + 2;
  end;

  procedure TestVar;
  var
    I, A, B: integer;
  begin
    for I := 1 to 1000 * 1000 * 1000 do
      NextVar(I, A, B);
  end;


  function NextA(I: integer): integer; inline;
  begin
    Result := I + 1;
  end;

  function NextB(I: integer): integer; inline;
  begin
    Result := I + 2;
  end;

  procedure TestResult;
  var
    I, A, B: integer;
  begin
    for I := 1 to 1000 * 1000 * 1000 do
    begin
      A := NextA(I);
      B := NextB(I);
    end;
  end;

var
  T: QWord;
begin
  T := GetTickCount64;
  TestOut;
  WriteLn(GetTickCount64 - T); //359

  T := GetTickCount64;
  TestVar;
  WriteLn(GetTickCount64 - T); //406

  T := GetTickCount64;
  TestResult;
  WriteLn(GetTickCount64 - T); //313

  ReadLn;
end.

What is the expected (correct) behavior?

The compiler should optimize the TestOut and TestVar as TestResult.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information