Roman Merz wrote:

> Pas C++, car le code produit ne serait pas aussi facilement
 > lisible.

Ah ? �tonnant.
Avec GCC 3.2 en tout cas les deux codes produits sont aussi
lisibles, � l'exception du mangling de nom de fonction en C++.

> test1 & test2:
> 080484B6 31 DB           xor ebx , ebx         ; a = 0
> 080484B8 8B 55 08        mov edx , [ebp+0x08]  ; load w
> 080484BB 90              nop                   ; --
> 080484BC 8D 74 26 00     lea esi , [esi]       ; --
> 080484C0 89 D0           mov eax , edx         ; copy w
> 080484C2 D1 EA           shr edx , 0x1         ; shift w
> 080484C4 83 E0 01        and eax , 0x1         ; test w
> 080484C7 41              inc ecx               ; loop counter
> 080484C8 01 C3           add ebx , eax         ; update a
> 080484CA 83 F9 0F        cmp ecx , 0xF         ; loop finished?
> 080484CD 76 F1           jbe...
> 
> Le code produit est identique dans les deux cas. Mais gcc
 > n'arrive pour une fois pas de remplacer inc ecx; cmp ecx,
 > 0xF par un dec ecx.

Le passage � GCC >=3.1 est tr�s b�n�fique du c�t� des
optimisations. Sur un programme C++ de jeu de dames j'ai
gagn� dans les 40% ! En l'occurrence il utilise "dec" ici :
.L13:
         movl    %edx, %eax
         shrl    %edx
         andl    $1, %eax
         addl    %eax, %ebx
         decl    %ecx
         jns     .L13

En compilant sp�cialement pour K6, il utilise une instruction
"loop" qui d�cr�mente ecx et saute :
.L16:
         movl    %edx, %eax
         shrl    $1, %edx
         andl    $1, %eax
         addl    %eax, %ebx
         loop    .L16

5 instructions, pas mal. Quoique sur Athlon cette instruction
est fortement d�conseill�e, 8 cycles d'ex�cution !

> test3b:
> for (i=16;i--;) {...}
> 
> Souvent vu comme recommondation. Je ne suis pas de cet avis,
 > car c'est
> traduit par
> mov ecx, 0xF
> Loop:
> dec ecx
> cmp ecx, -0x1
> jnz Loop

Idem avec GCC 3.2, sauf en compilant pour K6 qui donne � nouveau
la version en 5 instructions avec "loop" !

> test4:
> while (w != 0) {
>   a += w & 1;
>   w >>= 1;
> }
> 
> Bien d'accord que des autres principes peuvent etre plus
 > efficaces.

� remarquer que cette version, avec une distribution al�atoire et
� �gale probabilit� des bits, est en moyenne plus rapide car la
boucle n'est pas toujours effectu�e 16 fois comme avec un for.
D'o� (sauf erreur) :
1/2^16 : 0 it�ration
1/2^16 : 1 it�ration
2/2^16 : 2 it�rations
4/2^16 : 3 it�rations
8/2^16 : 4 it�rations
...
32768/2^16 : 16 it�rations

D'o� un nombre moyen d'it�rations de
(somme n=0..15(2^n*(n+1)))/2^16 = (aid� de Knuth)
((15*2^(15+2)-(15+1)*2^(15+1)+2)/(2-1)^2+2^(15+1)-1)/2^16=

15.00001525878906250000
Ce qui fait un gain de presque une it�ration. Mouais, on doit
pouvoir prouver bien plus simplement que �a tend vers une
it�ration de gain...

De toute fa�on on reste dans les m�mes complexit�s d'algorithme.

Mais sur ce genre de petites manipulations, avec un processeur
CISC, les compilateurs semblent encore assez loin de solutions
optimales.

Sur Motorola 68000 (d�sol�, je ne connais pas assez le 386, d�j�
le 68000 j'oublie), une boucle de 3 instructions :

; IN  D0.w  mot
; OUT D1.w  nb de bits

        move.w  D2,-(SP); D2 sera utilis� pour optimiser
        sub.w   D2,D2   ; D2 = 0; bit X = 0

Loop: 
addx.w 
D2,D1 
; D1 += 0 + X
        add.w   D0,D0   ; D0 += D0; X = retenue
        bne.b   Loop    ; if (D0 != 0) goto Loop

        move.w  (SP)+,D2; restaure D2


Le guide AMD Athlon Processor x86 Code Optimization Guide �
http://www.amd.com/us-en/Processors/ProductInformation/0,,30_118_756_759%5E2983,00.html
donne une version bas�e sur l'algorithme point� par Ivo.
17 instructions pour compter les bits d'un mot de 32 bits, pas mal. :-)
En MMX il donne une version aussi rapide, mais sur 64 bits.

Marc Mongenet

--
http://www-internal.alphanet.ch/linux-leman/ avant de poser
une question. Ouais, pour se d�sabonner aussi.

Répondre à