Donc usage de la pile.
Il y a 2 paires d'empilement :
1) Une pour protéger les fonctions "autour" de la routine ASM.
2) L'autre pour protéger la routine de la fonction native appelée dans la routine
J'ai mis les registres sans rigueur autre que le bon fonctionnement de ce listing.
Un deuxième point c'est le registre R12. Il est égal à 2, tout le temps, comme une constante. Curieusement, quand je le remplace par une constante immédiate (deux, 2), j'ai une vitesse plus lente de test. Comme si le voisinage des registres avait une influence sur l'optimisation des sauts.
L'exemple ici c'est un testeur de nombres premiers stockés dans le tableau P().
A titre comparatif, je crois que la routine ASM qui est 4 fois plus rapide que son équivalent en natif, cette routine ASM donc reste environ 16 (seize) fois plus lente que le listing proposé de recherche des nombres premiers par fweil en Automne 2015. (méthode éprouvée de recherche, et utilisation des SIMD)
Code : Tout sélectionner
;******************************************************************************************************************************************
Macro FinDeTest()
! FinDeTest Equ 100000 ; Maximum en ASM
EndMacro
#Fin = 100000 ; Maximum en natif (identique)
Global L, Sq, M, N, I, J, K = 1023
Global Dim P(K)
P(J) = 2
J + 1
P(J) = 3
J + 1
P(J) = 5
J + 1
; Procédure initiale
Procedure PN3()
For I = 4 To #Fin
Sq = Sqr(I)
M = 0
L = P(0)
Repeat
If (I % L) = 0 ; L'ASM fournira 2 résultats
; 1) Le quotient entier (RAX)
; 2) Le restant (modulo) (RDX)
Goto pasPremier
EndIf
M + 1
L = P(M)
Until L > Sq
P(J) = I
J + 1
If J > K
K + 1
K << 1
K - 1
ReDim P(K)
EndIf
pasPremier:
Next
EndProcedure
Macro Empile()
! Push R10
! Push R11
! Push R12
! Push R13
! Sub RSP, 32
EndMacro
Macro Depile()
! Add RSP, 32
! Pop R13
! Pop R12
! Pop R11
! Pop R10
EndMacro
; On optimise (à 400%) la routine extraite du fichier PureBasic.ASM
Procedure PN4()
FinDeTest()
Empile()
! Mov R12, 2
! Mov R11, 7 ; I = 7
! Mov R13, QWORD [a_P] ; *M = @P(0)
! _Depart:
! Mov R9, QWORD [R13] ; L = P(0)
! Mov R10, r13
! _Repeat3:
! Mov RAX, R11 ; If (I % L) = 0 (I = R11)
! CQO
! IDiv R9
! Cmp RDX, 0
! JZ _Paspremier
! Cmp RAX, R9 ; Tout testé ?
! JB _Estpremier
! Mov R9, QWORD [R10+8] ; L = peekq(*M) (<=> P(M) )
! LEA R10, [R10+8] ; *M + 8
! Jmp _Repeat3
! _Estpremier:
! Mov R15, QWORD [v_J] ; P(J) = I
! Mov QWORD [R13+R15*8], R11
! Inc R15 ; J + 1
! Mov QWORD [v_J], R15
! Mov R15, QWORD [v_J] ; If J > K
! Cmp R15, QWORD [v_K]
! JLE _Paspremier
! Mov R15, QWORD [v_K] ; K + 1
! Inc R15
! SAL R15, 1 ; K << 1
! Dec R15 ; K - 1
! Mov QWORD [v_K], R15
Empile()
! Mov RAX, R15 ; ReDim P(K)
! Inc RAX
! Mov RDX, a_P
! Mov RCX, RAX
! Call SYS_ReAllocateArray ; /!\ Regs volatiles /!\
Depile()
! Mov R13, QWORD [a_P]
! _Paspremier:
! Add R11, R12 ; I + 2
! Cmp R11, FinDeTest
! JB _Depart
Depile()
EndProcedure
Delay(1)
t0 = ElapsedMilliseconds()
PN4()
t1 = ElapsedMilliseconds()
delta = t1 - t0
If delta = 0
MessageRequester("", "Div / 0")
EndIf
Frq = (1000 * J) / delta
M$ = Str(J) + " premiers trouvés de 2 à " + Str(#Fin) + Chr(10)
M$ + "en " + Str(delta) + " ms" + Chr(10)
M$ + "Fréquence : " + Str(Frq) + "Hz (nb 1ers / seconde)"
MessageRequester("", M$)