2010-07-28 5 views
2

De nombreuses instructions SSE permettent à l'opérande de source d'être une adresse de mémoire alignée de 16 octets. Par exemple, les différentes instructions (un) pack. PUNCKLBW a la signature suivante:SSE2 intrinsics: accès direct à la mémoire

PUNPCKLBW XMM1, XMM2/M128

Maintenant, cela ne semble pas être possible du tout avec intrinsics. Il semble qu'il soit obligatoire d'utiliser les intrinsèques _mm_load * pour lire quoi que ce soit en mémoire. Ceci est l'intrinsèque pour PUNPCKLBW:

__m128i _mm_unpacklo_epi8 (__m128i a, __m128i b);

(Pour autant que je sache, le type de __m128i se réfère toujours à un registre XMM.)

Maintenant, pourquoi est-ce? C'est plutôt triste puisque je vois un certain potentiel d'optimisation en adressant la mémoire directement ...

Répondre

6

Les intrinsèques correspondent relativement directement aux instructions réelles, mais les compilateurs ne sont pas obligés d'émettre les instructions correspondantes. L'optimisation d'une charge suivie d'une opération (même lorsqu'elle est écrite en intrinsèques) dans la forme mémoire de l'opération est une optimisation commune effectuée par tous les compilateurs respectables lorsque cela est avantageux.

TLDR: écrit la charge et l'opération dans intrinsics, et laisse le compilateur l'optimiser.

Edit: exemple trivial:

#include <emmintrin.h> 
__m128i foo(__m128i *addr) { 
    __m128i a = _mm_load_si128(addr); 
    __m128i b = _mm_load_si128(addr + 1); 
    return _mm_unpacklo_epi8(a, b); 
} 

avec gcc -Os -fomit-frame-pointer donne Compiler:

_foo: 
movdqa  (%rdi), %xmm0 
punpcklbw 16(%rdi), %xmm0 
retq 

Voir? L'optimiseur va le trier.

+0

Je ne me plaindrais pas si le compilateur l'optimisait, mais au moins clang et gcc ne le font pas. C'est facile à vérifier avec l'option -S. Je trouve des traductions verbatim intrinsics -> assembly pour presque n'importe quel intrinsèque et peut mapper des registres directement aux variables. On dirait que ces compilateurs optimisent difficilement le code intrinsèque SIMD ... – dietr

+1

@dietr: clang et gcc font tous deux cette optimisation, comme vous pouvez le voir dans mon exemple. Construisez-vous avec l'optimisation désactivée? Essayez d'utiliser '-O1' ou plus. –

+0

J'utilise -O2. Je suppose que gcc/clang ne voit tout simplement aucun potentiel d'optimisation dans mon morceau de code ... – dietr

3

Vous pouvez simplement utiliser vos valeurs de mémoire directement. Par exemple:

__m128i *p=static_cast<__m128i *>(_aligned_malloc(8*4,16)); 

for(int i=0;i<32;++i) 
    reinterpret_cast<unsigned char *>(p)[i]=static_cast<unsigned char>(i); 

__m128i xyz=_mm_unpackhi_epi8(p[0],p[1]); 

La partie intéressante du résultat:

; __m128i xyz=_mm_unpackhi_epi8(p[0],p[1]); 
0040BC1B 66 0F 6F 00  movdqa  xmm0,xmmword ptr [eax] 
0040BC1F 66 0F 6F 48 10 movdqa  xmm1,xmmword ptr [eax+10h] 
0040BC24 66 0F 68 C1  punpckhbw xmm0,xmm1 
0040BC28 66 0F 7F 04 24 movdqa  xmmword ptr [esp],xmm0 

Ainsi, le compilateur fait un peu d'un mauvais travail - ou peut-être de cette façon est plus rapide et/ou jouer avec les options Cela corrige cela - mais il génère du code qui fonctionne, et le code C++ indique ce qu'il veut assez directement.

Questions connexes