On Friday 30 August 2002 08:49, Daniel wrote:

> Sauf erreur, le compilateur est capable de d�tecter une
> division/multiplication par une constante puissance de 2, et de transformer
> cette op�ration en bit-shift �quivalent.

> Seul le r�sultat du bench nous dira si la t�orie se confirme :-)

Test sans bench, mais avec gcc 2.96 (i586) et Bastard v0.16.
Compilations avec Optimization -O3.
Pas C++, car le code produit ne serait pas aussi facilement lisible.

test1:
for (i=0;i<16;i++) {
  a += w % 2;
  w /= 2;
}

test2:
for (i=0;i<16;i++) {
  a += w & 1;
  w >>= 1;
}

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.

Essayons de le forcer un peu:

test3a:
for (i=16;i>0;i--) {
  a += w & 1;
  w >>= 1;
}

08048531 B9 10 00 00 00  mov ecx , 0x10        ; load loop cnt
[...]
08048539 31 DB           xor ebx , ebx         ; a = 0
0804853B 8B 55 08        mov edx , [ebp+0x08]  ; load w
0804853E 89 F6           mov esi , esi         ; --
08048540 89 D0           mov eax , edx         ; copy w
08048542 D1 EA           shr edx , 0x1         ; shift w
08048544 83 E0 01        and eax , 0x1         ; test copy of w
08048547 01 C3           add ebx , eax         ; update a
08048549 49              dec ecx               ; loop counter
0804854A 75 F4           jnz ...

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

Finalement la proposition de Marc:

test4:
while (w != 0) {
  a += w & 1;
  w >>= 1;
}

08048511 31 C9           xor ecx , ecx         ; a = 0
08048513 89 E5           mov ebp , esp         ; 
08048515 8B 55 08        mov edx , [ebp+0x08]  ; load w
08048518 85 D2           test edx , edx        ; w already 0?
0804851A 74 0F           jx
0804851C 8D 74 26 00     lea esi , [esi]       ; --
08048520 89 D0           mov eax , edx         ; copy w
08048522 83 E0 01        and eax , 0x1         ; test copy
08048525 01 C1           add ecx , eax         ; update a
08048527 D1 EA           shr edx , 0x1         ; shift w
08048529 75 F5           jnz ...               ; w=0?

Bien d'accord que des autres principes peuvent etre plus efficaces.

btw une multiplication par deux est souvent traduit par add eax, eax.

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

Répondre à