Inine Assembler nutzbare Register

Für allgemeine Fragen zur Programmierung mit PureBasic.
SMaag
Beiträge: 152
Registriert: 08.05.2022 12:58

Inine Assembler nutzbare Register

Beitrag von SMaag »

Beim Purebasic Inline Assembler darf man leider nicht alle Register verwenden.

hier der Auszug aus der PB_HIlfe
- Auf x86-Prozessoren sind die zur Verfügung stehenden flüchtigen Register: eax, edx und ecx, xmm0, xmm1, xmm2 und xmm3.
- Auf x64-Prozessoren sind die zur Verfügung stehenden flüchtigen Register: rax, rcx, rdx, r8, r9, xmm0, xmm1, xmm2 und xmm3.
Alle anderen müssen immer reserviert bleiben.

ich hab für den ASM.Code zur Vektor Matrix Multiplikation mit SSE-Beschleunigung jedoch mehr Register
verwendet Xmm0..XMM7. Das könnte unter Umständen Schwierigkeiten geben.

hier der code! Fragen dazu im Anschluß

Code: Alles auswählen

 Procedure.i Vector_X_Matrix(*OUT.TVector, *IN.TVector, *Matrix.TMatrix)
    ; translated from the FreePascal Wiki at https://wiki.freepascal.org/SSE/de	  
   !MOV     rax, [p.p_Matrix]
   !Movups Xmm4, [rax + $00]
   !Movups Xmm5, [rax + $10]
   !Movups Xmm6, [rax + $20]
   !Movups Xmm7, [rax + $30]         
   !Mov rax,  [p.p_IN] 
   !Movups Xmm2, [rax]
   ; Line 0
   !Pshufd Xmm0, Xmm2, 00000000b
   !Mulps  Xmm0, Xmm4
   ; Line 1
   !Pshufd Xmm1, Xmm2, 01010101b
   !Mulps  Xmm1, Xmm5
   !Addps  Xmm0, Xmm1
   ; Line 2
   !Pshufd Xmm1, Xmm2, 10101010b
   !Mulps  Xmm1, Xmm6
   !Addps  Xmm0, Xmm1
   ; Line 3
   !Pshufd Xmm1, Xmm2, 11111111b
   !Mulps  Xmm1, Xmm7
   !Addps  Xmm0, Xmm1
   ; Return Result
   !Mov rax,  [p.p_OUT] 
   !Movups [rax], Xmm0
   Return
 EndProcedure

Wer kann dazu Auskunft geben?

1. Ich würde mal vermuten, dass wenn ich die nicht erlaubten Register in einer Procedure
verwende, die sonst keinen PB-Code ausführt, ist die Gefahr gering, dass ich wichtige Werte überschreibe.
Das reicht mir aber nicht, um das so zu machen.

2. Evtl. könnte man für die XMM4..7 entsprechende !PUSH und !POP Befehle einfügen.
Bin mir jedoch nicht sicher, ob dann der Stack für PB korrect bleibt. Theoretisch müsste er das.

3. Wie kommt man an den Assembler Out-Put???
Ich hab es mit Anleitung und dem Beispiel für Documented ASM-Output versucht.
Bei mir geht das alles nicht.
Mir würde schon der undokummentierte Output reichen. Also einfach die Datei wo das PB hinschreibt.
Ich hab sie leider nicht gefunden!
Benutzeravatar
mk-soft
Beiträge: 3701
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Inine Assembler nutzbare Register

Beitrag von mk-soft »

Schau mal in die Hilfe von PB nach Inline x86 ASM. Da steht welche register verwenden kannst.

Für ASM Output gibt es ein schönes IDE Tool von uns: Link: viewtopic.php?p=361128#p361128
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
SMaag
Beiträge: 152
Registriert: 08.05.2022 12:58

Re: Inine Assembler nutzbare Register

Beitrag von SMaag »

@mk-soft
Danke! Hab zwar etwas gebraucht, bis ich das mit den Tools verstanden habe, aber jetzt geht's!

Jetzt ist mir aufgefallen, dass da gar keine PUSH Befehle drin sind, was eigentlich auch klar ist. Die werden erst vom Assembler bei der Übersetzung erzeugt.

Also man muss die XMM4..7 mit aller höchster Wahrscheinlichkeit selber sichern, sonst gibt's irgendwann Probleme, wenn PB, da irgendwelche
Zwischenwerte von vor dem Procedureaufruf gespeichert werden.
Leider kann man XMM-Register nicht direkt mit PUSH, POP bearbeiten.

über Google Suche hab ich folgdendes gefunden

/For saving of just one xmm register e.g xmm0
sub esp, 16 // allocate space on stack
movdqu dqword [esp], xmm0

//Pop back the value from stack to xmm0
movdqu xmm0, dqword [esp]
add esp, 16 // re-align the stack

Kann man das wirklich so machen, oder muss man das epb-Register mit bearbeiten?

so in etwa!

Macro ASM_PUSH_XMM(XmmNo) ; !!! untested

!Push ebp ; aktuellen Base-Pointer sichern
!Mov ebp, esp ; hier bin ich mir nicht sicher!!!
!Sub esp, 16 ; das sollte stimmen
!Movdqu [esp], XmmNo ; das stimmt

EndMacro

Macro ASM_POP_XMM(XmmNo) ; !!! untested

!Movdqu XMMNo, [esp]
!Mov esp, ebp ;
!Pop ebp

EndMacro


eine alternative Lösung mit Structure für Speicherung der Xmm-Register

Code: Alles auswählen

 Structure TXmm4 Align 16
    XMM4.q		; durch Align 16 werden nach jeder q-Var 8 leer-Bytes eingefügt
    XMM5.q
    XMM6.q
    XMM7.q
  EndStructure
  
  Macro SaveXMM_4to6(regA, regD, regC)
    Protected memXmm.TXmm4  ; das müsste direkt den Bereich auf für die XMM-Register korrekt auf dem Stack erzeugen
    !Mov regD, [p.v_memXmm]
    !Movdqu [regD]   , Xmm4
    !Movdqu [regD+16], Xmm5
    !Movdqu [regD+32], Xmm6
  EndMacro
  
  Macro RestoreXMM_4to6(regA, regD, regC)
    ; we use RDX,EDX Register to not overwrite our Retrun-Value in RAX,EAX
    !Mov regD, [p.v_memXmm]
    !Movdqu Xmm4, [regD]
    !Movdqu Xmm5, [regD+16]
    !Movdqu Xmm6, [regD+32]
  EndMacro

SMaag
Beiträge: 152
Registriert: 08.05.2022 12:58

Re: Inine Assembler nutzbare Register

Beitrag von SMaag »

hab was gefunden
https://www.agner.org/optimize/calling_conventions.pdf
Seite 45 : 9 Exeption handling and stack unwinding

If a function has any local objects with destructors and if an exception or longjmp or thread
termination can occur inside the function or any of its child functions, then this function must
support stack unwinding.

_FunctionWithFramePointer PROC NEAR
PUSH EBP
MOV EBP, ESP
...
MOV ESP, EBP
POP EBP
RET
_FunctionWithFramePointer ENDP
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Inine Assembler nutzbare Register

Beitrag von STARGÅTE »

SMaag hat geschrieben: 13.12.2022 18:17 Beim Purebasic Inline Assembler darf man leider nicht alle Register verwenden.
Doch, darfst du schon, du musst nur sicher stellen, dass nach deinem ASM Code wieder alles so ist wie vor deinem ASM code, mit Ausnahme der flüchtigen Register (siehe Hilfe).
SMaag hat geschrieben: 13.12.2022 18:17 ich hab für den ASM.Code zur Vektor Matrix Multiplikation mit SSE-Beschleunigung jedoch mehr Register
verwendet Xmm0..XMM7. Das könnte unter Umständen Schwierigkeiten geben.
Ja das könnte passieren, wenn auch nicht sofort, so könnte irgendwann ein PB Update zu einem Fehler führen.
SMaag hat geschrieben: 13.12.2022 18:17 Evtl. könnte man für die XMM4..7 entsprechende !PUSH und !POP Befehle einfügen.
Bin mir jedoch nicht sicher, ob dann der Stack für PB korrect bleibt. Theoretisch müsste er das.
PUSH und POP sind nur für 32/64 bit register, da kommst du also nicht weiter mit den 128ern.
Ansonsten bleibt der Stack erhalten, wenn du in deinem Code genauso viel POP hast wie PUSH (oder den Stackpointer manipulierst).
Allerdings musst du dann aufpassen, wenn du innerhalb deines ASM Codes auf PB Variablen zugreifen willst, dann musst du dort entsprechende Verschieben.

Code: Alles auswählen

PUSH rbx
PUSH rsi
PUSH rdi

MOV	rdi, [p.p_Pointer1+24]   ; hier +24 für 3 * 8 Byte durch die PUSH
MOV  rsi, [p.p_Pointer2+24]
MOV  rbx, [p.v_Variable3+24]
;...
Zur Manipulation des Stackpointers möchte ich kein Halbwissen verbreiten.
Alternativ eine Protected Variable zu nehmen kann auch auch eine Lösung sein, weil PureBasic diese eh im Stack ablegt. Es läuft also aufs selbe hinaus.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
juergenkulow
Beiträge: 188
Registriert: 22.12.2016 12:49
Wohnort: :D_üsseldorf-Wersten

Re: Inine Assembler nutzbare Register

Beitrag von juergenkulow »

Code: Alles auswählen

; Ausgabe von Vector *OUT 
Structure TVector
  f.f[4]
EndStructure

Structure TMatrix
  vec.TVector[4]  
EndStructure  

Procedure Vector_X_Matrix(*OUT.TVector, *IN.TVector, *Matrix.TMatrix)
  !mov rbp,qword [p.p_Matrix ]                                 
  !Movups Xmm4, [rbp + $00]
  !Movups Xmm5, [rbp + $10]
  !Movups Xmm6, [rbp + $20]
  !Movups Xmm7, [rbp + $30]         
  !mov rbp,qword [p.p_IN ]
  !Movups Xmm2, [rbp]
  ; Line 0
  !Pshufd Xmm0, Xmm2, 00000000b
  !Mulps  Xmm0, Xmm4
  ; Line 1
  !Pshufd Xmm1, Xmm2, 01010101b
  !Mulps  Xmm1, Xmm5
  !Addps  Xmm0, Xmm1
  ; Line 2
  !Pshufd Xmm1, Xmm2, 10101010b
  !Mulps  Xmm1, Xmm6
  !Addps  Xmm0, Xmm1
  ; Line 3
  !Pshufd Xmm1, Xmm2, 11111111b
  !Mulps  Xmm1, Xmm7
  !Addps  Xmm0, Xmm1
  ; Return Result 
  !mov rbp,qword [p.p_OUT ]
  !Movups [rbp], Xmm0 
EndProcedure

Define a.TVector\f[0]=1.0 : a\f[1]=2.0 : a\f[2]=3.0 : a\f[3]=4.0 
Define c.TVector
Define m.TMatrix\vec[0]\f[0]=1.0 : m\vec[1]\f[1]=1.0 : m\vec[2]\f[2]=1.0 : m\vec[3]\f[3]=1.0
Vector_X_Matrix(@c,@a,@m)
Debug "v[0]:"+StrF(c\f[0])+" v[1]:"+StrF(c\f[1])+" v[2]:"+StrF(c\f[2])+" v[3]:"+StrF(c\f[3]) 
;v[0]:1 v[1]:2 v[2]:3 v[3]:4

; XMMx Register von x64dbg
; XMM0  : 4 3 2 1
; XMM1  : 4 0 0 0
; XMM2  : 4 3 2 1
; XMM3  : 0 0 0 0
; XMM4  : 0 0 0 1
; XMM5  : 0 0 1 0
; XMM6  : 0 1 0 0
; XMM7  : 1 0 0 0
; XMM8  : 0 0 0 0
; XMM9  : 0 0 0 0
; XMM10 : 0 0 0 0
; XMM11 : 0 0 0 0
; XMM12 : 0 0 0 0
; XMM13 : 0 0 0 0
; XMM14 : 0 0 0 0
; XMM15 : 0 0 0 0
Bitte stelle Deine Fragen, denn den Erkenntnisapparat einschalten entscheidet über das einzig bekannte Leben im Universum.

Jürgen Kulow Wersten :D_üsseldorf NRW D Europa Erde Sonnensystem Lokale_Flocke Lokale_Blase Orion-Arm
Milchstraße Lokale_Gruppe Virgo-Superhaufen Laniakea Sichtbares_Universum
SMaag
Beiträge: 152
Registriert: 08.05.2022 12:58

Re: Inine Assembler nutzbare Register

Beitrag von SMaag »

DANKE! das hat sich mittlerweile fast erledigt!

Mit dem Assembler Output von PB hab ich jetzt rausgefunden,
wie das gemacht wird.

Hier ist ein Auszug aus dem PB-ASM-OUT

Code: Alles auswählen

; Procedure Einsprungpunkt!
 PUSH   ebp
 PUSH   ebx
 
 SUB    esp, 8;  das sind Protected Variablen 

; das müsst nun das Sichern des neuen Stackpointers nach dem Anlegen der Variablen sein
 LEA    ebp,[esp]	
  PUSH   ebp
  POP    ebp

; CODE

  ADD    esp,8 ; das ist die Korrektur des Stackpointers für die Proteced Variablen
  POP    ebx	; altes ebx wieder herstellen
  POP    ebp  ; epb wieder herstellen
  RET    12 ; Übergabeparameter wieder vom Stack nehmen (ProcedureReturn)
d.h. intern dient EPB+Offset direkt zum adressieren der Variablen der Procedure auf dem Stack
und enthält den Stackpointer zum Zeitpunkt des Procedur-Calls.
Solange ich EPB nicht anfasse, dürfte alles i.O sein.

Ich denk damit bekomme ich das hin!
Hab schon eine sichere Variante mit einer Protected Struct für die Register, das ist zwar relativ viel Offset,
da der Speicher von PB automatisch mit 0en vollgeschrieben wird.
Wenn alles weitere sicher funktioniert, werd ich das nochmal optimiert testen.
Antworten