@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
Suche Leute, die 3DNow!, MMX, SSE bis SSE4, usw. können
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:
Gruss
Helle
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
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!
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!
- 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:
Alles klar, danke. Werde ich machen.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.

Kein Problem, danke für die "Blumen"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!

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:
Gruss
Helle
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 ?
Helle
- 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