Journal GCC et le mmx/sse{1,2,3)/3dnow

Posté par  (site web personnel) .
Étiquettes : aucune
0
2
oct.
2005
Nos processeurs modernes sont formidables et sont capable de nous proposer des merveilles comme 4 multiplicationss flotantes en un cycle.
Je veux parler des fpu MMX/SSE/3dnow

Je me suis dit, Gcc doit bien gérer ça (?)

Je me suis donc amusé à générer un petit code c

#include <stdio.h>


int main (void)
{
float a1,b1,c1,a2,b2,c2,z,y,x;
int i;

for (i= 45 ; i< 789 ; i++ ) if (i % 119) a1 = (float)i+75;

a2 = a1+56.456;
b1 = a2 + 743.4454;
b2 = a2 + 7568.45454;
c1 = a2 + 42.456546;
c2 = a2 + 4212213;

printf("%f,%f,%f,%f,%f,%f\n",a1,b1,c1,a2,b2,c2);

x = a1+a2;
y = b1+b2;
z = c1+c2;
printf("%f,%f,%f\n",x,y,z);

return 0;
}

gcc -S testsimd.c -O6 -msse2 -mtune=athlon-4 -march=athlon-4 -o t.asm
qui me produit ce code assembleur :


main:
flds .LC8
pushl %ebp
movl $45, %ecx
movl %esp, %ebp
pushl %ebx
movl $1154949189, %ebx
subl $164, %esp
flds .LC0
andl $-16, %esp
subl $16, %esp
.p2align 4,,7
.L6:
movl %ecx, %eax
imull %ebx
movl %ecx, %eax
sarl $31, %eax
sarl $5, %edx
subl %eax, %edx
movl %edx, %eax
sall $4, %eax
subl %edx, %eax
sall $3, %eax
subl %edx, %eax
cmpl %eax, %ecx
je .L4
fstp %st(1)
xorps %xmm0, %xmm0
cvtsi2ss %ecx, %xmm0
movss %xmm0, -92(%ebp)
flds -92(%ebp)
fadd %st(1), %st
fxch %st(1)
.L4:
incl %ecx
cmpl $788, %ecx
jle .L6
ffreep %st(0)
fldl .LC1
fadd %st(1), %st
fxch %st(1)
movl $.LC6, (%esp)
fstl 4(%esp)
fxch %st(1)
fstps -12(%ebp)
fstps -88(%ebp)
flds -12(%ebp)
fld %st(0)
fstl 28(%esp)
fld %st(1)
faddl .LC2
fxch %st(1)
fsts -40(%ebp)
fxch %st(1)
fstps -12(%ebp)
fld %st(1)
faddl .LC4
fxch %st(2)
faddl .LC3
flds -12(%ebp)
fstl 12(%esp)
fxch %st(3)
fstps -12(%ebp)
fxch %st(1)
fadds .LC5
fxch %st(1)
fstps -16(%ebp)
flds -12(%ebp)
fxch %st(2)
fstps -72(%ebp)
fsts -20(%ebp)
fstpl 44(%esp)
fstl 20(%esp)
flds -16(%ebp)
fxch %st(1)
fstps -56(%ebp)
fstpl 36(%esp)
call printf
movl $.LC7, (%esp)
flds -40(%ebp)
flds -88(%ebp)
faddp %st, %st(1)
flds -72(%ebp)
flds -56(%ebp)
fxch %st(1)
fadds -16(%ebp)
fxch %st(1)
fadds -20(%ebp)
fxch %st(2)
fstpl 4(%esp)
fxch %st(1)
fstpl 20(%esp)
fstpl 12(%esp)
call printf
xorl %eax, %eax
movl -4(%ebp), %ebx
leave
ret


Là je me dit, "tiens bizare, on dirait plutôt du code 387, malgré les deux instructions mmx du début"

Poussant l'investigation plus loin, j'apprend que les registres du 387 et mmx/sse sont les mêmes.
Je lit le manuel intel et amd sur le sse2 et le 3dnow, et là j'ai été frappé par la complexité de ses instructions : à part celle dévolues à l'addition, et à la multiplication, elles sont vraiment tordues et pas simple du tout à manipuler pour un humain expérimenté, alors un compilo....

J'ai donc l'affreux doute que le compilateur n'y arrive pas, malgré ce qui est écrit ici : http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/i386-and-x86_002d64-Opt(...)

Est-ce une illusion d'optique, Y a t-il d'autres compilateurs qui le font (celui d'Intel je suppose), ou est-ce vraiment encore un problème du fait de la complexité des instructions SIMD ?
  • # ...

    Posté par  . Évalué à 7.

    Tu peux faire mumuse avec http://gcc.gnu.org/onlinedocs/gcc-4.0.1/gcc/Vector-Extensions.html#(...) si tu veux tester des vecteurs dans un code C et l'utilisation d'instruction SIMD.

    Par contre je suis pas sur que ton example soit tres significatif pour la vectorisation...
    • [^] # Komité de Korrektion ortographik

      Posté par  . Évalué à 2.

      _o/* PAF exemple *\o_ PAF
      PAF *\o/* PAF

      Pourtant c'est pas dur... En anglais on écrit example avec un a comme anglais et en français on écrit exemple avec un e comme française ! :-D
  • # Auto-vectorisation

    Posté par  (site web personnel) . Évalué à 8.

    Va faire un tour du côté de :
    http://gcc.gnu.org/wiki/Autovectorization%20Enhancements(...)

    Ca devrait fonctionner avec gcc 4.1. À ce que j'ai compris : gcc sera capable d'utiliser MMX, 3dNow, SSE, et tout ça avec « l'auto-vectorisation ».

    Par contre, on peut choisir entre 387 et SSE avec l'option ... (man gcc | less puis /fpu) ... avec les options :
    - mfpu=nom
    - mfpe=nom
    - mfp=nom

    Nom autorisés : fpa, fpe2, fpe3, maverick, vfp. Ah non, c'est peut-être plutôt :
    -mfpmath=nom

    Avec les noms 387 ou sse ou "sse,387".

    Haypo
    • [^] # Re: Auto-vectorisation

      Posté par  (site web personnel) . Évalué à 1.

      Donc, gcc 4.1 sera capable d'utiliser du SSE pour des entiers ?

      De quoi faire de la virgule fixe par exemple ;-)

      « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

  • # sse

    Posté par  (site web personnel) . Évalué à 9.

    > nous proposer des merveilles comme 4 multiplicationss flotantes en un cycle.
    ça c'est vraiment le max archithéorique, d'ailleurs ni intel ni amd ne le claironnent haut et fort.. En pratique, c'est plutot 2.5 flops / cycle , aussi bien pour les p4 que les athlons.

    > j'apprend que les registres du 387 et mmx/sse sont les mêmes.

    non, uniquement mmx/387 , le sse est à part.

    > est-ce vraiment encore un problème du fait de la complexité des instructions SIMD ?

    le "piège" c'est que l'option '-msse" ne fait qu'autoriser gcc à utiliser les instructions sse. Si tu veux le forcer à les utiliser pour les operations sur les float, il faut mettre -fpmath=sse . Note que ça ne veut pas dire qu'il utilisera les instructions sse vectorielles, genre movaps, addps,etc (parce que ça lui demanderait d'être un peu trop malin, et surtout de gerer leurs contraintes sur l'alignement des données), mais plutot les instructions scalaires, genre movss, addss etc. Donc pour l'instant ça ne sert quasiment à rien, autant tout faire à la mimine avec les intrinsics.
    • [^] # Re: sse

      Posté par  (site web personnel) . Évalué à 2.

      Effectivement, si je lui met la ligne
      gcc -S testsimd.c -O6 -mfpmath=sse -mtune=athlon-4 -march=athlon-4 -o t.asm

      et là il me sort du mmx, propre

      [montaigne@localhost simd]$ cat t.asm | grep %xmm

      movss .LC0, %xmm0
      xorps %xmm2, %xmm2
      cvtsi2ss %ecx, %xmm2
      addss %xmm0, %xmm2
      movss %xmm2, -92(%ebp)
      movss -12(%ebp), %xmm4
      movss %xmm4, -72(%ebp)
      movss -12(%ebp), %xmm5
      movss %xmm5, -92(%ebp)
      movss %xmm5, -56(%ebp)
      movss %xmm4, -92(%ebp)
      movss %xmm2, -92(%ebp)
      movss %xmm2, -88(%ebp)
      movss -88(%ebp), %xmm2
      movss -92(%ebp), %xmm3
      movss -72(%ebp), %xmm1
      movss -56(%ebp), %xmm0
      addss -16(%ebp), %xmm1
      addss -20(%ebp), %xmm0
      addss %xmm2, %xmm3
      movss %xmm3, -92(%ebp)
      movss %xmm0, -92(%ebp)
      movss %xmm1, -92(%ebp)

      mais effectivement, dès que tu remplaces les float par des long, a plus mmx...

      Pourtant, ça se case aussi facilement ça, non ?

      « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

      • [^] # Re: sse

        Posté par  . Évalué à 4.

        1) c'est pas du mmx c'est du SSE (mais c'est vrai qu'on s'en fout un peu ;)
        2) Je crois que le sse2 ou 3 permet d'utiliser du double précision dans les registres vectoriels, mais pas le sse (pas vraiment sûr)
        • [^] # Re: sse

          Posté par  (site web personnel) . Évalué à 2.

          effectivement, le sse3 permet d'utiliser du double précision

          « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

          • [^] # Re: sse

            Posté par  (site web personnel) . Évalué à 9.

            Le sse2 aussi. En résumé:
            - mmx : les vecteurs de 2 entiers 32 bits ou 4 entiers 16 bits ou 8 entiers 8 bits.
            - sse : les vecteurs de 4 float.
            - sse2 : sse + les vecteurs de deux doubles, de 2 entiers 64 bits ou 4 entiers 32 bits ou 8 entiers 16 bits etc.
            - sse3 : sse2 + quelques trucs "cosmétiques" en plus (des instructions qui sont plus "nombres complexes" friendly , l'addition des termes d'un vecteur,..)
            • [^] # Re: sse

              Posté par  . Évalué à 2.

              IIRC tout ca est explique sur wikipedia (version en surement plus complete).
  • # SIMD et Float

    Posté par  . Évalué à 1.

    Les instructions MMX c'est pas sur des entiers 8 bits ou 16bits ?
    • [^] # Re: SIMD et Float

      Posté par  (site web personnel) . Évalué à 3.

      Ca dépend des processeurs : 64 bits sur PII il me semble, 128 à partir de PIII, sachant que ce n'est qu'à partir du PIV qu'on dispose d'un bus 128 bits pour remplir en un seul coup les registres.

      « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

  • # RISC ou CISC ? Un nouveau troll ?

    Posté par  . Évalué à 0.


    ... elles sont vraiment tordues et pas simple du tout à manipuler pour un humain expérimenté, alors un compilo....


    Ce n'est peut-être pas pour rien que l'on a "inventé" les processeurs RISC.

    Mais il semble que le marché préfère les CISC !

    Pourquoi le marché sélectionne-t-il toujours les plus mauvaises solutions ? Témoin: windows !
    • [^] # Re: RISC ou CISC ? Un nouveau troll ?

      Posté par  . Évalué à 8.

      Le marché n'est pas un bon moyen d'optimiser quelque chose vers le "meilleur" car il sélectionne les solutions les moins chères localement.

      Ce qui pose deux problèmes :
      1) moins cher (ne va pas forcément vers la qualité) ;
      2) localement (on évolue vers le moindre coût le plus facile à atteindre... ce qui peut être très cher par rapport au moins cher global !).

      Snark
    • [^] # Re: RISC ou CISC ? Un nouveau troll ?

      Posté par  (site web personnel) . Évalué à 2.

      Le problème du Risc, c'est que la taille des instructions et de leurs opérandes sont fixés sur 32 bits.

      Donc quand on veut faire rentrer 32 bits dans un registre, mais que 8 sont pris par l'instruction load, il faut décaler, retourner la chercher, etc...

      « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

    • [^] # Re: RISC ou CISC ? Un nouveau troll ?

      Posté par  . Évalué à 8.

      Le combat RISC vs CISC est mort depuis longtemps et le RISC a gagné.
      Les processeurs ont "tous" un coeur RISC avec eventuellement un traducteur CISC -> RISC si l'ISA le necessite. Certains procs (nottement x86 modernes) permettent une certaine latitude dans le placement des instru grâce à des systèmes de réordennancement dynamique qui gèrent les dépendances. C'est quasiment indispensable pour éviter de ramer horriblement si on fait de la traduction vu qu'on a au final plus d'instru regroupées de manière non optimale étant données les différences de vitesses entre les divers bus et mémoires, et vu que les procs sont superscalaires.

      Aujourd'hui d'autres archi s'orientent vers plus d'intelligence du compilo et necessitent une gestion explicite du parrallélisme des pipelines par ce dernier.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.