Thema: Delphi pack-Funktion optimieren

Einzelnen Beitrag anzeigen

jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#3

AW: pack-Funktion optimieren

  Alt 4. Feb 2012, 20:28
Viel lässt sich da nicht optimieren.
Oh, doch. Die 64bit Div- und Mod-Operationen sind sehr teuer und zudem auch nicht für Divisoren kleiner 2^32 optimiert. Und wenn man dann noch das Div und Mod in einem Schwung ermittelt, kann man da noch einiges rausholen.
Aber auch entfernen der String-Konkatenation tut sein übriges dazu.

Delphi-Quellcode:
function UDivMod6432(const Dividend: Int64; Divisor: LongWord; var Rest: LongWord): Int64;
// DivMod64 für "Divisor < 2^32"
{$IFDEF CPUX64}
asm
  // in: RCX = Dividend
  // EDX = Divisor
  // R8 = @Rest
  // out: RAX = Quotient
  mov rax, rcx // Register für die Division (RDX:RAX / RCX) vorbereiten
  mov ecx, edx // Divisor in ECX für die Division schieben
  xor rdx, rdx

  //div ecx // "Divisor < 2^32" ausnutzen
  db $F7, $F1 // XE2 compiler bug, es wird immer "div rcx" generiert

  mov dword ptr [r8], edx // Rest in "Rest" schreiben
end;
{$ELSE}
asm
  // in: [ebp+$0c]:[ebp+$08] = Dividend
  // EAX = Divisor
  // EDX = @Rest
  // out: EDX:EAX = Quotient
  push ebx
  push edx // Zeiger auf Rest sichern
  mov ecx, eax

  mov eax, dword ptr [ebp+$0c] // HIGH DWORD des Dividenden als LOW DWORD für die Division laden
  xor edx, edx // kein HIGH DWORD bei der Division
  div ecx // und dividieren (EDX enthält Rest, der als Übertrag genutzt wird)

  mov ebx, eax // HIGH DWORD des Quotienten sichern
  mov eax, dword ptr [ebp+$08] // LOW DWORD des Dividenden laden
  div ecx // und dividieren (EDX enthält Rest)

  pop ecx // Zeiger auf Rest wiederherstellen
  mov dword ptr [ecx], edx // Rest in "Rest" schreiben
  mov edx, ebx // HIGH DWORD des Quotienten wiederherstellen
  pop ebx
end;
{$ENDIF CPUX64}

function cvbase_ANSI(n: Int64): AnsiString;
var
  Buf: array[0..7] of AnsiChar;
  Index: Integer;
  r: LongWord;
begin
  Index := Length(Buf);
  while n > 0 do
  begin
    Dec(Index);
    n := UDivMod6432(n, 255, r);
    Buf[Index] := chtab[r];
  end;
  SetString(Result, PAnsiChar(@Buf[Index]), Length(Buf) - Index);
end;

function cvbase(n: Int64): string;
var
  Buf: array[0..7] of Char;
  Index: Integer;
  r: LongWord;
begin
  Index := Length(Buf);
  while n > 0 do
  begin
    Dec(Index);
    n := UDivMod6432(n, 255, r);
    Buf[Index] := chtab[r];
  end;
  SetString(Result, PChar(@Buf[Index]), Length(Buf) - Index);
end;
UPDATE: Die 32bit assembler Version nahm eine falsche Parameterreihenfolge an.

Geändert von jbg ( 5. Feb 2012 um 18:35 Uhr)
  Mit Zitat antworten Zitat