People said that Delphi produces quite-nice optimized code on integer operations. I try the following example in Delphi 2007, and see its assembly code produced by the compiler.
program p1000;
{$APPTYPE CONSOLE}
procedure test;
var
arr: array of integer;
i: integer;
begin
SetLength(arr, 100);
for i := 0 to High(arr) do
begin
if (i = High(arr)) then
begin
arr[i] := -9;
end;
end;
end;
begin
test;
readln;
end.
When building configuration is set to DEBUG, I can set a breakpoint and use shortkey Ctrl+Alt+D to see its assembly code, like this:
Project3.dpr.11: for i := 0 to High(arr) do
004045A1 8B45FC mov eax,[ebp-$04]
004045A4 E8F7FAFFFF call @DynArrayHigh
004045A9 8BF0 mov esi,eax
004045AB 85F6 test esi,esi
004045AD 7C1D jl $004045cc
004045AF 46 inc esi
004045B0 33DB xor ebx,ebx
Project3.dpr.13: if (i = High(arr)) then
004045B2 8B45FC mov eax,[ebp-$04]
004045B5 E8E6FAFFFF **call @DynArrayHigh**
004045BA 3BD8 cmp ebx,eax
004045BC 750A jnz $004045c8
Project3.dpr.15: arr[i] := -9;
004045BE 8B45FC mov eax,[ebp-$04]
004045C1 C70498F7FFFFFF mov [eax+ebx*4],$fffffff7
Project3.dpr.17: end;
004045C8 43 inc ebx
Project3.dpr.11: for i := 0 to High(arr) do
004045C9 4E dec esi
004045CA 75E6 jnz $004045b2
As far as I can understand, it calls High() function again and again in the loop:
Project3.dpr.13: if (i = High(arr)) then
004045B2 8B45FC mov eax,[ebp-$04]
004045B5 E8E6FAFFFF **call @DynArrayHigh**
004045BA 3BD8 cmp ebx,eax
When building configuration is set to RELEASE, the breakpoint isn't available, so I press F8/F7 to step into the loop.
00404589 6A64 push $64
0040458B 8D45FC lea eax,[ebp-$04]
0040458E B901000000 mov ecx,$00000001
00404593 8B1554454000 mov edx,[$00404554]
00404599 E8B6FCFFFF call @DynArraySetLength
0040459E 83C404 add esp,$04
004045A1 8B45FC mov eax,[ebp-$04]
004045A4 E8F7FAFFFF call @DynArrayHigh
004045A9 8BF0 mov esi,eax
004045AB 85F6 test esi,esi
004045AD 7C1D jl $004045cc
004045AF 46 inc esi
004045B0 33DB xor ebx,ebx
004045B2 8B45FC mov eax,[ebp-$04]
004045B5 E8E6FAFFFF call @DynArrayHigh
004045BA 3BD8 cmp ebx,eax
004045BC 750A jnz $004045c8
004045BE 8B45FC mov eax,[ebp-$04]
004045C1 C70498F7FFFFFF mov [eax+ebx*4],$fffffff7
004045C8 43 inc ebx
004045C9 4E dec esi
004045CA 75E6 jnz $004045b2
004045CC 33C0 xor eax,eax
004045BC 750A jnz $004045c8
Again, the same call @DynArrayHigh is produced...
So my question is, why the compiler can't optimize this? simply save the High() value in a local register/variable because the array size is not changed.
This is not a answer but rather a (self destructing) comment :)
In my view, The compiler must not attempt to optimize this.
Why should the compiler attempt to optimize a (non-deterministic) High function as opposed to other? (such as Length)
The dynamic array length might be changed inside the loop either by SetLenth, or by other means. the array might be re-initilzed at run-time and your code might depend on that:
for i := 0 to High(arr) do
begin
if (i = High(arr)) then
arr[i] := -9
else
if foo() then
arr := nil; // or SetLength(arr, 0);
if High(arr) = -1 then Exit; // arr is nil
end;
How do you suggest this should be optimized? Should the compiler even attempt to optimized this?
I don't see anything special about High functionm even if the compiler translates it to @DynArrayHigh.
If you want your code to be optimized , optimize it yourself .e.g:
var
arrHigh: Integer;
arrHigh := High(arr);
for i := 0 to arrHigh do
if i = arrHigh then...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With