Finalement, voici le code assembleur de la fonction suivante généré pour un 
processeur Itanium. Note : j'ai pris un tableu assez grand pour éviter les 
"loop unrolling" et poub=voir tester les performances (pas fait pour finir)

        uint BitCount(uint *w)
        {
                uint r = 0;
                uint i;

                for (i = 0; i < 65536; i++)
                {
                        r += *w & 0x2;
                        *w <<= 1;
                }

                return(r);
        }

Ce code doit être interprêté après avoir lu les documents mentionnés dans un 
de mes mails d'hier. Sinon, toute conclusion relève du folklore... Pour 
mémoire, Itanium a quadruplé chacune de ses unité fonctionnelle, il engendre 
(dans ce cas) du code en "modulo scheduled loop" et il peut effectuer jusqu'à 
4 opération en // par unité fonctionelle...

..L2:
BitCounter::
//file/line/col vm_app.c/45/1
//      ***EntryOp***   CMid911, r32 =             // A [vm_app.c: 45/1]
        alloc           r31 = ar.pfs, 1, 9, 0, 8   // M [vm_app.c: 45/1] [UVU: ]
        mov             ar.ec = 2                  // I
        brp.loop.few.imp ..L3, ..LB918             // B
        ld4             r33 = [r32]                // M [vm_app.c: 54/9] [UVuse]
        add             r8 = 0xffff, r0         ;; // I
        mov             r40 = ar.lc                // I [vm_app.c: 45/1]
        add             r9 = 0, r32             ;; // M
        nop.m           0                          // M
        mov             r41 = pr                   // I [vm_app.c: 45/1]
//      ***PseudoFenceOp***                        // A [vm_app.c: 45/1] [UVU: ]
        cmp.ne.or.andcm p16, p17 = 42, r0       ;; // M
        nop.m           0                          // M
        mov             ar.lc = r8                 // I
//file/line/col vm_app.c/50/6,52/5,54/9
        add             r8 = 0, r0                 // M [vm_app.c: 50/6] [UVU: ]
        nop.i           0                          // I
        nop.b           0                       ;; // B

..L3:
        nop.m           0                          // M
(p16)   extr.u          r32 = r33, 16, 16          // I [vm_app.c: 55/9]
(p16)   and             r34 = 2, r33               // I [vm_app.c: 54/9]
(p17)   add             r8 = r8, r35               // M [vm_app.c: 54/9]
        nop.f           0                          // F
[..LB918:] br.ctop.dptk.few ..L3                ;; // B [vm_app.c: 52/16]

..L4:
//file/line/col vm_app.c/58/5
        add             r33 = 0, r34               // M
        mov             ar.lc = r40                // I
        add             r32 = 0, r9             ;; // I
        st4             [r32] = r33                // M [vm_app.c: 55/9] [UVuse]
        mov             pr = r41, 0x1fffe          // I [vm_app.c: 58/5]
        br.ret.sptk.few rp                      ;; // B [vm_app.c: 58/5]

..L1:
//      ***EndOp***                             ;; // A

        .endp   BitCounter

Un mec d'HP m'a signalé qu'il existe une isnstruction beaucoup plus efficace 
pour compter les bits. Voici donc le code :

        #include <machine/inline.h>

        uint BitCount(uint *w)
        {
                uint r = 0;
                uint i;
                for (i = 0; i < 65536; i++)
                {
                        r += _Asm_popcnt(*w);
                        w++;
                }
        }

A mon avis, il faut aussi réduire le nombre de boucle car l'opération 
s'effectue sans doute sur 32 bits à la fois. DOnc pour un tableau de 128K  
bits (131072), on n'effectue plus que 4096 boucles, au lieu de 65536 avec la 
méthode précédente. De plus, l'instruction popcnt n'utilise qu'un seul cycle 
machine au lieu de plusieurs isntructions avec '& <<'. Notez aussi que 
l'incrémentation de w et i peut se faire dans le même cycle machine.

Un nouveau mêtier se dessine : programmeur assembleur sur Itanium :-)

Daniel




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

Répondre à