Von C++ nach Pascal

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Von C++ nach Pascal

Beitragvon Mathias » 21. Jun 2018, 17:52 Von C++ nach Pascal

Ich will folgenden C++ Code nach Pascal transferieren.
Code: Alles auswählen
void matrixMultiplication(float *matrixIn, // 4x4 matrix
float *vectorIn, // 4x1 vector
float *vectorOut) // 4x1 vector
{
// pointer row points to 16 elements array (beginning of the
// matrixIn array) containing column-major elements:
 // [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]
float *row = matrixIn;
__asm
{
mov esi, vectorIn // load input address
mov edi, vectorOut // load output address
// pointer to the first 4 elements of the array:
mov edx, row

 
Soweit bin ich schon mal gekommen.
Nun zu Frage, ist dies der richtige weg, auch was die var im Procedure-Kopf anbelangt ?
Und wie muss ich das float *row = matrixIn; umsetzen ?
Code: Alles auswählen
  procedure matrixMultiplication(var matrixIn: TMatrix; var vectorIn, vectorOut: TVector4f);
    {$asmmode intel}
  begin
    asm
             Mov     Esi, vectorIn // load input address
             Mov     Edi, vectorOut // load output address
             // pointer to the first 4 elements of the array:
             Mov     Edx, row


Der komplette C++-Code befindet sich hier: http://www-cs.ccny.cuny.edu/~gertner/Cs ... tion_4.pdf
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 21. Jun 2018, 19:06 Re: Von C++ nach Pascal

Was sind denn überhaupt die typen TMatrix und TVector4f? Denn der Code arbeitet auf Pointern, wenn die beiden typen Statische Arrays oder Records sind wirst du mit deinem Ansatz nicht glücklich denn mit:
Code: Alles auswählen
Mov     Esi, vectorIn

würde dann der Inhalt statt die Addresse in ESI geladen werden, was spätetestens bei
Code: Alles auswählen
movups xmm0, [esi]

knallt.

Wenn es Dynamische Arrays sind dann kannst du den Code praktisch direkt übernehmen:
Code: Alles auswählen
Row: PSingle; // vordefiniert???
...
Row := PSingle(matrixIn)
Warf
 
Beiträge: 985
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 21. Jun 2018, 19:13 Re: Von C++ nach Pascal

Danke erst mal.

Auf die Idee mit dem PSingle bin ich unterdessen auch gekommen. Auch habe ich die 64Bit-Register angepasst.

Nun sieht mein Kopf so aus. Immerhin knallt es nicht mehr.

Code: Alles auswählen
  procedure matrixMultiplication(matrixIn, vectorIn, vectorOut: PSingle);
  var
    i: integer;
    row: PSingle;
 
    {$asmmode intel}
  begin
    row := matrixIn;
    asm
             Mov     Rsi, vectorIn // load input address
             Mov     Rdi, vectorOut // load output address
             // pointer to the first 4 elements of the array:
             Mov     Rdx, row
             // Move Unaligned Parallel Scalars
             // load the registers with matrix values:
             Movups  Xmm4, [Rdx] // xmm4 contains 1,5, 9,13
             Movups  Xmm5, [Rdx+$10] // +16 (4 bytes x 4 elements)


Der Aufruf sieht folgendermassen aus:
Code: Alles auswählen
type
  glFloat = Single;  // aus dglOpenGL.pas
 
  TVector4f = array[0..3] of GLfloat;
  Tmat4x4 = array[0..3] of TVector4f;
  TMatrix = Tmat4x4;
 
var
    Matrix: TMatrix
    v0, vv: TVector4f;
 
begin
  vv := v0;
  matrixMultiplication(@Matrix, @vv, @v0);
 


Das Ergebnis sie aus wie im Anhang. Eigentlich sollte es ein Würfel sein.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 21. Jun 2018, 19:18 Re: Von C++ nach Pascal

Ich habe grad mal nachgeschaut, zumindest Delphi unterstützt den @ Operoator im ASM, also könnte eventuell auch das gehen:
Code: Alles auswählen
  procedure matrixMultiplication(matrixIn: TMatrix; vectorIn: TVector4f; out vectorOut: TVector4f ); // muss ja nur eins output sein
  var
    i: integer;
    row: PSingle;
 
    {$asmmode intel}
  begin
    row := PSingle(@MatrixIn);
    asm
             Mov     Rsi, @vectorIn // load input address
             Mov     Rdi, @vectorOut // load output address
             // pointer to the first 4 elements of the array:
             Mov     Rdx, row
             // Move Unaligned Parallel Scalars
             // load the registers with matrix values:
             Movups  Xmm4, [Rdx] // xmm4 contains 1,5, 9,13
             Movups  Xmm5, [Rdx+$10] // +16 (4 bytes x 4 elements)


Ich mag es nicht wenn Funktionsaufrufe Pointer brauchen (wenn es sich vermeiden lässt)
Warf
 
Beiträge: 985
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 21. Jun 2018, 22:01 Re: Von C++ nach Pascal

Das Ergebnis sie aus wie im Anhang. Eigentlich sollte es ein Würfel sein.

Der Fehler war hier, und somit kein Pointer-Fehler. Irgendwie habe die die Werte in der Matrix anders rum übergeben.
Da sieht man wieder, das es vieles im INet, welches Fehler enthält.
Code: Alles auswählen
             Movups  Xmm4, [Rdx+$30] // xmm4 contains 1,5, 9,13
             Movups  Xmm5, [Rdx+$20] // +16 (4 bytes x 4 elements)
             // xmm5 contains 2,6,10,14
             Movups  Xmm6, [Rdx+$10] // +32 (8 bytes x 4 elements)
             // xmm6 contains 3,7,11,15
             Movups  Xmm7, [Rdx+$00] // +48 (12 bytes x 4 


Den Kopf habe ich noch ein wenig abgeändert und somit kann ich voll auf Pointer verzichten. @ ist nicht nötig.
Code: Alles auswählen
  procedure matrixMultiplication(const matrixIn: TMatrix; const vectorIn: TVector4f; out vectorOut: TVector4f);
    {$asmmode intel}
  begin
    asm
             Mov     Rsi, vectorIn // load input address
             Mov     Rdi, vectorOut // load output address
             // pointer to the first 4 elements of the array:
             Mov     Rdx, matrixIn;


Auch das Haupt-Programm ist Pointer frei.
Code: Alles auswählen
begin
  matrixMultiplication(Matrix, v0, v0);
  matrixMultiplication(Matrix, v1, v1);
  matrixMultiplication(Matrix, v2, v2);

Assembler einfacher geworden gegenüber eines 8088er. Man muss sich nicht mehr mit Offset und Segment rum schlagen. :wink:
Mit diesen MMX-Funktionen kann man die Matrizen und Vektor-Berechnungen von OpenGL ein wenig beschleunigen. :wink:
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 22. Jun 2018, 20:22 Re: Von C++ nach Pascal

Ich habe grad mal nachgeschaut, zumindest Delphi unterstützt den @ Operoator im ASM, also könnte eventuell auch das gehen:

Es geht sogar noch eleganter, ohne Umwege über ein Register.
Code: Alles auswählen
function VectorMultiplySSE(const mat: TMatrix; const vec: TVector4f): TVector4f; assembler;
  {$asmmode intel}
asm
         Movups  Xmm4, [mat+$30] // xmm4 contains 1,5, 9,13
         Movups  Xmm5, [mat+$20] // +16 (4 bytes x 4 elements)

Oder ist dies etwa langsamer als folgender Code ?

Code: Alles auswählen
function VectorMultiplySSE(const mat: TMatrix; const vec: TVector4f): TVector4f; assembler;
  {$asmmode intel}
asm
         Movups  Xmm4, [rsi+$30] // xmm4 contains 1,5, 9,13
         Movups  Xmm5, [mat+$20] // +16 (4 bytes x 4 elements) 

Der kompilierte Code ist in beiden Varianten exakt gleich lang.

Ich habe noch im Debugger nachgeguckt, dort wird mat auf RSI übersetzt.

Code: Alles auswählen
unit1.pas:84                              Movups  Xmm4, [rsi+$30] // xmm4 contains 1,5, 9,13
000000000045FAB4 0f106630                 movups 0x30(%rsi),%xmm4
unit1.pas:85                              Movups  Xmm5, [mat+$20] // +16 (4 bytes x 4 elements)
000000000045FAB8 0f106e20                 movups 0x20(%rsi),%xmm5
unit1.pas:87                              Movups  Xmm6, [rsi+$10] // +32 (8 bytes x 4 elements)
000000000045FABC 0f107610                 movups 0x10(%rsi),%xmm6
unit1.pas:89                              Movups  Xmm7, [mat+$00] // +48 (12 bytes x 4
 

Der Bezeichnername finde ich eleganter, der kennt man garantiert, aber was für ein Register der Kompiler nimmt ist eine Frage.

Mein nächster Schritt wird sein, die SSE-Register zu verstehen, die sind voll Neuland für mich. :wink:
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

• Themenende •

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

porpoises-institution
accuracy-worried