AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

SIMD-Dll in asm für Delphi

Ein Thema von mathias l. · begonnen am 23. Dez 2003 · letzter Beitrag vom 26. Dez 2003
Antwort Antwort
mathias l.

Registriert seit: 23. Dez 2003
Ort: Bei Hamburg
4 Beiträge
 
#1

SIMD-Dll in asm für Delphi

  Alt 23. Dez 2003, 15:35
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:
.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
Insbsondere ist problematisch, das die xmm-SIMD Befehle eine 16Byte-Datenausrichtungen verlangen, aber in Delphi5 hab ich noch keine Direktive gefunden, die das bewerkstelligt.

Vielen Dank
  Mit Zitat antworten Zitat
mathias l.

Registriert seit: 23. Dez 2003
Ort: Bei Hamburg
4 Beiträge
 
#2

Re: SIMD-Dll in asm für Delphi

  Alt 23. Dez 2003, 16:07
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.
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#3

Re: SIMD-Dll in asm für Delphi

  Alt 23. Dez 2003, 16:23
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:
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;
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.
Sicherlich ist hier etwas in der Art eines "Nodemanagers" denkbar, trotzdem bleibt ein gewisser Mehraufwand...
gruß, choose
  Mit Zitat antworten Zitat
Robert Marquardt
(Gast)

n/a Beiträge
 
#4

Re: SIMD-Dll in asm für Delphi

  Alt 23. Dez 2003, 17:00
Nimm doch den Assembler und kompilier die paar Statements nach Maschinencode und arbeite mit DB in Delphi.
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#5

Re: SIMD-Dll in asm für Delphi

  Alt 23. Dez 2003, 17:04
Erinnert ein wenig an die Zeiten von Inline-ASM unter TP mit db 66h

Wie löst Du das Problem mit der Ausrichtung, Robert?
gruß, choose
  Mit Zitat antworten Zitat
Robert Marquardt
(Gast)

n/a Beiträge
 
#6

Re: SIMD-Dll in asm für Delphi

  Alt 23. Dez 2003, 17:18
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:
type
  TAlignedMemory = record
    Allocated: Pointer;
    Aligned: Pointer;
  end;

function GetAlignedMemory(var Mem: TAlignedMemory): Pointer;
procedure FreeAlignedMemory(const Mem: TAlignedMemory);
Die Implementation ist ja schon weitgehend da.
  Mit Zitat antworten Zitat
mathias l.

Registriert seit: 23. Dez 2003
Ort: Bei Hamburg
4 Beiträge
 
#7

Re: SIMD-Dll in asm für Delphi

  Alt 26. Dez 2003, 13:05
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!
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:48 Uhr.
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