![]() |
SIMD-Dll in asm für Delphi
Hallo, ich würde gerne für die Berechnung von 4x4-Matrizen in Delphi SIMD (xmm) benutzen. Da ich unter Delphi5 per inline-asm diese Befehle nicht nutzen kann, möchte ich mit dem masm32 eine dll schreiben, die die Funktion "MultMatrix" exportiert. Leider Erhalte ich die Fehlermeldung EPrivileg. Villeicht mag sich ja mal jemand den Code anschauen.
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; function MultMatrix(x, y: Pointer): Pointer; stdcall; external 'test.dll'; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var a,b,c,d: array of single; i: Integer; begin setlength(d, 32); setlength(a, 16); setlength(b, 16); setlength(c, 16); d[0]:= 1.0; d[1]:= 0.0; d[2]:= 0.0; d[3]:= 0.0; d[4]:= 0.0; d[5]:= 1.0; d[6]:= 0.0; d[7]:= 0.0; d[8]:= 0.0; d[9]:= 0.0; d[10]:=1.0; d[11]:=0.0; d[12]:=0.0; d[13]:=0.0; d[14]:=0.0; d[15]:=1.0; d[16]:=1.0; d[17]:=0.0; d[18]:=0.0; d[19]:=0.0; d[20]:=0.0; d[21]:=1.0; d[22]:=0.0; d[23]:=0.0; d[24]:=0.0; d[25]:=0.0; d[26]:=1.0; d[27]:=0.0; d[28]:=0.0; d[29]:=0.0; d[30]:=0.0; d[31]:=1.0; for i:=0 to 15 do a[i]:= d[i]; // a ist eine 4x4 Einheitsmatrix for i:=0 to 15 do b[i]:= d[i+16]; // b auch. Beide miteinander multipliziert // sollten wieder ne Einheitsmatrix ergeben. c:= MultMatrix(a, b); end; end. Und hier der asm-dll-code:
Code:
Insbsondere ist problematisch, das die xmm-SIMD Befehle eine 16Byte-Datenausrichtungen verlangen, aber in Delphi5 hab ich noch keine Direktive gefunden, die das bewerkstelligt.
.586
.xmm .model flat, stdcall option casemap: none .data m2 dd 16 dup (0.0) .code MultMatrix proc ths: DWORD, m1: DWORD ; Hier sollen 2 Adressen von Matritzen ; (je 16 Single-Werte) übergeben werden push edi push esi push eax push edx mov edi, m1 movaps xmm4, [edi] movaps xmm5, [edi+16] movaps xmm6, [edi+32] movaps xmm7, [edi+48] mov esi, ths mov eax, 0 L1: movaps xmm0, [esi+eax] movaps xmm1, xmm0 movaps xmm2, xmm0 movaps xmm3, xmm0 shufps xmm0, xmm2, 000h shufps xmm1, xmm2, 055h shufps xmm2, xmm2, 0AAh shufps xmm3, xmm3, 0FFh mulps xmm0, [edi] mulps xmm1, [edi+16] mulps xmm2, [edi+32] mulps xmm3, [edi+48] addps xmm0, xmm1 addps xmm0, xmm2 addps xmm0, xmm3 mov edx, eax add edx, m2 movaps [edx], xmm0 add eax, 16 cmp eax, 48 jle L1 mov eax, offset m2 ; m2 enthält die Ergebnis-Matrix pop edx pop eax pop edi pop esi ret MultMatrix endp DllMain proc hInstDll :DWORD, dwNotification :DWORD, lpReserved :DWORD ret DllMain endp end Vielen Dank |
Re: SIMD-Dll in asm für Delphi
Hallo nochmal, habe versucht die Matrix-arrays auf diesem Weg an 16-Byte-Grenzen auszurichten, (aber es funktioniert trotzdem noch nicht):
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TRec = packed Record Data: packed Array of single; //16 * 4 Byte =>sollte an 16 Byte ausgerichtet sein end; PRec = ^TRec; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; function MultMatrix(x, y: Pointer): Pointer; stdcall; external 'test.dll'; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var a, b, c: TRec; pa, pb, pc: PRec; i: Integer; begin //a,b: Einheitsmatrizen; c: Nullmatrix. SetLength(a.Data, 16); SetLength(b.Data, 16); SetLength(c.Data, 16); for i:=0 to 15 do a.Data[i]:=0.0; for i:=0 to 15 do b.Data[i]:=0.0; for i:=0 to 15 do c.Data[i]:=0.0; a.Data[0]:= 1.0; a.Data[5]:= 1.0; a.Data[10]:= 1.0; a.Data[15]:= 1.0; b.Data[0]:= 1.0; b.Data[5]:= 1.0; b.Data[10]:= 1.0; b.Data[15]:= 1.0; pa:= @a; pb:= @b; pc:= @c; //nach Multiplikation sollte c eine Einheitsmatrix sein pc:= MultMatrix(pb, pb); end; end. |
Re: SIMD-Dll in asm für Delphi
Hallo Mathias,
herzlich willkommen bei der Delphi-PRAXiS! Das Schlüsselwort packed bewirkt genau das Gegenteil von dem, was Du möchtest, hat aber erst dann Auswirkungen, wenn mehr als ein Feld in einem Record vorhanden ist... Zur Ausrichtung Deines Feldes auf 16 Byte-Grenzen gibt es in Delphi leider keine Compileroptionen oder Attribute bei der Deklaration. Wenn Du allerdings den Auffwand nicht scheust, könntest Du mit dynamische alloziertem Speicher arbeiten, etwa in der Form:
Delphi-Quellcode:
problematisch an dem Ansatz sind allerdings die "verschendeten Bytes am Ende" und die Tatsache, dass Du zu jedem Record eine weitere Referenz auf den tatsächlich alloziiertem Datenbereich halten musst.
type
TMyMatrix = array[0..15] of Single; PMyMatrix = ^TMyMatrix; //... var myPointer: Pointer; myMatrix : PMyMatrix; begin // allocate memory with 15 Bytes "extra space" GetMem(myPointer, SizeOf(TMyMatrix)+15); try // calculate offset with 16 Byte alignment within memory frame myMatrix:= PMyMatrix((Integer(myPointer)+$0F) and $FFFFFFF0); // initialize memory ZeroMemory(myMatrix, SizeOf(TMyMatrix)); myMatrix^[0]:= 1.0; myMatrix^[1]:= 2.0; // call routine with reference DoSth(myMatrix); finally FreeMem(myPointer); end; end; Sicherlich ist hier etwas in der Art eines "Nodemanagers" denkbar, trotzdem bleibt ein gewisser Mehraufwand... |
Re: SIMD-Dll in asm für Delphi
Nimm doch den Assembler und kompilier die paar Statements nach Maschinencode und arbeite mit DB in Delphi.
|
Re: SIMD-Dll in asm für Delphi
Erinnert ein wenig an die Zeiten von Inline-ASM unter TP mit db 66h ;)
Wie löst Du das Problem mit der Ausrichtung, Robert? |
Re: SIMD-Dll in asm für Delphi
Die angegebene Loesung ist schon brauchbar.
Fuer kompliziertere Sachen muss man sich moeglicherweise einen eigenen kleinen Memorymanager bauen. Einfacher waere aber etwas der Art:
Delphi-Quellcode:
Die Implementation ist ja schon weitgehend da.
type
TAlignedMemory = record Allocated: Pointer; Aligned: Pointer; end; function GetAlignedMemory(var Mem: TAlignedMemory): Pointer; procedure FreeAlignedMemory(const Mem: TAlignedMemory); |
Re: SIMD-Dll in asm für Delphi
Hi, vielen Dank für Eure Hilfe, hab's jetzt hinbekommen - hier der dll und delphi-code, die jetzt beide funktionieren:
Code:
.586
.xmm .model flat, stdcall option casemap: none .code MultMatrix proc ths: DWORD, m1: DWORD, m2:DWORD ; This are two adresses of 4x4Matrices ; which are 16*4 Bytes long push esi push edi push eax push edx mov edi, m1 movaps xmm4, [edi] movaps xmm5, [edi+16] movaps xmm6, [edi+32] movaps xmm7, [edi+48] mov esi, ths mov eax, 0 L1: movaps xmm0, [esi+eax] movaps xmm1, xmm0 movaps xmm2, xmm0 movaps xmm3, xmm0 shufps xmm0, xmm2, 000h shufps xmm1, xmm2, 055h shufps xmm2, xmm2, 0AAh shufps xmm3, xmm3, 0FFh mulps xmm0, [edi] mulps xmm1, [edi+16] mulps xmm2, [edi+32] mulps xmm3, [edi+48] addps xmm0, xmm1 addps xmm0, xmm2 addps xmm0, xmm3 mov edx, m2 add edx, eax movaps [edx], xmm0 add eax, 16 cmp eax, 48 jle L1 pop edx pop eax pop edi pop esi ret MultMatrix endp DllMain proc hInstDll :DWORD, dwNotification :DWORD, lpReserved :DWORD ret DllMain endp end
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMyMatrix = array[0..15] of Single; PMyMatrix = ^TMyMatrix; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; procedure MultMatrix(x, y, z: Pointer); stdcall; external 'test.dll'; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var pa, pb, pc: PMyMatrix; p1, p2, p3: Pointer; i: Integer; begin GetMem(p1, SizeOf(TMyMatrix)+15); pa:= PMyMatrix((Integer(p1)+$0F) and $FFFFFFF0); ZeroMemory(pa, SizeOf(TMyMatrix)); GetMem(p2, SizeOf(TMyMatrix)+15); pb:= PMyMatrix((Integer(p2)+$0F) and $FFFFFFF0); ZeroMemory(pb, SizeOf(TMyMatrix)); GetMem(p3, SizeOf(TMyMatrix)+15); pc:= PMyMatrix((Integer(p3)+$0F) and $FFFFFFF0); ZeroMemory(pc, SizeOf(TMyMatrix)); for i:=0 to 15 do pc^[i]:=0.0; // pc is an empty matrix, pa, bb are // arbitrary 4x4 Matrices pa^[00]:= 1.0; pa^[01]:= 2.0; pa^[02]:= 3.0; pa^[03]:= 1.0; pa^[04]:= 2.0; pa^[05]:= 3.0; pa^[06]:= 1.0; pa^[07]:= 2.0; pa^[08]:= 3.0; pa^[09]:= 1.0; pa^[10]:= 2.0; pa^[11]:= 3.0; pa^[12]:= 1.0; pa^[13]:= 2.0; pa^[14]:= 3.0; pa^[15]:= 1.0; pb^[00]:= 3.0; pb^[01]:= 2.0; pb^[02]:= 1.0; pb^[03]:= 3.0; pb^[04]:= 2.0; pb^[05]:= 1.0; pb^[06]:= 3.0; pb^[07]:= 2.0; pb^[08]:= 1.0; pb^[09]:= 3.0; pb^[10]:= 2.0; pb^[11]:= 1.0; pb^[12]:= 3.0; pb^[13]:= 2.0; pb^[14]:= 1.0; pb^[15]:= 3.0; MultMatrix(pa, pb, pc); //pc is the Result FreeMem(p1); FreeMem(p2); FreeMem(p3); end; end. Frohe Weihnachten noch! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz