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.
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