Thema: ASM vs Delphi

Einzelnen Beitrag anzeigen

Benutzerbild von MaBuSE
MaBuSE

Registriert seit: 23. Sep 2002
Ort: Frankfurt am Main (in der Nähe)
1.840 Beiträge
 
Delphi 10 Seattle Enterprise
 
#17

Re: ASM vs Delphi

  Alt 17. Jan 2005, 11:47
Zitat von sakura:
Und anschließend teste noch folgende, welche imo die schnellste sein sollte:
Delphi-Quellcode:
function VectorSetValue(const Value:Single): TVector3D;
asm
  mov edx, Value
  mov [eax], edx
  mov [eax + $04], edx
  mov [eax + $08], edx
end;
Deren Ergebnis ist i.A. identisch zur Pascal-Lösung, verzichtet aber auf das wiederholte Laden des Übergabewertes.
Bei dieser Lösung sollte man aber bedenken, dass sich durch eine Änderung am record TVector3D evtl. die Adressen ändern.

Beisp:
Delphi-Quellcode:
type
  TVector3D = record x, y, z: Single; end;
Dann funktioniert sakuras Lösung.

Delphi-Quellcode:
type
  TVector3D = record x, nein_tu_das_nicht, y, z: Single; end;
Ups, nun haben sich die Adressen geändert.
Delphi-Quellcode:
function VectorSetValue(const Value:Single): TVector3D;
asm
  mov edx, Value
  mov [eax], edx
  mov [eax + $08], edx
  mov [eax + $0c], edx
end;
Das ganze ist nun um 4 Byte verschoben, da single 4 Byte belegt.
Werden andere Typen verwendet z.B. Double statt Single, dann sind die Adressen auch entsprechend anders.

Das Delphi aus dem Original Quelltext macht, lässt sich sehr leicht mit dem CPU Fenster ermitteln.
Delphi-Quellcode:
type
  TVector3D = record x, y, z: Single; end;

function VectorSetValue(const Value:Single): TVector3D;
begin // <- hier Haltepunkt setzen (F5 Taste)
  Result.X := Value;
  Result.Y := Value;
  Result.Z := Value
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: TVector3D;
begin
  x := VectorSetValue(1);
  Caption := IntToStr(Round(x.x+x.y+x.z)); // Anmerkung: Diese Zeile ist nur da,
                                            // damit Delphi mir mein x nicht wegoptimiert ;-)
end;
Wird die Applikation mit F9 gestartet, und der Button1 gedrückt, so bleibt der Debugger an der Stelle begin (in der Funktion VectorSetValue) stehen.
Mit "Menü -> Ansicht -> Debug-Fenster -> CPU" kann man das CPU Fenster öffnen.
hier steht nun folgendes:
Code:
Unit1.pas.30: begin
  0044D944 55                 push ebp
  0044D945 8BEC              mov ebp,esp
Unit1.pas.31: Result.X := Value;
  0044D947 8B5508             mov edx,[ebp+$08]
  0044D94A 8910               mov [eax], edx
Unit1.pas.32: Result.Y := Value;
  0044D94C 8B5508             mov edx,[ebp+$08]
  0044D94F 895004             mov [eax + $04], edx
Unit1.pas.33: Result.Z := Value;
  0044D952 8B5508             mov edx,[ebp+$08]
  0044D955 895008             mov [eax + $08], edx
...
[ebp+$08] ist die Adresse von Value, also kann man auch mov edx, Value schreiben.
Da das Register edx durch ein mov [eax],edx nicht verändert wird braucht man es nicht noch mal mit der Adresse von Value zu laden.
Daraus ergibt sich Sakuras Quelltext:
Code:
  mov edx, Value
  mov [eax], edx
  mov [eax + $04], edx
  mov [eax + $08], edx
Wenn nun ein verändertes Array (z.B. Double als Typ) verwendet wird, kann man im CPU Fenster sehen, was Delphi daraus macht und sein ASM entsprechend anpassen.
(°¿°) MaBuSE - proud to be a DP member
(°¿°) MaBuSE - proud to be a "Rüsselmops" ;-)
  Mit Zitat antworten Zitat