Pile et voisinage des registres

Pour discuter de l'assembleur
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Pile et voisinage des registres

Message par Ollivier »

Dans cet exemple, j'ai extrait l'empilement/dépilement de la pile et placé ça dans des macros. On n'est pas toujours contraints de le faire. Là, ce qui force à "protéger" les registres, c'est l'utilisation d'une fonction native : PB_SysReallocateArray.

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$)
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Pile et voisinage des registres

Message par Ollivier »

C'est un délire ces trains de satellites. Au dessus de Paris à l'oeil nu, en ce moment-même, orientation Ouest-Est.

J'enchaînerai sur une étrange observation sur les nombres premiers. Papipp, fweil et d'autres ont déjà dû observer ça...
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Pile et voisinage des registres

Message par Ollivier »

On va considérer, qu'excepté 2 et 5, les nombres premiers se terminent toujours par le chiffre 1, 3, 7 ou 9.

Si on prend un suite entre 10K et 10K + 10 (K reste toujours entier), par exemple entre 10 et 20, on constate alors 4 "places" susceptibles d'être occupées par des nombres premiers : 11, 13, 17 et 19.

C'est pareil entre n'importe quelle autre paire de bornes : entre 20 et 30, on a les places 21, 23, 27 et 29.

Entre 30 et 40, on a les places 31, 33, 37 et 39. Etc...

C'est assez pratique d'avoir un lot de 4 places qui peuvent être dans 2 et seulement 2 cas de figure : soit un nombre premier, soit un nombre pas premier.

Ça fait un quartet. Un nombre de 4 bits entre 0000 et 1111 (base 2) ou entre 0 et 15 (base 10), ou encore entre 0 et F (base 16).

Résultat : après tests entre 10 et 20, j'ai le code F, car 11, 13, 17 et 19 sont premiers.

En suivant l'ordre de lecture (j'en conviens, car on peut suivre l'ordre inverse aussi) entre 20 et 30, j'ai le code 5 (code 0101 base 2, car 23 et 29 sont alors seuls premiers).

Ainsi entre 10 et 50, j'ai le code F5AE.

Je vais considérer que chaque chiffre hexa se répartit en x et en y alternativement : xyxyxyxyxyxy etc...

Autrement dit, entre 10K et 10K + 20 (vingt), j'ai un point sur une surface limitée de 16 par 16.

Si je dessine un sprite de 16 par 16 avec tous ces tests, étrangement, ça remplit une sorte de chambranle tout léger. En tout cas, si les bits 1 des nombres premiers sont persistants, on n'obtient absolument pas un carré blanc de 16 pixels par 16 pixels, même si on pousse la recherche à plusieurs millions de tests. Seul un quart de la surface environ est occupé.

Autrement dit : << dis-moi les 4 états, premiers ou non, des nombres terminant par 1, 3, 7 et 9 dans une dizaine, je te trouverai 75% des états impossibles dans la dizaine suivante. >>
Répondre