Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 03/10/2011, à 19:39

ehmicky

[Résolu][C]Compiler du code SSE1/SSE2

Bonjour à tous,

J'essaye de savoir comment faire en sorte que le compilateur produise des instructions MMX, SSE1 ou SSE2. J'ai essayé avec "gcc -O2 -mtune=native -mmmx -msse -msse2" avec un code qui me semble propice :

typedef struct Pack
{
    char u, d, t, q, c, s, z, h;
} Pack;

Pack Multi(Pack MonPack, int Facteur)
{
    MonPack.u += Facteur;
    MonPack.d += Facteur;
    MonPack.t += Facteur;
    MonPack.q += Facteur;
    MonPack.c += Facteur;
    MonPack.s += Facteur;
    MonPack.z += Facteur;
    MonPack.h += Facteur;
    return MonPack;
};

int main(void)
{
    return 0;    
}

mais je n'obtiens que des instructions x86 "classiques" :

$ gcc -Wall -Wextra -O2 -mtune=native -mmmx -msse -msse2 b.c && gdb -ex "disas Multi" -ex "quit" a.out
Reading symbols from /home/ether/a/ASM/a.out...(no debugging symbols found)...done.
Dump of assembler code for function Multi:
   0x080483a0 <+0>:    push   ebp
   0x080483a1 <+1>:    mov    ebp,esp
   0x080483a3 <+3>:    lea    esp,[esp-0xc]
   0x080483a7 <+7>:    mov    DWORD PTR [esp+0x4],esi
   0x080483ab <+11>:    mov    DWORD PTR [esp],ebx
   0x080483ae <+14>:    mov    DWORD PTR [esp+0x8],edi
   0x080483b2 <+18>:    mov    eax,DWORD PTR [ebp+0x8]
   0x080483b5 <+21>:    mov    ecx,DWORD PTR [ebp+0xc]
   0x080483b8 <+24>:    movzx  edx,BYTE PTR [ebp+0x14]
   0x080483bc <+28>:    movsx  esi,ch
   0x080483bf <+31>:    add    edx,esi
   0x080483c1 <+33>:    mov    esi,ecx
   0x080483c3 <+35>:    shr    esi,0x10
   0x080483c6 <+38>:    mov    ebx,DWORD PTR [ebp+0x10]
   0x080483c9 <+41>:    mov    BYTE PTR [eax+0x1],dl
   0x080483cc <+44>:    movzx  edx,BYTE PTR [ebp+0x14]
   0x080483d0 <+48>:    add    edx,esi
   0x080483d2 <+50>:    mov    esi,ecx
   0x080483d4 <+52>:    mov    BYTE PTR [eax+0x2],dl
   0x080483d7 <+55>:    sar    esi,0x18
   0x080483da <+58>:    movzx  edx,BYTE PTR [ebp+0x14]
   0x080483de <+62>:    add    edx,esi
   0x080483e0 <+64>:    movsx  esi,bh
   0x080483e3 <+67>:    mov    BYTE PTR [eax+0x3],dl
   0x080483e6 <+70>:    movzx  edx,BYTE PTR [ebp+0x14]
   0x080483ea <+74>:    lea    edi,[edx+ebx*1]
   0x080483ed <+77>:    add    edx,esi
   0x080483ef <+79>:    mov    esi,ebx
   0x080483f1 <+81>:    mov    BYTE PTR [eax+0x5],dl
   0x080483f4 <+84>:    shr    esi,0x10
   0x080483f7 <+87>:    movzx  edx,BYTE PTR [ebp+0x14]
   0x080483fb <+91>:    sar    ebx,0x18
   0x080483fe <+94>:    add    esi,edx
   0x08048400 <+96>:    add    ebx,edx
   0x08048402 <+98>:    add    edx,ecx
   0x08048404 <+100>:    mov    BYTE PTR [eax],dl
   0x08048406 <+102>:    mov    edx,edi
   0x08048408 <+104>:    mov    BYTE PTR [eax+0x4],dl
   0x0804840b <+107>:    mov    edx,esi
   0x0804840d <+109>:    mov    BYTE PTR [eax+0x6],dl
   0x08048410 <+112>:    mov    BYTE PTR [eax+0x7],bl
   0x08048413 <+115>:    mov    ebx,DWORD PTR [esp]
   0x08048416 <+118>:    mov    esi,DWORD PTR [esp+0x4]
   0x0804841a <+122>:    mov    edi,DWORD PTR [esp+0x8]
   0x0804841e <+126>:    mov    esp,ebp
   0x08048420 <+128>:    pop    ebp
   0x08048421 <+129>:    ret    0x4
End of assembler dump.

Mon CPU est un Intel Atom, sur un OS 32 bits, et supportent MMX/SSE1/SSE2 :

$ cat /proc/version
Linux version 2.6.38-11-generic (buildd@rothera) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) ) #48-Ubuntu SMP Fri Jul 29 19:05:14 UTC 2011
$ cat /proc/cpuinfo | grep flags
flags        : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm movbe lahf_lm dts

J'ai vu par ailleurs que l'on pouvaient utiliser des types spéciaux genre "__m128" pour faire comprendre au compilateur qu'il fallait faire une optimisation vectorielle.
Je me demande donc :
  1) est-ce que l'on est obligé d'utiliser ces types pour obtenir des instructions SSE à l'heure actuelle, ou est-il possible de faire en sorte (via des flags, des #define, etc.) que le compilateur optimise de lui-même ?
  2) sinon, quelles techniques et types utiliser, dans la mesure où je suis obligé de produire du code multi-compilateur (puisqu'il s'agit d'une bibliothèque), et donc cela m'embête un peu d'utilise une suite de #ifdef pour adapter en fonction du compilateur (mais bon, c'est peut-être la seule solution !)
  3) je peux utiliser cpuid à l'échelle de l'assembleur pour checker le support des SSE sur un CPU x86, mais j'aimerais le faire à un plus haut niveau en C, et de manière portable (pas spécifique à GNU/Linux par exemple) : comment faire ?

Merci beaucoup !

Dernière modification par ehmicky (Le 05/10/2011, à 03:11)


Stego++, bibliothèque libre de stéganographie (avec cryptographie), à venir !
Besoin de votre aide :
Stats sur les compilateurs C++ les plus utilisés
Comment utiliser les archetypes C++ ?

Hors ligne

#2 Le 03/10/2011, à 23:20

Uda

Re : [Résolu][C]Compiler du code SSE1/SSE2

D'après ce que j'ai comrpis, il y a 3 manière d'obtenir des instruction SIMD avec GCC
1) Utiliser les includes *mmintrin.h qui contiennent des instructions spécifiques pour la plateforme x86.
Cela oblige obligatoirement a compiler pour une archi spécifique mais a l'avantage d'être portable entre compilateur (celui du micrososft et d'intel au moins). Mais, tu peux pas les utiliser pour une autre architecture.
2) Utiliser l'extension GCC de vector instructions
C'est un jeu restreint d'instruction SIMD mais qui fonctionne sur d'autre archi qu'intel (A vérifier mais je crois qu'il y a une implémentation software si cela existe pas sur l'archi cible). Du coup ton code est un peu plus portable d'un point de vue architecture mais t'oblige a utiliser GCC.
3) L'auto-Vertorisation des boucles:
Là c'est fait automatiquement par GCC lorsqu'il rencontre certain type de boucle.
Par exemple avec ton exemple, il faudrait que Pack soit définie sous forme de tableau et que tu remplace ta fonction par une boucle qui parcours le tableau. GCC devrait pouvoir automatiquement générer des instruction SIMD si tu compile pour une archi qui le support.

Hors ligne

#3 Le 05/10/2011, à 03:10

ehmicky

Re : [Résolu][C]Compiler du code SSE1/SSE2

Salut,

Merci beaucoup pour ton aide.
Je pense donc que je vais pencher pour cette solution :
  - ou utiliser des bibliothèques compilant avec des SIMD (peu importe la méthode utilisée par le créateur de la bibliothèque) pour la manipulation d'images/sons/vidéo
  - ou, si les bibliothèques ne suffisent pas, utiliser les headers <*mmintrin.h>. Cela ne sera disponible que sur x86, le reste sera compilé avec des instructions non-SIMD, mais cela restera dispo sur les principaux compilateurs, et je n'ai pas non plus envie de me prendre trop la tête en maintenance.

Merci !


Stego++, bibliothèque libre de stéganographie (avec cryptographie), à venir !
Besoin de votre aide :
Stats sur les compilateurs C++ les plus utilisés
Comment utiliser les archetypes C++ ?

Hors ligne