Inline-Assembler in Abbrevia-ZIP-unit übersetzen
-
- Beiträge: 688
- Registriert: Mi 3. Okt 2007, 21:00
- OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
- CPU-Target: x86_64
Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Hallo!
Ich habe aus der Abbrevia-ZIP-Komponente alle LibC-Abhängigkeiten entfernt, um die Komponente auch unter 64bit-Systemen lauffähig zu machen. Das Problem ist nur, dass eine unit 32bit-Assembler benutzt. Kann jemand diese (sehr lange) Stelle in der angehängten Unit übersetzen? Und wieso wird da überhaupt ASM verwendet?
Ich habe aus der Abbrevia-ZIP-Komponente alle LibC-Abhängigkeiten entfernt, um die Komponente auch unter 64bit-Systemen lauffähig zu machen. Das Problem ist nur, dass eine unit 32bit-Assembler benutzt. Kann jemand diese (sehr lange) Stelle in der angehängten Unit übersetzen? Und wieso wird da überhaupt ASM verwendet?
- Dateianhänge
-
- abdfinw.pas
- Die abdfinw.pas mit ASM-Code
- (21.94 KiB) 96-mal heruntergeladen
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Da brauchste doch nur den Compiler Switch ändern.
-
- Beiträge: 688
- Registriert: Mi 3. Okt 2007, 21:00
- OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
- CPU-Target: x86_64
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Klarer Fall von: Sieht den Wald vor lauter Bäumen nicht!"
Danke, damit hat sich das wohl erledigt.

-
- Beiträge: 688
- Registriert: Mi 3. Okt 2007, 21:00
- OS, Lazarus, FPC: Linux (L 0.9.29 FPC 2.4.2)
- CPU-Target: x86_64
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Nein, doch nicht. Wie übersetze ich folgendes?:
Und: Warum ist Assembler eigentlich soviel schneller als alle anderen Sprachen?
Code: Alles auswählen
procedure AbReverseBits(var W : Word);assembler;
{-Reverse the order of the bits in W}
register;
const
RevTable : array[0..255] of Byte = ($00, $80, $40, $C0, $20, $A0, $60,
$E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88, $48, $C8, $28,
$A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8, $04, $84, $44,
$C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4, $74, $F4, $0C,
$8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC, $3C, $BC, $7C,
$FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92, $52, $D2, $32,
$B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA, $1A, $9A, $5A,
$DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6, $66, $E6, $16,
$96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE, $2E, $AE, $6E,
$EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81, $41, $C1, $21,
$A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1, $09, $89, $49,
$C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9, $79, $F9, $05,
$85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5, $35, $B5, $75,
$F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D, $5D, $DD, $3D,
$BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3, $13, $93, $53,
$D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB, $1B,
$9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7, $27, $A7, $67,
$E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F, $4F, $CF, $2F,
$AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF);
asm
push eax // save EAX
mov eax, [eax] // read value into EAX
xor ecx, ecx // zero ECX
mov cl, al // prepare for table lookup
lea edx, RevTable // get address to table
mov al, [edx+ecx] // table lookup for low byte
mov cl, ah // prepare high byte for table lookup
mov ah, al // reverse bytes
mov al, [edx+ecx] // table lookup for high (now low) byte
pop edx // restore address to W
mov [edx], eax // move value to W
end;
-
- Beiträge: 1103
- Registriert: Di 5. Aug 2008, 09:37
- OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
- CPU-Target: 32/64,PPC(+64), ARM
- Wohnort: Eindhoven (Niederlande)
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Targion hat geschrieben: Und: Warum ist Assembler eigentlich soviel schneller als alle anderen Sprachen?
Code: Alles auswählen
w:=revtable[hi(w)]+(revtable[lo(w)] shl 8);
Nicht alles was Assembler ist, ist auch schneller. Von manche RTL routine in aeltere Delphi's ist bekannt das die assembler Versionen langsamer sinds als die korrespondierende Pascal Versionen auf P-II und neurer. Das Problem: der Assembler war alt und nur fuer P-I optimiert.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Perfekt für die Architektur passender Assembler-Code ist natürlich immer mindestens genauso schnell, wie das was ein Compiler erzeugen kann (der kann ja schließlich auch nur dasselbe bauen). Aber bei neuen Prozessoren benötigt Hand-Optimieren reichlich Gehirnschmalz um irgendetwas zu verbessern und außerdem kann man Pech haben, dass es bei einem anderen Prozessor dann schlechter ist als der Code des FP-Compilers.
Für BitReverse Biete Delphi-Jedi diese Funktionen an, die mir ziemlich ideal vorkommen. (Die 64-Bit variante sollte man vielleicht besser wie die 32 Bit variante bauen, damit sie auf 64-Bit Prozessoren flotter läuft (wird dann auf 32 Bit Prozessoren allerdings vermutlich langsamer). )
(Die Nbbel-Tabelle ist vermutlich besser als eine Byte-Tabelle, da sie wesentlich kleiner ist und den Cache dadurch besser ausnutzt.)
Für BitReverse Biete Delphi-Jedi diese Funktionen an, die mir ziemlich ideal vorkommen. (Die 64-Bit variante sollte man vielleicht besser wie die 32 Bit variante bauen, damit sie auf 64-Bit Prozessoren flotter läuft (wird dann auf 32 Bit Prozessoren allerdings vermutlich langsamer). )
(Die Nbbel-Tabelle ist vermutlich besser als eine Byte-Tabelle, da sie wesentlich kleiner ist und den Cache dadurch besser ausnutzt.)
Code: Alles auswählen
function ReverseBits(Value: Byte): Byte; overload;
function ReverseBits(Value: Shortint): Shortint; overload;
function ReverseBits(Value: Smallint): Smallint; overload;
function ReverseBits(Value: Word): Word; overload;
function ReverseBits(Value: Integer): Integer; overload;
function ReverseBits(Value: Cardinal): Cardinal; overload;
function ReverseBits(Value: Int64): Int64; overload;
function ReverseBits(P: Pointer; Count: Integer): Pointer; overload;
const
// Lookup table of bit reversed nibbles, used by simple overloads of ReverseBits
RevNibbles: array [0..NibbleMask] of Byte =
($0, $8, $4, $C, $2, $A, $6, $E, $1, $9, $5, $D, $3, $B, $7, $F);
function ReverseBits(Value: Byte): Byte;
begin
Result := RevNibbles[Value shr BitsPerNibble] or
(RevNibbles[Value and NibbleMask] shl BitsPerNibble);
end;
//--------------------------------------------------------------------------------------------------
function ReverseBits(Value: Shortint): Shortint;
begin
Result := RevNibbles[Byte(Value) shr BitsPerNibble] or
(RevNibbles[Value and NibbleMask] shl BitsPerNibble);
end;
//--------------------------------------------------------------------------------------------------
function ReverseBits(Value: Smallint): Smallint;
begin
Result := ReverseBits(Word(Value));
end;
//--------------------------------------------------------------------------------------------------
function ReverseBits(Value: Word): Word;
var
I: Integer;
begin
Result := 0;
for I := 0 to NibblesPerWord - 1 do
begin
Result := (Result shl BitsPerNibble) or RevNibbles[Value and NibbleMask];
Value := Value shr BitsPerNibble;
end;
end;
//--------------------------------------------------------------------------------------------------
function ReverseBits(Value: Integer): Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to NibblesPerInteger - 1 do
begin
Result := (Result shl BitsPerNibble) or RevNibbles[Value and NibbleMask];
Value := Value shr BitsPerNibble;
end;
end;
//--------------------------------------------------------------------------------------------------
function ReverseBits(Value: Cardinal): Cardinal;
var
I: Integer;
begin
Result := 0;
for I := 0 to NibblesPerCardinal - 1 do
begin
Result := (Result shl BitsPerNibble) or RevNibbles[Value and NibbleMask];
Value := Value shr BitsPerNibble;
end;
end;
//--------------------------------------------------------------------------------------------------
function ReverseBits(Value: Int64): Int64;
begin
TULargeInteger(Result).LowPart := ReverseBits(TULargeInteger(Value).HighPart);
TULargeInteger(Result).HighPart := ReverseBits(TULargeInteger(Value).LowPart);
end;
//--------------------------------------------------------------------------------------------------
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
mschnell hat geschrieben:Für BitReverse Biete Delphi-Jedi diese Funktionen an, die mir ziemlich ideal vorkommen. (Die 64-Bit variante sollte man vielleicht besser wie die 32 Bit variante bauen, damit sie auf 64-Bit Prozessoren flotter läuft (wird dann auf 32 Bit Prozessoren allerdings vermutlich langsamer). )
(Die Nbbel-Tabelle ist vermutlich besser als eine Byte-Tabelle, da sie wesentlich kleiner ist und den Cache dadurch besser ausnutzt.)
Ich habe das mal kurz ausgemessen bei 100000000 Schleifendurchläufen:
AbReversebits: 1130 ms
fpc-Variante von marcov: 1040 ms
Jedi ReverseBits: 2530 ms
ach, und das ist auch gut: fpc 2.2.2 ist ca. 11 % schneller als Delphi 5

sorry, ich hatte die Optimierung vergessen. Mit -O2 sieht es folgendermaßen aus:
AbReversebits: 1120 ms
fpc-Variante von marcov: 680 ms
Jedi ReverseBits: 1220 ms
Gruß, Bernd.
Zuletzt geändert von _Bernd am Mo 15. Sep 2008, 18:06, insgesamt 1-mal geändert.
-
- Beiträge: 1103
- Registriert: Di 5. Aug 2008, 09:37
- OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
- CPU-Target: 32/64,PPC(+64), ARM
- Wohnort: Eindhoven (Niederlande)
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Hast du auch Inline versucht fuer die Pascal varianten?_Bernd hat geschrieben: Ich habe das mal kurz ausgemessen bei 100000000 Schleifendurchläufen:
AbReversebits: 1130 ms
fpc-Variante von marcov: 1040 ms
Jedi ReverseBits: 2530 ms
ach, und das ist auch gut: fpc 2.2.2 ist ca. 11 % schneller als Delphi 5![]()

Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Mit inline sieht es so aus:marcov hat geschrieben: Hast du auch Inline versucht fuer die Pascal varianten?
AbReversebits: 1070 ms
fpc-Variante von marcov: 630 ms
Jedi ReverseBits: 1030 ms
Gruß, Bernd.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen
Nicht schlecht ! Beide FPC-Varianten sind schneller als Assembler, eine sogar fast doppelt so flott. Glückwunsch an's FPC-Team !
Aber Vorsicht ! Auf einer anderen Maschine könne die Test deutlich anders ausfallen.
Versucht das 'mal jemand auf einer 64 Bit Kiste ?
-Michael
Aber Vorsicht ! Auf einer anderen Maschine könne die Test deutlich anders ausfallen.
Versucht das 'mal jemand auf einer 64 Bit Kiste ?
-Michael