Optimize Low and High for Integer
Summary
Looking for a weird slowness in a code, I think I find a weird problem in optimizer.
System Information
Lazarus 2.3.0 (rev main-2_3-1804-g43e385a90b) FPC 3.3.1 x86_64-win64-win32/win64
Example Project
program project1;
uses
SysUtils;
function Check1Integer(Index: Integer; const Value: TCharArray; const A: TCharArray): Integer; inline;
var
I, J: Integer;
begin
for I := Index to High(Value) do
for J := Low(A) to High(A) do
if Value[I] = A[J] then
Exit(I);
Result := -1;
end;
function Check2Integer(Index: Integer; const Value: TCharArray; const A: TCharArray): Integer; inline;
var
I, J, L, H: Integer;
begin
L := Low(A);
H := High(A);
for I := Index to High(Value) do
for J := L to H do
if Value[I] = A[J] then
Exit(I);
Result := -1;
end;
function Test1Check1Integer(const Value: TCharArray; const A: TCharArray): Integer;
var
I: Integer;
begin
Result := 0;
I := 0;
repeat
I := Check1Integer(I, Value, A);
I += 1;
Result += 1;
until I = 0;
Result -= 1;
end;
function Test1Check2Integer(const Value: TCharArray; const A: TCharArray): Integer;
var
I: Integer;
begin
Result := 0;
I := 0;
repeat
I := Check2Integer(I, Value, A);
I += 1;
Result += 1;
until I = 0;
Result -= 1;
end;
procedure Test2Check1Integer(const Value: TCharArray; const A: TCharArray);
var
I: Integer;
begin
I := 0;
repeat
I := Check1Integer(I, Value, A);
I += 1;
until I = 0;
end;
procedure Test2Check2Integer(const Value: TCharArray; const A: TCharArray);
var
I: Integer;
begin
I := 0;
repeat
I := Check2Integer(I, Value, A);
I += 1;
until I = 0;
end;
procedure Test3Check1Integer(const Value: TCharArray; const A: TCharArray);
var
I: Integer;
begin
for I := 0 to High(Value) do
Check1Integer(I, Value, A);
end;
procedure Test3Check2Integer(const Value: TCharArray; const A: TCharArray);
var
I: Integer;
begin
for I := 0 to High(Value) do
Check2Integer(I, Value, A);
end;
function Check1Int64(Index: Int64; const Value: TCharArray; const A: TCharArray): Int64; inline;
var
I, J: Int64;
begin
for I := Index to High(Value) do
for J := Low(A) to High(A) do
if Value[I] = A[J] then
Exit(I);
Result := -1;
end;
function Check2Int64(Index: Int64; const Value: TCharArray; const A: TCharArray): Int64; inline;
var
I, J, L, H: Int64;
begin
L := Low(A);
H := High(A);
for I := Index to High(Value) do
for J := L to H do
if Value[I] = A[J] then
Exit(I);
Result := -1;
end;
function Test1Check1Int64(const Value: TCharArray; const A: TCharArray): Int64;
var
I: Int64;
begin
Result := 0;
I := 0;
repeat
I := Check1Int64(I, Value, A);
I += 1;
Result += 1;
until I = 0;
Result -= 1;
end;
function Test1Check2Int64(const Value: TCharArray; const A: TCharArray): Int64;
var
I: Int64;
begin
Result := 0;
I := 0;
repeat
I := Check2Int64(I, Value, A);
I += 1;
Result += 1;
until I = 0;
Result -= 1;
end;
procedure Test2Check1Int64(const Value: TCharArray; const A: TCharArray);
var
I: Int64;
begin
I := 0;
repeat
I := Check1Int64(I, Value, A);
I += 1;
until I = 0;
end;
procedure Test2Check2Int64(const Value: TCharArray; const A: TCharArray);
var
I: Int64;
begin
I := 0;
repeat
I := Check2Int64(I, Value, A);
I += 1;
until I = 0;
end;
procedure Test3Check1Int64(const Value: TCharArray; const A: TCharArray);
var
I: Int64;
begin
for I := 0 to High(Value) do
Check1Int64(I, Value, A);
end;
procedure Test3Check2Int64(const Value: TCharArray; const A: TCharArray);
var
I: Int64;
begin
for I := 0 to High(Value) do
Check2Int64(I, Value, A);
end;
var
A: TCharArray = (#0);
Tick: QWord;
Value: TCharArray;
begin
SetLength(Value, 1000000000);
Tick := GetTickCount64;
Test1Check1Integer(Value, A);
WriteLn('Test1Check1Integer: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test1Check2Integer(Value, A);
WriteLn('Test1Check2Integer: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test2Check1Integer(Value, A);
WriteLn('Test2Check1Integer: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test2Check2Integer(Value, A);
WriteLn('Test2Check2Integer: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test3Check1Integer(Value, A);
WriteLn('Test3Check1Integer: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test3Check2Integer(Value, A);
WriteLn('Test3Check2Integer: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test1Check1Int64(Value, A);
WriteLn('Test1Check1Int64: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test1Check2Int64(Value, A);
WriteLn('Test1Check2Int64: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test2Check1Int64(Value, A);
WriteLn('Test2Check1Int64: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test2Check2Int64(Value, A);
WriteLn('Test2Check2Int64: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test3Check1Int64(Value, A);
WriteLn('Test3Check1Int64: ', GetTickCount64 - Tick);
Tick := GetTickCount64;
Test3Check2Int64(Value, A);
WriteLn('Test3Check2Int64: ', GetTickCount64 - Tick);
ReadLn;
end.
What is the current bug behavior?
These are the times, In all cases the Check1 and Check2 versions should take the same time or Check2 be slower. But it is not the case and even different results for Integer and Int64. This issue happen for three cases I marked in this log.
Test1Check1Integer: 1750[1]
Test1Check2Integer: 1406[1]
Test2Check1Integer: 1953
Test2Check2Integer: 1953
Test3Check1Integer: 1735[2]
Test3Check2Integer: 1515[2]
Test1Check1Int64: 1297
Test1Check2Int64: 1734
Test2Check1Int64: 1938[3]
Test2Check2Int64: 1734[3]
Test3Check1Int64: 1313
Test3Check2Int64: 1297
Here is the assembly output: project1.s