Suche Leute, die 3DNow!, MMX, SSE bis SSE4, usw. können

Du brauchst Grafiken, gute Programme oder Leute die dir helfen? Frag hier.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

@NtQ: Bei den SSE-Beispielen sind von mir im Schreibrausch doch tatsächlich in einigen Fällen als "Hilfs-Befehle SSE2-Instruktionen verwendet worden. Auf einem Thunderbird gibt es damit eine Fehlermeldung. Mein Fehler! Habe alle Beispiele nochmal durchgeschaut und diesbezüglich korrigiert.

Gruss
Helle
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Da es verdammt fehlerträchtig ist z.B. auf einem SSE2-PC SIMD-Code nur für z.B. maximal SSE zu schreiben, hier ein Check-Programm, das zumindest grobe "Fehler" findet. Leider gibt es in FAsm nicht so etwas wie eine Direktive "No_SSE2". Statt dessen wird SSE2-Code im SSE-Programm munter abgearbeitet und der Autor wundert sich über Fehler-Meldungen von Nutzern, deren PC kein SSE2 unterstützt.
Hier also das Check-Programm:

Code: Alles auswählen

;- SIMD-Überprüfung, zumindest auf grobe Fehler
;- "Helle" Klaus Helbing, 16.01.2007, PB v4.02 
;- Befehle mit Doppel-M: EMMS (MMX), FEMMS (3DNow!). Kein x86-er! FEMMS gleich für Test auf 3DNow!
;- Es wird davon ausgegangen, dass "!" der Beginn einer Assembler-Befehlszeile ist, wenn vorher 
;-  nicht ";" oder "("
;- Zeilenumbruch "0D0A"
;- Leerzeilen "0D0A"

Global DNow.l
Global Filelaenge.l
Global IsX.l
Global MemoryID.l
Global Zeile.l = 1

Global C.b
Global Datei$ = ""
Global SuchB$ = ""

Global Ext$ = ""
Global Ext1$ = "3DNow!"
Global Ext2$ = "Extended 3DNow!"
Global Ext3$ = "SSE"
Global Ext4$ = "SSE2"
Global Ext5$ = "SSE3"
Global Ext6$ = "SSSE3"

Global MMXmitXMM$ = " MOVD MOVQ PADDB PADDW PADDD PADDSB PADDSW PADDUSB PADDUSW PMADDWD PMULHW PMULLW PSUBB PSUBW PSUBD PSUBSB PSUBSW PSUBUSB PSUBUSW PSLLW PSLLD PSLLQ PSRAW PSRAD PSRLW PSRLD PSRLQ PAND PANDN POR PXOR PCMPEQB PCMPEQW PCMPEQD PCMPGTB PCMPGTW PCMPGTD PACKSSWB PACKSSDW PACKUSWB PUNPCKHBW PUNPCKHWD PUNPCKHDQ PUNPCKLBW PUNPCKLWD PUNPCKLDQ " ;alle ohne EMMS FXRSTOR FXSAVE
Global DNow$ = " PAVGUSB PFACC PFADD PFMUL PFRCP PFRCPIT1 PFRCPIT2 PFRSQIT1 PFRSQRT PFSUB PFSUBR PMULHRW PF2ID PI2FD PFCMPEQ PFCMPGE PFCMPGT PFMAX PFMIN PREFETCH PREFETCHW " ;ohne PSWAPW und FEMMS
Global eDNow$ = " PSWAPD PFNACC PFPNACC PF2IW PI2FW "
Global SSE$ = " LDMXCSR MASKMOVQ MOVAPS MOVHLPS MOVHPS MOVLHPS MOVLPS MOVMSKPS MOVNTPS MOVNTQ MOVSS MOVUPS PEXTRW PINSRW PMOVMSKB STMXCSR CVTPI2PS CVTPS2PI CVTSI2SS CVTSS2SI CVTTPS2PI CVTTSS2SI ADDPS ADDSS DIVPS DIVSS MULPS MULSS PAVGB PAVGW PMULHUW PSADBW RCPPS RCPSS RSQRTPS RSQRTSS SQRTPS SQRTSS SUBPS SUBSS ANDNPS ANDPS ORPS XORPS CMPPS CMPSS COMISS MAXPS MAXSS MINPS MINSS PMAXSW PMAXUB PMINSW PMINUB UCOMISS PSHUFW SHUFPS UNPCKHPS UNPCKLPS PREFETCHT0 PREFETCHT1 PREFETCHT2 PREFETCHNTA SFENCE "
Global SSE2$ = " MASKMOVDQU MOVAPD MOVDQA MOVDQU MOVDQ2Q MOVHPD MOVLPD MOVMSKPD MOVNTDQ MOVNTI MOVNTPD MOVQ2DQ MOVSD MOVUPD CVTDQ2PD CVTDQ2PS CVTPD2DQ CVTPD2PI CVTPD2PS CVTPI2PD CVTPS2DQ CVTPS2PD CVTSD2SI CVTSD2SS CVTSI2SD CVTSS2SD CVTTPD2PI CVTTPD2DQ CVTTPS2DQ CVTTSD2SI ADDPD ADDSD DIVPD DIVSD MULPD MULSD PADDQ PMULUDQ PSUBQ SQRTPD SQRTSD SUBPD SUBSD PSLLDQ PSRLDQ ANDNPD ANDPD ORPD XORPD CMPPD CMPSD COMISD MAXPD MAXSD MINPD MINSD UCOMISD PSHUFD PSHUFHW PSHUFLW SHUFPD PUNPCKHQDQ PUNPCKLQDQ UNPCKHPD UNPCKLPD CLFLUSH LFENCE MFENCE PAUSE "
Global SSE3$ = " MOVDDUP MOVSHDUP MOVSLDUP FISTTP ADDSUBPD ADDSUBPS HADDPD HADDPS HSUBPD HSUBPS LDQU MONITOR MWAIT "
Global SSSE3$ = " PABSB PABSD PABSW PHADDD PHADDSW PHADDW PHSUBD PHSUBSW PHSUBW PMADDUBSW PMULHRSW PSIGNB PSIGND PSIGNW PSHUFB PALIGNR "

;SSE4 wäre hier (noch) Unfug

;-------- Abfragen
Global Proggipfad$ = "E:\Codes\PureBasic 4.0\SIMD\"   ;wo es eben jeder hat für den Schnellzugriff  ANPASSEN!
Datei$ = OpenFileRequester("SIMD - Datei auswählen", Proggipfad$, "PureBasic-Dateien (*.pb, *.pbi)|*.pb;*.pbi", 0)
;Datei$ = "SIMD-Test.pb"                ;eigene Testdatei
  If OpenWindow(0, 0, 0, 400, 230, "Welche Erweiterungen sind zulässig (MMX ist automatisch gesetzt) ?", #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
   
    CheckBoxGadget(1, 10,  10, 65, 20, Ext1$)
    CheckBoxGadget(2, 10,  40, 105, 20, Ext2$)
    CheckBoxGadget(3, 10,  70, 50, 20, Ext3$)
    CheckBoxGadget(4, 10,  100, 50, 20, Ext4$)    
    CheckBoxGadget(5, 10,  130, 50, 20, Ext5$)    
    CheckBoxGadget(6, 10,  160, 55, 20, Ext6$)    
    ButtonGadget(7, 10, 200, 380, 20, "O.K.")  
 
      Repeat
         WaitWindowEvent()
             DNow = GetGadgetState(1)
            eDNow = GetGadgetState(2)
              SSE = GetGadgetState(3)
             SSE2 = GetGadgetState(4)              
             SSE3 = GetGadgetState(5)              
            SSSE3 = GetGadgetState(6)             
             ENDE = EventGadget()    
      Until ENDE = 7
      
  EndIf
  CloseWindow(0)

;-------- Rückkopplungen sicherstellen, z.B. SSE2 beinhaltet automatisch auch SSE  
  If eDNow : DNow = 1 : EndIf
  If SSE2  : SSE  = 1 : EndIf
  If SSE3  : SSE  = 1 : SSE2 = 1 : EndIf
  If SSSE3 : SSE  = 1 : SSE2 = 1 : SSE3 = 1 : EndIf

;-------- Dateilänge ermitteln
        OpenFile(0, Datei$)
           Filelaenge = Lof(0)
        CloseFile(0) 

;-------- RAM-Speicher für direkten Zugriff reservieren
       MemoryID = AllocateMemory(Filelaenge)
       If MemoryID = $0 
         MessageRequester("Fehler!", "Konnte den benötigten Speicher nicht reservieren!")
        End  
       EndIf 

;-------- Datei ins RAM kopieren       
       OpenFile(0, Datei$)
           ReadFile(0, Datei$)
           ReadData(0, MemoryID, Filelaenge)
       CloseFile(0)       

;-------- Suchbeginn
!mov esi,[v_MemoryID]
!add [v_Filelaenge],esi
SucheAusrufe:
!cmp word[esi],0a0dh         ;Test auf Leerzeile
!je l_nextz0
!cmp byte[esi],3bh           ;";" Test auf Kommentarzeile
!je l_zeilee                 ;Zeilenende suchen
!cmp byte[esi],28h           ;"("
!je l_zeilee
!cmp byte[esi],21h           ;"!"   
!je l_sucheasm   
!inc esi
!cmp esi,[v_Filelaenge]
!jb l_sucheausrufe 
!jae l_ende

;-------- Zeilenende suchen
ZeileE:
!inc esi
!cmp esi,[v_Filelaenge]
!jae l_ende
!cmp word[esi],0a0dh
!jne l_zeilee

NextZ0: 
!inc esi                     ;weil 0d0a 2 Byte sind
NextZ:
!inc esi 
!cmp esi,[v_Filelaenge]
!jae l_ende
!inc [v_Zeile]
!jmp l_sucheausrufe

SucheASM:
!push esi
SucheASM1:
!dec esi
!cmp byte[esi],20h           ;Leerzeichen
!je l_sucheasm1
!cmp byte[esi],3ah           ;":"  wird akzeptiert
!je l_suchemm
!cmp byte[esi],0ah           ;LF  wird akzeptiert
!je l_suchemm
!pop esi
!jmp l_zeilee

;-------- Assembler-Zeile gefunden 
SucheMM:
!pop esi
SucheMM1:
!inc esi
!cmp byte[esi],20h
!je l_suchemm1
!mov ax,[esi]
!and ax,0dfdfh               ;Kleinbuchstaben-Bit löschen
!cmp ax,4d4dh                ;"MM"
!je l_suchereg
!cmp word[esi],0a0dh
!je l_nextz0
!jmp l_suchemm1

Suchereg:
!push esi
Suchereg1:
!dec esi
!cmp byte[esi],21h           ;"!"
!je l_isreg
!cmp byte[esi],5bh           ;"["
!jne l_suchereg1
!pop esi
!push esi
Suchereg2:
!inc esi
!cmp byte[esi],5dh           ;"]"
!je l_suchereg3
!cmp byte[esi],3bh           ;";" Test auf Kommentar
!je l_isreg       
!cmp byte[esi],0dh           ;CR
!je l_isreg    
!jmp l_suchereg2
Suchereg3:
!pop esi
!jmp l_zeilee
IsReg:
!pop esi

;-------- Vorher noch Test ob EMMS oder FEMMS 
!mov al,[esi-1]
!and al,0dfh                 ;Kleinbuchstaben-Bit löschen
!cmp al,58h                  ;"X"
!jne l_tests
!mov [v_IsX],1               ;ist ein XMM-Register!
!jmp l_echtreg

TestS:
!mov al,[esi+2]
!and al,0dfh                 ;Kleinbuchstaben-Bit löschen
!cmp al,53h                  ;"S"
!jne l_echtreg

!mov ax,[esi-2]
!and ax,0dfdfh               ;Kleinbuchstaben-Bit löschen
!cmp ax,4546h                ;"EF"
!jne l_echtreg               ;EMMS ist MMX und somit erlaubt! 

!cmp [v_DNow],0
!jne l_zeilee                ;ist erlaubt

MessageRequester("Fehler in " + Datei$ + " !", "Zeile " + Str(Zeile) + " : FEMMS ist ein 3DNow-Befehl !")
!jmp l_aus1

;-------- Hier geht´s los mit der Überprüfung, der Befehl steht links vom Register
EchtReg:
!push esi
;- nach links auf ":" und "!" testen, dann nach rechts auf 1.Buchstaben
!sub esi,4                   ;mal besten Wert ermitteln
ER1:
!dec esi
!cmp byte[esi],21h           ;"!"
!je l_er2
!cmp byte[esi],3ah           ;":"
!je l_er2
!jmp l_er1
ER2:
!inc esi
!cmp byte[esi],20h           ;Leerzeichen
!je l_er2
!pushad
SuchB$ = " "                 ;1 Leerzeichen für vorn!
!popad
!xor edi,edi
ER3:
!mov al,[esi+edi]
!cmp al,20h                  ;Leerzeichen
!je l_er4
!and al,0dfh                 ;Kleinbuchstaben-Bit löschen; ist auch das einzige Bit von Leerzeichen!!!
!mov [v_C],al
!pushad
SuchB$ + Chr(C) 
!popad
!inc edi
!jmp l_er3
ER4:
SuchB$ + " "                 ;1 Leerzeichen für hinten!

!pop esi

;-------- Test für SSE = 0
   If SSE = 0
     If IsX
       MessageRequester("Fehler in " + Datei$ + " !", "Zeile " + Str(Zeile) + " :  XMM - Register sind erst ab SSE möglich !")
       !jmp l_aus1
     EndIf      
    
     If FindString(SSE$, SuchB$, 1)
       Ext$ = Ext3$
       !jmp l_aus
     EndIf      
     
     If FindString(SSE2$, SuchB$, 1)
       Ext$ = Ext4$
       !jmp l_aus
     EndIf 

     If FindString(SSE3$, SuchB$, 1)
       Ext$ = Ext5$
       !jmp l_aus
     EndIf 
  
     If FindString(SSSE3$, SuchB$, 1)
       Ext$ = Ext6$
       !jmp l_aus
     EndIf   
   !jmp l_amd   
   EndIf 

;-------- Test für SSE2 = 0
   If SSE2 = 0
     If FindString(SSE2$, SuchB$, 1)
       Ext$ = Ext4$
       !jmp l_aus
     EndIf 

     If FindString(SSE3$, SuchB$, 1)
       Ext$ = Ext5$
       !jmp l_aus
     EndIf 
  
     If FindString(SSSE3$, SuchB$, 1)
       Ext$ = Ext6$
       !jmp l_aus
     EndIf   
   
     If IsX
       If FindString(MMXmitXMM$, SuchB$, 1)
         MessageRequester("Fehler in " + Datei$ + " !", "Zeile " + Str(Zeile) + " : " + SuchB$ + " ist mit einem XMM - Register erst ab SSE2 möglich !")
         !jmp l_aus1
       EndIf   
     EndIf 
   !jmp l_amd   
   EndIf 

;-------- Test für SSE3 = 0
   If SSE3 = 0
     If FindString(SSE3$, SuchB$, 1)
       Ext$ = Ext5$
       !jmp l_aus
     EndIf 
  
     If FindString(SSSE3$, SuchB$, 1)
       Ext$ = Ext6$
       !jmp l_aus
     EndIf   
   !jmp l_amd   
   EndIf 

;-------- Test für SSSE3 = 0
   If SSSE3 = 0
     If FindString(SSSE3$, SuchB$, 1)
       Ext$ = Ext6$
       !jmp l_aus
     EndIf   
   EndIf 

AMD:
;-------- Test für DNow = 0
   If DNow = 0
     If FindString(DNow$, SuchB$, 1)
       Ext$ = Ext1$
       !jmp l_aus
     EndIf   
   EndIf 

;-------- Test für eDNow = 0
   If eDNow = 0
     If FindString(eDNow$, SuchB$, 1)
       Ext$ = Ext2$
       !jmp l_aus
     EndIf 
   EndIf 

;-------- 
!jmp l_zeilee                ;alles o.K.  

;-------- Auswertung
Ende:
MessageRequester("Hurra!", "Keinen Fehler gefunden !")
!jmp l_aus1

Aus:
MessageRequester("Fehler in " + Datei$ + " !", "Zeile " + Str(Zeile) + " : " + SuchB$ + " ist ein " + Ext$ + " - Befehl !")
Aus1:
FreeMemory(MemoryID) 
End      
Gruss
Helle
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

@André: Habe soeben eine Version hochgeladen, die meiner Meinung nach brauchbar ist (nochmals überarbeitete Beispiele). Wenn noch Interesse besteht, kann diese Version weiterverwendet werden.

Gruss
Helle

P.S.: Ist gar nicht so einfach, so etwas halbwegs ordentlich über die Bühne zu bringen. Je näher man dem Ende kommt, desto weniger gefällt einem der Anfang. Auch gerade bei den Beispielen kann man gewaltig daneben liegen. Also: Respekt vor Deiner Arbeit betr. deutscher Hilfe-Datei! Wenn ich da mal rummosere, bitte nicht so ernst nehmen!
Benutzeravatar
Andre
PureBasic Team
Beiträge: 1765
Registriert: 11.09.2004 16:35
Computerausstattung: MacBook Core2Duo mit MacOS 10.6.8
Lenovo Y50 i7 mit Windows 10
Wohnort: Saxony / Deutscheinsiedel
Kontaktdaten:

Beitrag von Andre »

Helle hat geschrieben:@André: Habe soeben eine Version hochgeladen, die meiner Meinung nach brauchbar ist (nochmals überarbeitete Beispiele). Wenn noch Interesse besteht, kann diese Version weiterverwendet werden.
Alles klar, danke. Werde ich machen. :)
Helle hat geschrieben: P.S.: Ist gar nicht so einfach, so etwas halbwegs ordentlich über die Bühne zu bringen. Je näher man dem Ende kommt, desto weniger gefällt einem der Anfang. Auch gerade bei den Beispielen kann man gewaltig daneben liegen. Also: Respekt vor Deiner Arbeit betr. deutscher Hilfe-Datei! Wenn ich da mal rummosere, bitte nicht so ernst nehmen!
Kein Problem, danke für die "Blumen" :mrgreen:
Bye,
...André
(PureBasicTeam::Docs - PureArea.net | Bestellen:: PureBasic | PureVisionXP)
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

NtQ ging es ja auch um Macros mit SIMD-Befehlen. Im englischen Forum hatte Dreglor mal eine grosse Macro-Datei veröffentlicht, die aber etliche Fehler enthält. Hier mal ein kleines Beispiel von mir:

Code: Alles auswählen

;- Man kann eine (extra) Macro-Datei aufbauen (z.B. als Include-Datei)
;- Die Macro-Namen sind von mir frei gewählt! Sollten selbsterklärend sein
;- Bei z.B. Load könnte man noch zwischen integer, single-float und double-float unterscheiden
Macro Add_PS_XReg_XReg(Ziel_Register, Quell_Register)
  !addps xmm#Ziel_Register, xmm#Quell_Register
EndMacro

Macro Dup_XReg_Single0_All(Register)
  !shufps xmm#Register, xmm#Register, 0
EndMacro 

Macro Load_Var128_XReg(Ziel_Variable, Quell_Register) 
  !movups dqword[Ziel_Variable], xmm#Quell_Register
EndMacro 

Macro Load_XReg_Var128(Ziel_Register, Quell_Variable) 
  !movups xmm#Ziel_Register, dqword[Quell_Variable] 
EndMacro  

Macro Load_XReg_Var32(Ziel_Register, Quell_Variable)
  !movss xmm#Ziel_Register, dword[Quell_Variable]
EndMacro


;- Programm-Code
Load_XReg_Var128(0, A)       ;lade eine 128-Bit-Variable (hier A bis D) in Register XMM0
Load_XReg_Var32(1, E)        ;lade eine 32-Bit-Variable (hier E) in Register XMM1 (unteres Double-Word)
Dup_XReg_Single0_All(1)      ;dupliziere das untere Double-Word (0) in alle anderen (All) Double-Words von Register XMM1
Add_PS_XReg_XReg(0, 1)       ;addiere Packed-Single (also jeweils alle 4 Double-Words miteinander) Register XMM0 und XMM1 
Load_Var128_XReg(R, 0)       ;lade in eine 128-Bit-Variable (hier R) den Inhalt von Register XMM0

;- Test-Ausgabe
MessageRequester("Macro-Beispiel, zu A bis D wird jeweils E addiert", StrF(PeekF(?R)) + #LFCR$ + StrF(PeekF(?R + 4)) + #LFCR$ + StrF(PeekF(?R + 8)) + #LFCR$ + StrF(PeekF(?R + 12)))

End

;- Dies verwende ich gern, kann jeder anders machen (Strukturen?)  
!section '.data' Data readable writeable
!A DD       12345.6
!B DD       23456.7                    ;oder times 1 DD ....
!C DD       34567.8
!D DD       45678.9
!E DD       56789.0 
R:
!R DQ ?                                ;1 Quad-Word reservieren 
!times 1 DQ ?
Gruss
Helle
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

@Helle:
Check mal deine PNs. Da ist schon länger eine überfällig. :wink:
Antworten