3

最大配列要素を検索するには、Delphiでasm関数を作成する必要があります。だから私が書いたワット。ここでいくつかのprolbemを手に入れました。

まずmov ecx, len、ここでは正しく機能しません。実際には、の値は置き換えられますが、 !ECXの値は置き換えられません。lenそして、例を挙げればmov ecx, 5、ecxに5が表示されます。

2番目-この関数を5つの要素の配列でテストします(mov ecx, 5ofcを使用)。奇妙な結果が返されます。このように配列0の要素を読み込もうとしたときに、私が何かをしているせいかもしれません。

mov edx, arr
      lea ebx, dword ptr [edx]

でもこんな風に読めば

  lea ebx, arr

操作が無効だと書いてありますので、こうやってみたら

lea bx, arr

サイズが一致しないということです。

どうすればこの問題を解決できますか?ここに完全なコード:

 program Project2;

    {$APPTYPE CONSOLE}

    uses
      SysUtils;

    Type
      TMyArray = Array [0..255] Of Byte;



    function randArrCreate(len:Integer):TMyArray;
    var temp:TMyArray; i:Integer;
    begin
      Randomize;
      for i:=0 to len-1 do
        temp[i]:=Random(100);
      Result:= temp;
    end;

    procedure arrLoop(arr:TMyArray; len:Integer);
    var i:integer;
    begin
      for i:=0 to len-1 do begin
          Write(' ');
          Write(arr[i]);
          Write(' ');
        end;
    end;

    function arrMaxAsm(arr:TMyArray; len:integer):Word; assembler;
    asm
      mov edx, arr
      lea ebx, dword ptr [edx]
      mov ecx, len
      xor ax,ax  //0
      mov ax, [ebx]  //max

      @cycle:
        mov dx, [ebx]
        cmp dx, ax
        jg @change
        jmp @cont
      @change:
        mov ax, dx
      @cont:
        inc ebx
      loop @cycle

      mov result, ax
    end;


    var massive:TMyArray; n,res:Integer;
    begin
      Readln(n);
      massive:=randArrCreate(n);//just create random array
      arrLoop(massive,n);//just to show what in it
      res:=arrMaxAsm(massive, n);
      Writeln(res);
      Readln(n);
    end.
4

1 に答える 1

3

まず、呼び出し規約:どのデータが関数に送信され、どこに送信されますか?

ドキュメントによると、配列はデータへの32ビットポインタとして渡され、整数は値として渡されます。

同じドキュメントによると、複数の呼び出し規約がサポートされています。残念ながら、デフォルトのものは文書化されていません。明示的に指定することをお勧めします。

うまくいかないあなたの説明に基づいてmov ecx, len、私はコンパイラregisterがデフォルトで規則を使用し、引数がすでにとに配置されていecxedx、それからあなたのコードがそれらを混ぜ合わせたと推測しています。その規則で機能するようにコードを変更するか、スタックを使用して引数を渡すようにコンパイラーに指示することができます-stdcall規則を使用してください。私は任意に2番目のオプションを選びました。どちらを選択する場合でも、呼び出し規約を明示的に指定してください。


次に、実際の機能ロジック。

  1. フル32ビットレジスタではなく16ビットレジスタを使用している理由はありますか?
  2. 配列にはバイトが含まれていますが、単語を読み取って比較しています。
  3. lea ebx, dword ptr [edx]と同じmov ebx, edxです。別の一時変数を導入しているだけです。
  4. 署名されているかのように要素を比較しています。
  5. 最近のコンパイラは、を使用せずにループを実装する傾向がありますloop
  6. また、ドキュメントには、ebx保存する必要があると記載されています。関数はを使用するため、ebx元の値を最初に保存し、後で復元する必要があります。

これが私があなたの関数を書き直した方法です(私は約8年間Delphiに触れていないのでLazarusを使用しています-手の届くところにコンパイラはありません):

function arrMaxAsm(arr:TMyArray; len:integer):Word; assembler; stdcall;
 asm
  push ebx                 { save ebx }

  lea edx, arr             { Lazarus accepts a simple "mov edx, arr" }
  mov edx, [edx]           { but Delphi 7 requires this indirection }

  mov ecx, len
  xor ax, ax               { set default max to 0 }
  test ecx, ecx
  jle @done                { if len is <= 0, nothing to do }
  movzx ax, byte ptr [edx] { read a byte, zero-extend it to a word } 
                           { and set it as current max }

 @cont:
  dec ecx                  
  jz @done                 { if no elements left, return current max }

 @cycle:
  inc edx
  movzx bx, byte ptr [edx] { read next element, zero-extend it }
  cmp bx, ax               { compare against current max as unsigned quantities }
  jbe @cont
  mov ax, bx
  jmp @cont

 @done:
  pop ebx                  { restore saved ebx }
  mov result, ax
end;

ループジャンプ(YMMV)を再編成することで、さらに最適化できる可能性があります。


:これは、バイトサイズの符号なし値に対してのみ正しく機能します。異なるサイズ/符号付きの値に適応させるには、いくつかの変更を行う必要があります。

データサイズ:

  1. 適切なバイト数を読み取ります。
    movzx bx, byte ptr [edx]  { byte-sized values }

    mov bx, word ptr [edx]    { word-sized values }

    mov ebx, dword ptr [edx]  { dword-sized values }
                              { note that the full ebx is needed to store this value... }

この読み取りは2か所で行われることに注意してください。dwordsを扱っている場合は、結果をからに変更する必要もありaxますeax

  1. 適切なバイト数を超えて進みます。
     @cycle:
      inc edx    { for an array of bytes }

      add edx, 2 { for an array of words }

      add edx, 4 { for an array of dwords }

符号付きの値の処理:

  1. 値の拡張が適用されている場合は、からに変更する必要がありmovzxますmovsx

  2. 新しい最大値を設定する前の条件付きジャンプを調整する必要があります。

      cmp bx, ax         { compare against current max as unsigned quantities }
      jbe @cont

      cmp bx, ax         { compare against current max as signed quantities }
      jle @cont
于 2012-11-17T15:38:18.490 に答える