10

人々は、Delphi は整数演算で非常に優れた最適化されたコードを生成すると言いました。Delphi 2007 で次の例を試してみると、コンパイラによって生成されたアセンブリ コードが表示されます。

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.

ビルド構成が DEBUG に設定されている場合、次のように、ブレークポイントを設定し、ショートキーCtrl+ Alt+Dを使用してそのアセンブリ コードを表示できます。

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

私が理解できる限りHigh()、ループ内で関数を何度も呼び出します。

Project3.dpr.13: if (i = High(arr)) then
    004045B2 8B45FC           mov eax,[ebp-$04]
    004045B5 E8E6FAFFFF       **call @DynArrayHigh**
    004045BA 3BD8             cmp ebx,eax

ビルド構成が RELEASE に設定されている場合、ブレークポイントは使用できないため、F8/を押しF7てループにステップ インします。

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

繰り返しますが、同じことcall @DynArrayHighが生成されます...
私の質問は、コンパイラがこれを最適化できないのはなぜですか? High()配列サイズは変更されないため、値をローカルレジスタ/変数に保存するだけです。

4

1 に答える 1

9

これは答えではなく、(自己破壊的な)コメントです:)

私の見解では、コンパイラはこれを最適化しようとしてはなりません。

Highコンパイラが他の関数とは対照的に(非決定論的)関数を最適化しようとする必要があるのはなぜですか?(などLength

動的配列の長さは、ループ内SetLenthで、または他の方法で変更される可能性があります。配列は実行時に再初期化される可能性があり、コードはそれに依存する可能性があります。

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;

これを最適化する必要があることをどのように提案しますか?コンパイラはこれを最適化することさえ試みるべきですか?コンパイラがfunctionmをに変換しても、functionmについて特別なことは何もわかりません。High@DynArrayHigh

コードを最適化する場合は、自分で最適化してください。例:

var
  arrHigh: Integer;

  arrHigh := High(arr);
  for i := 0 to arrHigh do
    if i = arrHigh then...
于 2013-03-13T18:42:58.183 に答える