Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Optimallösung gesucht: Little Endian <-> Big Endian (https://www.delphipraxis.net/113353-optimalloesung-gesucht-little-endian-big-endian.html)

FAlter 6. Mai 2008 16:58


Optimallösung gesucht: Little Endian <-> Big Endian
 
Hi,

kann man das noch optimieren? (Kommentiert ist der Code, den Delphi erzeugt.)

Delphi-Quellcode:
procedure SwapBytes(var X: WideChar);
asm
  mov  dx, [X] //mov dx, [eax]
  xchg dl, dh
  mov [X], dx //mov [eax], dx
end;

procedure SwapBytes(var X: UCS4Char);
asm
  mov  edx, [X] //mov edx, [eax]
  bswap edx
  mov  [X], edx //mov [eax], edx
end;
Und ich geh doch richtig davon aus, dass das, was übergeben wird, der Zeiger auf das Zeichen ist (wegen var)?

Mfg
FAlter

sirius 6. Mai 2008 17:25

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
1. x liegt in eax und du musst es nicht erst noch weiter herumschieben.
2. gibt es für 16bit noch die Delphi-Funktion swap. Die erzeugt direkt inline-Code.

himitsu 6. Mai 2008 17:39

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
@sirius: bei mir ist Swap 32 bit (Integer)
nja, aber es ist zumindestens noch eine Funktion ist
Delphi-Quellcode:
w := Swap(w);
// erzeugt aber das selbe Ergebnis wie
ByteSwap(w);
und als Inline ist es besser


aber nee, diesen Code kann man nicht mehr optimieren, (leider geht ja bei ASM kein Inline)
nur ein & könnte nicht schaden.
Delphi-Quellcode:
procedure SwapBytes(var X: WideChar);
asm
  mov  dx, [&X]
  xchg dl, dh
  mov  [&X], dx
end;

procedure SwapBytes(var X: UCS4Char);
asm
  mov  edx, [&X]
  bswap edx
  mov  [&X], edx
end;

// ohne BSWAP für alte CPUs
procedure SwapBytes(var X: UCS4Char);
asm
  mov  edx, [&X]
  xchr dh, dl
  rol  edx, 16
  xchg dh, dl
  mov  [&X], edx
end;
was du optimieren könntest, wäre mehrere Zeichen umzuwandeln und nicht nur Eines.



aber wie meinst du das?
Zitat:

Kommentiert ist der Code, den Delphi erzeugt.


[add]
@sirius:
Delphi-Quellcode:
function SwapBytes(X: WideChar): WideChar;
asm
  xchg al, ah
end;

function SwapBytes(X: UCS4Char): UCS4Char;
asm
  bswap eax
end;

Namenloser 6. Mai 2008 17:43

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Ich denke er meint den Code aus der CPU-Ansicht vom Debugger.

FAlter 6. Mai 2008 17:56

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

Swap kannte ich noch nicht, hab gleich mal nachgesehen.

Aus der Delphi-Hilfe:
X ist ein Ausdruck des Typs SmallInt oder Word (16 Bit).

Ich hab aber WideChar. Notfalls gehts mit Typecasten.

Aus der Delphi-Hilfe:
Die Funktion ist nur aus Gründen der Abwärtskompatibilität vorhanden.


Na Toll. Dann so:

Delphi-Quellcode:
procedure SwapBytes(var X: WideChar); inline;
//Hinweis siehe unter der Prozedur!
begin
  X := WideChar(Swap(Word(X)));
end;
{

Sollte CodeGear "swap" eines Tages endgültig abschaffen, bitte das hier nutzen:

procedure SwapBytes(var X: WideChar);
asm
  mov  dx, [X] //mov dx, [eax]
  xchg dl, dh
  mov [X], dx //mov [eax], dx
end;

}
Wenigstens wird der Aufruf jetzt so übersetzt (Result ist WideString):

Code:
[b]FAUnicode.pas.137: SwapBytes(Result[I]);[/b]
0045949D 8B06             mov eax,[esi]
0045949F 8D4458FE        lea eax,[eax+ebx*2-$02]
004594A3 0FB708           movzx ecx,[eax]
004594A6 86E9             xchg cl,ch
004594A8 668908           mov [eax],cx
004594AB 43               inc ebx
Schade, dass Inline und Inline-Assembler ( :lol: ) sich nicht vertragen.

@roter Kasten: Es steht zwar als Integer in der OH, aber es steht auch darunter, was ich oben geschrieben habe: Smallint oder Word, also 16 Bit.

Das & braucht man bloß, wenns nicht eindeutig ist. Es gibt aber kein Register X, also wird der Parameter genommen. Wenn ich ihn ch für Char genannt hätte, müsste ich &Ch schreiben.

Für mehrere Zeichen müsste ich mich noch genauer mit dem Aufbau von Strings und der Übergabe von String-Parametern beschäftigen, dann kann ich auch gleich den ganzen String umwandeln (und dyn. Arrays, denn USC4String ist ein type array of USC4Char). Da es jedoch nur geschrieben wurde, weil ich es schnell brauchte und ich eigentlich was ganz anderes tun wollte, werd ich mich im Moment nicht groß in was einlesen, was ich noch nicht kann und mit dem ursprünglichen Thema nichts zu tun hat. Hab aber schon die TODO-Kommentare gesetzt. ;) Evtl. hat ja hier jemand Langeweile.

Mit "wie es Delphi übersetzt" meine ich was der aus dem X macht. Erst hatte ich eax stehen aber das ging logischerweise nicht, da X als eax "übersetzt" wurde (der Parameter wurde also in eax übergeben). Aber das CPU-Fenster hat mir die Ursache gezeigt und ich bin auf (e)dx umgestiegen.

Das mit den Funktionen ist schon klar, dass die dann kürzer gehen (da ich dann keine Referenzen übergeben habe), aber das ist mehr Schreibarbeit. Wird es denn optimaler, wenn ich x := SwapBytes(x) schreibe? Kann sogar sein, wenn der Wert vorm Aufruf "zufällig" in (a)ax lag und später wieder dort gebraucht wird. Nur die Variante mit der obsolete-Funktion Swap ist so schon schnell genug, aber das als inline-Funktion zu schreiben macht auch keinen Unterschied.

Mfg
FAlter

himitsu 6. Mai 2008 18:20

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
[edit] ups, ausversehn gelöscht ... wollte eigentlich zitieren, statt editieren

FAlter 6. Mai 2008 18:44

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

nochmal zum Thema optimieren, indem ich den ganzen String auf einmal bearbeite (vielleicht mach ich es ja doch schon jetzt):

Delphi-Quellcode:
procedure SwapBytes(var X: WideString);
procedure SwapBytes(var X: UCS4String);
Wird da jetzt ein Zeiger auf einen WideString (UCS4String), welcher wiederum ein Zeiger auf die Wide(UCS4)Chars ist, übergeben?

Mfg
FAlter

PS: Welche alten CPUs unterstützen denn kein bswap? Ich dachte immer, das gibts ab i80386DX (und was vor dem i486DX ist, ist eh egal, da lässt sich ja kein Win32 drauf installieren).
PPS: Ein WideString kat keinen Referenzzähler? :shock:

[edit] Es heißt UCS4String - sorry. Dann ist der Fehler weiter unten wohl auch ursprünglich meiner. [/edit]

nicodex 6. Mai 2008 19:01

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Wenn die Delphi-Version Inline unterstützt, dann macht Assembler keinen Sinn mehr:
Delphi-Quellcode:
{$IFDEF BIG_ENDIAN}
type
  WordBE = Word;
{$ELSE ~BIG_ENDIAN}
function WordBE(AValue: Word): Word; inline;
begin
  Result := Swap(AValue);
end;
{$ENDIF BIG_ENDIAN}

procedure TForm20.FormCreate(Sender: TObject);
var
  Value: Word;
begin
  Value := WordBE($1234); // inlined: mov _x, $3412 !!!
  ShowMessage(IntToHex(Value, SizeOf(Value) * 2));
  Value := WordBE(Value); // inlined: xchg _l, _h
  ShowMessage(IntToHex(Value, SizeOf(Value) * 2));
end;

FAlter 6. Mai 2008 19:15

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

darum habe ich ja, wie in #5 geschrieben, die Funktion abgewandelt als inline mit swap. Das betrifft aber erstens noch nicht die 4-Byte-Variante und zweitens kann man evtl. noch was rausholen, wenn man die ganzen Strings umwandelt.

Mfg
FAlter

himitsu 6. Mai 2008 19:18

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
WideString+Ref: nein, denn Delphi leitet den Widestring an OleStr weiter und der kennt keine Refferenzzählung.

'ne "einfache" Lösung wäre:

Delphi-Quellcode:
procedure SwapString(Var S: WideString);
asm
  mov eax, [eax]

  test eax, eax
  jz  @exit

  mov ecx, [eax - 4]
  shr ecx, 1

  @loop:

  mov  dx, [eax]
  xchg dl, dh
  mov  [eax], dx

  add eax, 2
  dec ecx
  jnz @loop

  @exit:
end;

procedure SwapString(Var S: UCS4String);
asm
  mov eax, [eax]

  test eax, eax
  jz  @exit

  mov ecx, [eax - 4]

  @loop:

  mov  edx, [eax]
  bswap edx
  mov  [eax], edx

  add eax, 4
  dec ecx
  jnz @loop

  @exit:
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:40 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz