Autor |
Beitrag |
Whaite
Hält's aus hier
Beiträge: 2
|
Verfasst: Do 08.05.08 00:16
Hallo zusammen,
ich habe ein etwas seltsames Problem mit einem Record unter TurboDelphi, den ich mittels SSE optimieren will. Folgendermaßen sieht mein Test-Code aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| type TglVector4f = record public var X, Y, Z, W: Single; class operator Add(A, B: TglVector4f): TglVector4f; end;
class operator TglVector4f.Add(A, B: TglVector4f): TglVector4f; asm movaps xmm0, DQWord ptr [A.X] movaps xmm1, DQWord ptr [B.X] addps xmm0, xmm1 movaps DQWord ptr [Result.X], xmm0 end;
procedure TForm1.FormCreate(Sender: TObject); var V, U: TglVector4f; begin V.X := 1; V.Y := 2; V.Z := 3; U.X := 4; U.Y := 14; U.Z := 24;
V := V + U; end; |
Kompiliere ich das so, endet das beim Zugriff auf [A.X] im class operator mit einer AccessViolation. Das seltsame daran ist: Entferne ich die Auskommentierung des asm-Codes in OnCreate (sodass der Code da ausgeführt wird) vor der eigentlichen Addition, wird korrekt gerechnet und kein Zugriffsfehler erzeugt. Ich habe schon einigermaßen rumprobiert, aber mir wird das weder so recht klar noch scheint sich allzu viel im Netz dazu finden zu lassen.
Übersetzt wird das alles vom Compiler dann jedenfalls so:
Auskommentiert/Ohne seltsamen Zusatz:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
| Unit1.pas.36: movaps xmm0, DQWord ptr [A.X] 0045215C 0F2800 movaps xmm0,dqword ptr [eax] Unit1.pas.37: movaps xmm1, DQWord ptr [B.X] 0045215F 0F280A movaps xmm1,dqword ptr [edx] Unit1.pas.38: addps xmm0, xmm1 00452162 0F58C1 addps xmm0,xmm1 Unit1.pas.39: movaps DQWord ptr [Result.X], xmm0 00452165 0F2901 movaps dqword ptr [ecx],xmm0 Unit1.pas.40: end; 00452168 C3 ret 00452169 8D4000 lea eax,[eax+$00] Unit1.pas.61: begin 0045216C 56 push esi 0045216D 57 push edi 0045216E 83C4D0 add esp,-$30 Unit1.pas.62: V.X := 1; 00452171 C704240000803F mov [esp],$3f800000 Unit1.pas.63: V.Y := 2; 00452178 C744240400000040 mov [esp+$04],$40000000 Unit1.pas.64: V.Z := 3; 00452180 C744240800004040 mov [esp+$08],$40400000 Unit1.pas.65: U.X := 4; 00452188 C744241000008040 mov [esp+$10],$40800000 Unit1.pas.66: U.Y := 14; 00452190 C744241400006041 mov [esp+$14],$41600000 Unit1.pas.67: U.Z := 24; 00452198 C74424180000C041 mov [esp+$18],$41c00000 Unit1.pas.73: V:=V+U; 004521A0 8D4C2420 lea ecx,[esp+$20] 004521A4 8D542410 lea edx,[esp+$10] 004521A8 8BC4 mov eax,esp 004521AA E8ADFFFFFF call TglVector4f.&op_Addition 004521AF 8D742420 lea esi,[esp+$20] 004521B3 8BFC mov edi,esp 004521B5 A5 movsd 004521B6 A5 movsd 004521B7 A5 movsd 004521B8 A5 movsd Unit1.pas.74: end; 004521B9 83C430 add esp,$30 004521BC 5F pop edi 004521BD 5E pop esi 004521BE C3 ret 004521BF 90 nop |
Mit zusätzlichem Asm-Code davor:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| Unit1.pas.36: movaps xmm0, DQWord ptr [A.X] 0045215C 0F2800 movaps xmm0,dqword ptr [eax] Unit1.pas.37: movaps xmm1, DQWord ptr [B.X] 0045215F 0F280A movaps xmm1,dqword ptr [edx] Unit1.pas.38: addps xmm0, xmm1 00452162 0F58C1 addps xmm0,xmm1 Unit1.pas.39: movaps DQWord ptr [Result.X], xmm0 00452165 0F2901 movaps dqword ptr [ecx],xmm0 Unit1.pas.40: end; 00452168 C3 ret 00452169 8D4000 lea eax,[eax+$00] Unit1.pas.61: begin 0045216C 55 push ebp 0045216D 8BEC mov ebp,esp 0045216F 83C4D0 add esp,-$30 00452172 56 push esi 00452173 57 push edi Unit1.pas.62: V.X := 1; 00452174 C745F00000803F mov [ebp-$10],$3f800000 Unit1.pas.63: V.Y := 2; 0045217B C745F400000040 mov [ebp-$0c],$40000000 Unit1.pas.64: V.Z := 3; 00452182 C745F800004040 mov [ebp-$08],$40400000 Unit1.pas.65: U.X := 4; 00452189 C745E000008040 mov [ebp-$20],$40800000 Unit1.pas.66: U.Y := 14; 00452190 C745E400006041 mov [ebp-$1c],$41600000 Unit1.pas.67: U.Z := 24; 00452197 C745E80000C041 mov [ebp-$18],$41c00000 Unit1.pas.70: movaps xmm0, dqword ptr [V.X] 0045219E 0F2845F0 movaps xmm0,dqword ptr [ebp-$10] Unit1.pas.73: V:=V+U; 004521A2 8D4DD0 lea ecx,[ebp-$30] 004521A5 8D55E0 lea edx,[ebp-$20] 004521A8 8D45F0 lea eax,[ebp-$10] 004521AB E8ACFFFFFF call TglVector4f.&op_Addition 004521B0 8D75D0 lea esi,[ebp-$30] 004521B3 8D7DF0 lea edi,[ebp-$10] 004521B6 A5 movsd 004521B7 A5 movsd 004521B8 A5 movsd 004521B9 A5 movsd Unit1.pas.74: end; 004521BA 5F pop edi 004521BB 5E pop esi 004521BC 8BE5 mov esp,ebp 004521BE 5D pop ebp 004521BF C3 ret |
Mein Problem; die Assemblerbefehle sind mir zwar klar, aber das Hintergrundwissen um die Logik warum genau hier nun push, pop, lea, etc. mit genau diesem und jenem Register notwendig ist, fehlt mir.  Ansonsten springt mich auch nichts an, was diesen seltsamen Unterschied erklären würde, ich tippe aber mal darauf, dass ich irgendwie falsche Speicheradressen bekomme. Schaue ich mir aber den Speicherbereich an, auf den eax zeigt, dann steht dort wirklich A.X, A.Y, A.Z, A.W ohne Lücke drin.
Hat da vielleicht jemand ne Idee oder einen Fortbildungslink?
MfG
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 08.05.08 08:41
Hallo,
sind Deine Daten überhaupt auf 16 Bytegrenzen ausgerichtet (aligned)?
Sicher gibt es hierfür Kompilereinstellungen.
homepages.fh-giessen...orlesung/sse-ref.pdf
Zitat: |
12.4.3. SSE – Datentransport Befehle
Die SSE Datentransport Befehle transportieren einfache Gleitkommazahlen zwischen zwei XMM
Registern oder zwischen einem XMM Register und dem Arbeitsspeicher.
MOVAPS—Move Aligned Packed Single-Precision Floating-Point Values
Instruction Description
MOVAPS xmm1, xmm2/m128 Move packed single-precision floating-point values from xmm2/m128 to xmm1.
MOVAPS xmm2/m128, xmm1 Move packed single-precision floating-point values from xmm1 to xmm2/m128.
Der MOVAPS Befehl kopiert einen Doppel-Quadword Operanden mit vier 32bit-Gleitkommawerten aus
dem Speicher in ein 128bit XMM Register und umgekehrt, oder zwischen zwei XMM Registern. Die
Speicheradresse muss 16 Byte aligned (d.h. ohne Rest durch 16 teilbar) sein.
MOVUPS—Move Unaligned Packed Single-Precision Floating-Point Values
Instruction Description
MOVUPS xmm1, xmm2/m128 Move packed single-precision floating-point values from xmm2/m128 to xmm1.
MOVUPS xmm2/m128, xmm1 Move packed single-precision floating-point values from xmm1 to xmm2/m128.
Der MOVUPS Befehl führt die gleiche Operation durch wie der MOVAPS Befehl, akzeptiert jedoch auch
nicht-alignte Adressen. Der MOVUPS Befehl ist dafür langsamer.
|
ALternativ MOVUPS testen oder Die Speicheradresse von V,U ausgeben lassen.
ala Format('%X %X %X %X',[@V.X,@V.Y,@V.Z,@V.W])
eventuell fehlt packed record
TglVector4f = packed record.
Gruß Horst
|
|
Whaite 
Hält's aus hier
Beiträge: 2
|
Verfasst: Do 08.05.08 14:29
Das war wohl so ziemlich das einzige, was ich vollkommen verdrängt hatte... und heute überleg ich noch, was das "a" eigentlich bedeuten sollte...
Mittels SetMinimumBlockAlignment(mba16Byte); lässt sich das Problem aus der Welt schaffen.
Einziger Nachteil, Delphi's FPU-Code scheint bei dieser Einzeloperation etwa 4 mal schneller zu sein.
Danke für die Antwort und den PDF-Link
MfG
|
|
|