Inline-Assembler in Abbrevia-ZIP-unit übersetzen

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Targion
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

Beitrag von Targion »

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?
Dateianhänge
abdfinw.pas
Die abdfinw.pas mit ASM-Code
(21.94 KiB) 96-mal heruntergeladen

Benutzeravatar
theo
Beiträge: 10949
Registriert: Mo 11. Sep 2006, 19:01

Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen

Beitrag von theo »

Da brauchste doch nur den Compiler Switch ändern.

Targion
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

Beitrag von Targion »

Klarer Fall von: Sieht den Wald vor lauter Bäumen nicht!" :roll: Danke, damit hat sich das wohl erledigt.

Targion
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

Beitrag von Targion »

Nein, doch nicht. Wie übersetze ich folgendes?:

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;
Und: Warum ist Assembler eigentlich soviel schneller als alle anderen Sprachen?

marcov
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

Beitrag von marcov »

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);
oder so.

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.

mschnell
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

Beitrag von mschnell »

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.)

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;
 
//--------------------------------------------------------------------------------------------------
 
 

_Bernd
Beiträge: 145
Registriert: Di 13. Feb 2007, 11:16

Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen

Beitrag von _Bernd »

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.

marcov
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

Beitrag von marcov »

_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 :-)
Hast du auch Inline versucht fuer die Pascal varianten? :-)

_Bernd
Beiträge: 145
Registriert: Di 13. Feb 2007, 11:16

Re: Inline-Assembler in Abbrevia-ZIP-unit übersetzen

Beitrag von _Bernd »

marcov hat geschrieben: Hast du auch Inline versucht fuer die Pascal varianten? :-)
Mit inline sieht es so aus:

AbReversebits: 1070 ms
fpc-Variante von marcov: 630 ms
Jedi ReverseBits: 1030 ms

Gruß, Bernd.

mschnell
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

Beitrag von mschnell »

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

Antworten