Le test While...Wend est faussé par l'ajout de l'instruction Not.
(Not (a=b) ) == (a <> b)
En théorie, tu peux insérer ton code PB au sein d'un code ASM, mais dans la pratique, ça n'est pas possible à cause des modifs de registres qu'effectuent tes instructions PB. En gros, certaines instructions vont être ok (ex: calcul très spécifiques) si tu vérifies que l'équivalent ASM de l'instruction PB ne vient pas foirer ton/tes registre(s) de comptage. (paramètre /COMMENTED de PBCompiler.EXE pour vérifier le fichier ASM). Les autres instructions qui sont des macros de l'ensemble des fonctions dispo peuvent apporter à des foirages chaotiques, car il est impossible de vérifier l'ensemble des routines pré-compilées par Fred pour voir si elle vont foirer le(s) registre(s) de comptage utilisé(s). Pour réussir à insérer un code PB dans un code ASM, il faut procéder à une sauvegarde de registres.
Schéma:
![Début de 1ère partie de code ASM]
![Fin de 1ère partie de code ASM avec sauvegarde des registres]
[Début de code PB]
[Fin de code PB]
![Début de 2nde partie de code ASM avec restauration des registres]
![Fin de 2nde partie de code ASM]
Or, c'est ce que Fred a mis en place dans chacune de ses instructions de boucle: une sécurisation de registre, qui prend un temps non négligeable.
C'est ce laps de temps-là qui vous fait halluciner et penser que Fred a merdé. Pourtant, il n'a sûrement pas merdé. Seulement, l'ASM c'est tout sauf quelquechose de souple. Il n'y a que des types de boucles très spécifiques qui peuvent subir une absence de sécurisation des registres, notamment certains calculs (une addition, une soustraction, un swap ou une opération logique) ou l'utilisation des instructions XMM (mais là, on reste dans l'ASM et non dans les instructions PB). Pour tout le reste, il est impensable d'optimiser les boucles mieux que ce qu'elles sont déjà.
L'ASM ça n'est vraiment pas le truc souple!
Exemple:
Pour les petites boucles, il vaut mieux utiliser une étiquette, décrémenter le registre de comptage (1ère instruction) et répéter si non zéro (2nde instruction). (donc 2 instructions pour la totalité, c'est ça l'essentiel d'une boucle d'ailleurs)
Alors que pour les grosses boucles, il vaudrait mieux utiliser une étiquette, et "LOOPer" (1 seule instruction).
Problème: L'instruction n'est valable qu'à partir d'un seuil tellement arbitraire selon les CPUs qu'elle est inutilisable. Il faudrait que l'exécutable démarre en mesurant ce seuil et recompile les instructions machine pour y insérer les instructions Loop là où elles sont valables. Et il faudrait que les boucles concernées aient une très grande itération FIXE, ce qui est rarement le cas. A mon avis, on doit retrouver des instructions LOOP dans un missile à tête chercheuse. Ailleurs, je ne vois pas trop où ça pourrait être utile...
Mais bon, pour les hardis crasher, je vous ai rajouté une boucle ASM0 (faut bien qu'on rigole un peu): il n'y a juste que 2 instructions tout simplement, comme expliqué plus haut:
Code : Tout sélectionner
;==========================
; Test by Mytic
;==========================
;
DisableDebugger
; !!! désactivez le débogueur avant !!!
max = 999999999
;=================================(ASM0)============================
;(Ollivier)
Delay(1000)
t.d = ElapsedMilliseconds()
!PUSH Ecx
!MOV Ecx,[v_max]
!LP0: ; Etiquette de départ
; Ici, c'est l'intérieur de la boucle
; Dès qu'on insère une instruction PB,
; il faut absolument rajouter !PUSH Ecx
; avant et !POP Ecx après, ce qui revient
; aux même timings que FOR...NEXT
; ou REPEAT...UNTIL
!DEC Ecx ; Equivalent de Next, 1ère instruction
!JNE LP0 ; Equivalent de Next, 2nde instruction
!POP Ecx
S0.d = ElapsedMilliseconds()-t
;MessageRequester(Str(max), "")
;End
;=================================(ASM)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
!PUSH Eax
!PUSH Ebx
!MOV Eax,[v_a]
!MOV Ebx,[v_max]
!LP1:
!INC Eax
!CMP Eax,Ebx
!JNE LP1
!MOV [v_a],Eax
!POP Ebx
!POP Eax
S1.d = ElapsedMilliseconds()-t
;MessageRequester("ASM",StrD(S1))
;=================================(Semi ASM/PB!)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
!PUSH Eax
!MOV Eax,[v_a]
Repeat
!INC Eax
!MOV [v_a],Eax
Until(a=max)
!POP Eax
S2.d = ElapsedMilliseconds()-t
;MessageRequester("Semi ASM/PB!",StrD(S2))
;=================================(PB REPEAT UNTIL!)========================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
Repeat
a+1
Until(a=max)
S3.d = ElapsedMilliseconds()-t
;MessageRequester("PB!",StrD(S3))
;=================================(PB FOR NEXT!)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a=0
For a=1 To max
Next a
S4.d = ElapsedMilliseconds()-t
;MessageRequester("PB!",StrD(S3))
;=================================(PB WHILE WEND!)==========================
Delay(1000)
t.d = ElapsedMilliseconds()
a = 0
While (a<>max) ; Ici j'ai viré Not (instruction inutile en plus! Olliv)
a+1
Wend
S5.d = ElapsedMilliseconds()-t
;============================( Conclusion )
R$ = "ASM Version perso = " + Str(S0) + #CRLF$ + "ASM = " + Str(S1) + #CRLF$ + "ASM Repeat = " + Str(S2) + #CRLF$ + "Repeat Until = " + Str(S3) +#CRLF$ + "For Next = " + Str(S4) +#CRLF$ + "While Wend = " + Str(S5)
MessageRequester("Comparaison",R$)