Difference between revisions of "SSE/de"
(Created page with "{{Translate}} == SSE == Mit der SSE-Erweiterung der Modernen CPUs, kann bis zu 8-9fache Geschwindigkeitssteigerung erzielen, gegenüber klassischen FPU-Operationen.<br> Am be...") |
m (→Matrizen multiplizieren: Page category) |
||
(24 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | {{ | + | {{LanguageBar}} |
== SSE == | == SSE == | ||
− | Mit der SSE-Erweiterung der Modernen CPUs, kann bis zu 8-9fache Geschwindigkeitssteigerung erzielen, gegenüber klassischen FPU-Operationen. | + | |
+ | Mit der SSE-Erweiterung der Modernen CPUs, kann bis zu 8-9fache Geschwindigkeitssteigerung erzielen, gegenüber klassischen FPU-Operationen. | ||
+ | |||
Am besten werden 4x Vektoren und 4x4 Matrizen unterstützt, dies wird sehr viel bei OpenGL gebraucht. | Am besten werden 4x Vektoren und 4x4 Matrizen unterstützt, dies wird sehr viel bei OpenGL gebraucht. | ||
+ | |||
+ | Die Assembler-Blöcke sind so angepasst, das sie auf 32Bit und 64Bit CPU laufen, vorausgesetzt, sie sind Intel kompatibel ARM (Raspberry) geht nicht, die haben einen anderen Befehlssatz. | ||
+ | |||
+ | Folgende Beispiele sollten alle ab Intel-Core laufen. | ||
+ | |||
+ | |||
+ | Teilweise, kann Lazarus von Haus auf SSE und AVX verwenden, dafür muss folgendes unter ''"Projekt --> Projekteinstellungen... --> Benutzerdefinierte Einstellungen"'' ergänzt werden: | ||
+ | <pre> | ||
+ | -al | ||
+ | -CfAVX2 | ||
+ | -CpCOREAVX2 | ||
+ | -O3 | ||
+ | -Sv | ||
+ | -OpCOREAVX2 | ||
+ | -OoFASTMATH | ||
+ | </pre> | ||
+ | |||
+ | Dies hat auf die direkten Assembler Funktionen keinen Einfluss. | ||
=== Hilfs- Deklarationen und Funktionen === | === Hilfs- Deklarationen und Funktionen === | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="pascal"> | ||
+ | {$asmmode intel} | ||
+ | |||
type | type | ||
TVector4f = array[0..3] of Single; | TVector4f = array[0..3] of Single; | ||
TMatrix = array[0..3] of TVector4f; | TMatrix = array[0..3] of TVector4f; | ||
+ | |||
+ | var | ||
+ | a: TVector4f = (1.0, 2.0, 3.0, 4.0); | ||
+ | b: TVector4f = (5.0, 6.0, 7.0, 8.0); | ||
+ | c: TVector4f; | ||
+ | f: single = 2.0; | ||
procedure WriteVector(v: TVector4f); | procedure WriteVector(v: TVector4f); | ||
begin | begin | ||
− | WriteLn(v[0]: 8: 4, ' ', v[1]: 8: 4, ' ', v[2]: 8: 4, ' ', v[3]: 8: 4 | + | WriteLn(v[0]: 8: 4, ' ', v[1]: 8: 4, ' ', v[2]: 8: 4, ' ', v[3]: 8: 4); |
end; | end; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 19: | Line 48: | ||
=== Die wichtigsten Vektor-Operationen === | === Die wichtigsten Vektor-Operationen === | ||
− | <syntaxhighlight> | + | ==== Vektoren Addieren ==== |
+ | |||
+ | Klassisch: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Result[0] := v0[0] + v1[0]; | ||
+ | Result[1] := v0[1] + v1[1]; | ||
+ | Result[2] := v0[2] + v1[2]; | ||
+ | Result[3] := v0[3] + v1[3]; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | SSE beschleunigt: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register; | ||
+ | asm | ||
+ | Movups Xmm0, [v0] | ||
+ | Movups Xmm1, [v1] | ||
+ | Addps Xmm1, Xmm0 | ||
+ | Movups [Result], Xmm1 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Vektoren Subtrahieren ==== | ||
+ | |||
+ | Klassisch: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Result[0] := v0[0] - v1[0]; | ||
+ | Result[1] := v0[1] - v1[1]; | ||
+ | Result[2] := v0[2] - v1[2]; | ||
+ | Result[3] := v0[3] - v1[3]; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | SSE beschleunigt: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register; | ||
+ | asm | ||
+ | Movups Xmm0, [v0] | ||
+ | Movups Xmm1, [v1] | ||
+ | Subps Xmm1, Xmm0 | ||
+ | Movups [Result], Xmm1 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Vektoren Multiplizieren ==== | ||
+ | |||
+ | Klassisch: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Result[0] := v0[0] * v1[0]; | ||
+ | Result[1] := v0[1] * v1[1]; | ||
+ | Result[2] := v0[2] * v1[2]; | ||
+ | Result[3] := v0[3] * v1[3]; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | SSE beschleunigt: | ||
+ | |||
+ | <syntaxhighlight lang="pascal> | ||
+ | function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register; | ||
+ | asm | ||
+ | Movups Xmm0, [v0] | ||
+ | Movups Xmm1, [v1] | ||
+ | Mulps Xmm1, Xmm0 | ||
+ | Movups [Result], Xmm1 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Vektoren Dividieren ==== | ||
+ | |||
+ | Klassisch: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Result[0] := v0[0] / v1[0]; | ||
+ | Result[1] := v0[1] / v1[1]; | ||
+ | Result[2] := v0[2] / v1[2]; | ||
+ | Result[3] := v0[3] / v1[3]; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | SSE beschleunigt: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register; | ||
+ | asm | ||
+ | Movups Xmm0, [v0] | ||
+ | Movups Xmm1, [v1] | ||
+ | Divps Xmm1, Xmm0 | ||
+ | Movups [Result], Xmm1 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Vektoren Tauschen ==== | ||
+ | |||
+ | Klassisch: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Result[0] := v[3]; | ||
+ | Result[1] := v[2]; | ||
+ | Result[2] := v[1]; | ||
+ | Result[3] := v[0]; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | SSE beschleunigt: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | function Vec_Swap(const v: TVector4f): TVector4f; assembler; nostackframe; register; | ||
+ | asm | ||
+ | Movups Xmm0, [v] | ||
+ | Pshufd Xmm1,Xmm0, $1b | ||
+ | Movups [Result], Xmm1 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Vektoren Skalieren ==== | ||
− | + | Klassisch: | |
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Result[0] := v[0] * f; | ||
+ | Result[1] := v[1] * f; | ||
+ | Result[2] := v[2] * f; | ||
+ | Result[3] := v[3] * f; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | SSE beschleunigt: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | function Vec_Multiply_All(const v: TVector4f; f: Single): TVector4f; assembler; nostackframe; register; | ||
+ | asm | ||
+ | Movss Xmm0, f | ||
+ | Pshufd Xmm0, Xmm0, $00 | ||
+ | Movups Xmm1, [v] | ||
+ | Mulps Xmm1,Xmm0 | ||
+ | Movups [Result], Xmm1 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Beispiele === | ||
+ | <syntaxhighlight lang="pascal"> | ||
procedure TForm1.Button1Click(Sender: TObject); | procedure TForm1.Button1Click(Sender: TObject); | ||
var | var | ||
− | a: TVector4f = (1, 2, 3, 4); | + | a: TVector4f = (1.0, 2.0, 3.0, 4.0); |
− | b: TVector4f = (5, 6, 7, 8); | + | b: TVector4f = (5.0, 6.0, 7.0, 8.0); |
c: TVector4f; | c: TVector4f; | ||
Line 33: | Line 199: | ||
begin | begin | ||
WriteLn('Addieren'); | WriteLn('Addieren'); | ||
− | + | c := Vec_Add(a, b); | |
− | c | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
WriteVector(c); | WriteVector(c); | ||
WriteLn(); | WriteLn(); | ||
WriteLn('Subtrahieren'); | WriteLn('Subtrahieren'); | ||
− | + | c := Vec_Sub(b, a); | |
− | c | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
WriteVector(c); | WriteVector(c); | ||
WriteLn(); | WriteLn(); | ||
− | |||
WriteLn('Multipizieren'); | WriteLn('Multipizieren'); | ||
− | + | c := Vec_Multiply(b, a); | |
− | c | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
WriteVector(c); | WriteVector(c); | ||
WriteLn(); | WriteLn(); | ||
− | |||
WriteLn('Dividieren'); | WriteLn('Dividieren'); | ||
− | + | c := Vec_Divide(b, a); | |
− | c | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
WriteVector(c); | WriteVector(c); | ||
WriteLn(); | WriteLn(); | ||
WriteLn('Vertauschen'); | WriteLn('Vertauschen'); | ||
− | + | c := Vec_Swap(a); | |
− | c | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
WriteVector(c); | WriteVector(c); | ||
WriteLn(); | WriteLn(); | ||
WriteLn('Alle Multipizieren'); | WriteLn('Alle Multipizieren'); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
f := 2.2; | f := 2.2; | ||
− | + | c:=Vec_Multiply_All(a, f); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
WriteVector(c); | WriteVector(c); | ||
WriteLn(); | WriteLn(); | ||
Line 134: | Line 232: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Vektoren | + | === Vektoren multiplizieren === |
+ | |||
+ | Vektor mit einer Matrix multiplizieren. | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
{$asmmode intel} | {$asmmode intel} | ||
− | function VectorMultiplySSE(const mat: TMatrix; const vec: TVector4f): TVector4f; assembler; | + | function VectorMultiplySSE(const mat: TMatrix; const vec: TVector4f): TVector4f; assembler; nostackframe; register; |
asm | asm | ||
Movups Xmm4, [mat + $00] | Movups Xmm4, [mat + $00] | ||
Line 172: | Line 272: | ||
=== Matrizen multiplizieren === | === Matrizen multiplizieren === | ||
+ | |||
+ | 2 Matrizen mutiplizieren. | ||
+ | |||
Für eine Matrix-Multiplikation, hat man mit SSE etwa 8-9fache Geschwindigkeitssteigerung, gegenüber klassichen Single-Multiplikationen. | Für eine Matrix-Multiplikation, hat man mit SSE etwa 8-9fache Geschwindigkeitssteigerung, gegenüber klassichen Single-Multiplikationen. | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
{$asmmode intel} | {$asmmode intel} | ||
− | function MatrixMultiplySSE(const M0, M1: TMatrix): TMatrix; assembler; | + | function MatrixMultiplySSE(const M0, M1: TMatrix): TMatrix; assembler; nostackframe; register; |
asm | asm | ||
Movups Xmm4, [M0 + $00] | Movups Xmm4, [M0 + $00] | ||
Line 273: | Line 376: | ||
[[Category:Free Pascal Programmers Guide/de]] | [[Category:Free Pascal Programmers Guide/de]] | ||
+ | {{AutoCategory}} |
Latest revision as of 08:24, 19 January 2020
│ Deutsch (de) │
SSE
Mit der SSE-Erweiterung der Modernen CPUs, kann bis zu 8-9fache Geschwindigkeitssteigerung erzielen, gegenüber klassischen FPU-Operationen.
Am besten werden 4x Vektoren und 4x4 Matrizen unterstützt, dies wird sehr viel bei OpenGL gebraucht.
Die Assembler-Blöcke sind so angepasst, das sie auf 32Bit und 64Bit CPU laufen, vorausgesetzt, sie sind Intel kompatibel ARM (Raspberry) geht nicht, die haben einen anderen Befehlssatz.
Folgende Beispiele sollten alle ab Intel-Core laufen.
Teilweise, kann Lazarus von Haus auf SSE und AVX verwenden, dafür muss folgendes unter "Projekt --> Projekteinstellungen... --> Benutzerdefinierte Einstellungen" ergänzt werden:
-al -CfAVX2 -CpCOREAVX2 -O3 -Sv -OpCOREAVX2 -OoFASTMATH
Dies hat auf die direkten Assembler Funktionen keinen Einfluss.
Hilfs- Deklarationen und Funktionen
{$asmmode intel}
type
TVector4f = array[0..3] of Single;
TMatrix = array[0..3] of TVector4f;
var
a: TVector4f = (1.0, 2.0, 3.0, 4.0);
b: TVector4f = (5.0, 6.0, 7.0, 8.0);
c: TVector4f;
f: single = 2.0;
procedure WriteVector(v: TVector4f);
begin
WriteLn(v[0]: 8: 4, ' ', v[1]: 8: 4, ' ', v[2]: 8: 4, ' ', v[3]: 8: 4);
end;
Die wichtigsten Vektor-Operationen
Vektoren Addieren
Klassisch:
Result[0] := v0[0] + v1[0];
Result[1] := v0[1] + v1[1];
Result[2] := v0[2] + v1[2];
Result[3] := v0[3] + v1[3];
SSE beschleunigt:
function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register;
asm
Movups Xmm0, [v0]
Movups Xmm1, [v1]
Addps Xmm1, Xmm0
Movups [Result], Xmm1
end;
Vektoren Subtrahieren
Klassisch:
Result[0] := v0[0] - v1[0];
Result[1] := v0[1] - v1[1];
Result[2] := v0[2] - v1[2];
Result[3] := v0[3] - v1[3];
SSE beschleunigt:
function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register;
asm
Movups Xmm0, [v0]
Movups Xmm1, [v1]
Subps Xmm1, Xmm0
Movups [Result], Xmm1
end;
Vektoren Multiplizieren
Klassisch:
Result[0] := v0[0] * v1[0];
Result[1] := v0[1] * v1[1];
Result[2] := v0[2] * v1[2];
Result[3] := v0[3] * v1[3];
SSE beschleunigt:
function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register;
asm
Movups Xmm0, [v0]
Movups Xmm1, [v1]
Mulps Xmm1, Xmm0
Movups [Result], Xmm1
end;
Vektoren Dividieren
Klassisch:
Result[0] := v0[0] / v1[0];
Result[1] := v0[1] / v1[1];
Result[2] := v0[2] / v1[2];
Result[3] := v0[3] / v1[3];
SSE beschleunigt:
function Vec_Add(const v0, v1: TVector4f): TVector4f; assembler; nostackframe; register;
asm
Movups Xmm0, [v0]
Movups Xmm1, [v1]
Divps Xmm1, Xmm0
Movups [Result], Xmm1
end;
Vektoren Tauschen
Klassisch:
Result[0] := v[3];
Result[1] := v[2];
Result[2] := v[1];
Result[3] := v[0];
SSE beschleunigt:
function Vec_Swap(const v: TVector4f): TVector4f; assembler; nostackframe; register;
asm
Movups Xmm0, [v]
Pshufd Xmm1,Xmm0, $1b
Movups [Result], Xmm1
end;
Vektoren Skalieren
Klassisch:
Result[0] := v[0] * f;
Result[1] := v[1] * f;
Result[2] := v[2] * f;
Result[3] := v[3] * f;
SSE beschleunigt:
function Vec_Multiply_All(const v: TVector4f; f: Single): TVector4f; assembler; nostackframe; register;
asm
Movss Xmm0, f
Pshufd Xmm0, Xmm0, $00
Movups Xmm1, [v]
Mulps Xmm1,Xmm0
Movups [Result], Xmm1
end;
Beispiele
procedure TForm1.Button1Click(Sender: TObject);
var
a: TVector4f = (1.0, 2.0, 3.0, 4.0);
b: TVector4f = (5.0, 6.0, 7.0, 8.0);
c: TVector4f;
f: single = 2.0;
begin
WriteLn('Addieren');
c := Vec_Add(a, b);
WriteVector(c);
WriteLn();
WriteLn('Subtrahieren');
c := Vec_Sub(b, a);
WriteVector(c);
WriteLn();
WriteLn('Multipizieren');
c := Vec_Multiply(b, a);
WriteVector(c);
WriteLn();
WriteLn('Dividieren');
c := Vec_Divide(b, a);
WriteVector(c);
WriteLn();
WriteLn('Vertauschen');
c := Vec_Swap(a);
WriteVector(c);
WriteLn();
WriteLn('Alle Multipizieren');
f := 2.2;
c:=Vec_Multiply_All(a, f);
WriteVector(c);
WriteLn();
end;
Vektoren multiplizieren
Vektor mit einer Matrix multiplizieren.
{$asmmode intel}
function VectorMultiplySSE(const mat: TMatrix; const vec: TVector4f): TVector4f; assembler; nostackframe; register;
asm
Movups Xmm4, [mat + $00]
Movups Xmm5, [mat + $10]
Movups Xmm6, [mat + $20]
Movups Xmm7, [mat + $30]
Movups Xmm2, [vec]
// Zeile 0
Pshufd Xmm0, Xmm2, 00000000b
Mulps Xmm0, Xmm4
// Zeile 1
Pshufd Xmm1, Xmm2, 01010101b
Mulps Xmm1, Xmm5
Addps Xmm0, Xmm1
// Zeile 2
Pshufd Xmm1, Xmm2, 10101010b
Mulps Xmm1, Xmm6
Addps Xmm0, Xmm1
// Zeile 3
Pshufd Xmm1, Xmm2, 11111111b
Mulps Xmm1, Xmm7
Addps Xmm0, Xmm1
Movups [Result], Xmm0
end;
Matrizen multiplizieren
2 Matrizen mutiplizieren.
Für eine Matrix-Multiplikation, hat man mit SSE etwa 8-9fache Geschwindigkeitssteigerung, gegenüber klassichen Single-Multiplikationen.
{$asmmode intel}
function MatrixMultiplySSE(const M0, M1: TMatrix): TMatrix; assembler; nostackframe; register;
asm
Movups Xmm4, [M0 + $00]
Movups Xmm5, [M0 + $10]
Movups Xmm6, [M0 + $20]
Movups Xmm7, [M0 + $30]
// Spalte 0
Movups Xmm2, [M1 + $00]
Pshufd Xmm0, Xmm2, 00000000b
Mulps Xmm0, Xmm4
Pshufd Xmm1, Xmm2, 01010101b
Mulps Xmm1, Xmm5
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 10101010b
Mulps Xmm1, Xmm6
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 11111111b
Mulps Xmm1, Xmm7
Addps Xmm0, Xmm1
Movups [Result + $00], Xmm0
// Spalte 1
Movups Xmm2, [M1 + $10]
Pshufd Xmm0, Xmm2, 00000000b
Mulps Xmm0, Xmm4
Pshufd Xmm1, Xmm2, 01010101b
Mulps Xmm1, Xmm5
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 10101010b
Mulps Xmm1, Xmm6
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 11111111b
Mulps Xmm1, Xmm7
Addps Xmm0, Xmm1
Movups [Result + $10], Xmm0
// Spalte 2
Movups Xmm2, [M1 + $20]
Pshufd Xmm0, Xmm2, 00000000b
Mulps Xmm0, Xmm4
Pshufd Xmm1, Xmm2, 01010101b
Mulps Xmm1, Xmm5
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 10101010b
Mulps Xmm1, Xmm6
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 11111111b
Mulps Xmm1, Xmm7
Addps Xmm0, Xmm1
Movups [Result + $20], Xmm0
// Spalte 3
Movups Xmm2, [M1 + $30]
Pshufd Xmm0, Xmm2, 00000000b
Mulps Xmm0, Xmm4
Pshufd Xmm1, Xmm2, 01010101b
Mulps Xmm1, Xmm5
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 10101010b
Mulps Xmm1, Xmm6
Addps Xmm0, Xmm1
Pshufd Xmm1, Xmm2, 11111111b
Mulps Xmm1, Xmm7
Addps Xmm0, Xmm1
Movups [Result + $30], Xmm0
end;
Autor: Mathias