2010-10-21 19 views
3

J'essaye d'optimiser une fonction en utilisant SSE2. Je me demande si je peux mieux préparer les données pour mon code d'assemblage de cette façon. Mes données source sont un ensemble de caractères non signés provenant de pSrcData. Je le copie dans ce tableau de flottants, car mon calcul doit se faire en float.Conversion de chars non signés en float en assembly (pour préparer les calculs vectoriels flottants)


unsigned char *pSrcData = GetSourceDataPointer(); 

__declspec(align(16)) float vVectX[4]; 

vVectX[0] = (float)pSrcData[0]; 
vVectX[1] = (float)pSrcData[2]; 
vVectX[2] = (float)pSrcData[4]; 
vVectX[3] = (float)pSrcData[6]; 

__asm 
{ 
    movaps xmm0, [vVectX] 
    [...] // do some floating point calculations on float vectors using addps, mulps, etc 
} 

est-il un moyen plus rapide pour moi de jeter tous les octets de pSrcData à un flotteur et le stocker dans vVectX?

Merci!

Répondre

5

(1) et avec un masque de mettre à zéro les octets impairs (PAND)

(2) Décompresser de 16 bits à 32 bits (PUNPCKLWD avec un vecteur zéro)

(3) Autre 32 bits à flots (CVTDQ2PS)

Trois instructions.

1

Super vieux fil Je me rends compte, mais je cherchais moi-même le code pour le faire. Ceci est ma solution, que je pense est plus simple:

#include <immintrin.h> 
#include <stdint.h> 

#ifdef __AVX__ 
// Modified from http://stackoverflow.com/questions/16031149/speedup-a-short-to-float-cast 
// Convert unsigned 8 bit integer to float. Length must be multiple of 8 
int avxu8tof32(uint8_t *src, float *dest, int length) { 
    int i; 

    for (i=0; i<length; i+= 8) { 

    // Load 8 8-bit int into the low half of a 128 register 
    __m128i v = _mm_loadl_epi64 ((__m128i const*)(src+i)); 

    // Convert to 32-bit integers 
    __m256i v32 = _mm256_cvtepu8_epi32(v); 

    // Convert to float 
    __m256 vf = _mm256_cvtepi32_ps (v32); 

    // Store 
    _mm256_store_ps(dest + i,vf); 
    } 
    return(0); 
} 
#endif 

Cependant l'analyse comparative montre qu'il ne plus rapide qu'un simple boucle sur le tableau en C, avec l'optimisation du compilateur est activée. Peut-être que l'approche sera plus utile en tant qu'étape initiale d'un tas de calculs AVX.

+0

L'OP ne veut que tous les * autres * 'uint8_t' comme' float'. Avec AVX2, le meilleur est probablement un '__m128i'' _mm_and_si128' et ensuite '_mm256_cvtepu16_epi32'. Ou si vous allez plus tard emballer dans 'uint8_t', peut-être un 256b' and' et décompresser lo/hi (contre zéro) dans la voie pour aller de 16b à 32b éléments entiers avant la conversion en FP. Cela évite tout mélange aléatoire (comme 'vpmovzx ymm'), et évite d'avoir besoin du shuffle inversé pour l'emballage. –

+0

Et oui, vous voudriez le faire à la volée avant quelque chose que vous avez manuellement vectorisé. Les compilateurs peuvent auto-vectoriser des boucles simples de copie + conversion. –

+0

Merci Peter - Je l'ai manqué entièrement – Chris