Question

de GCC vecteur extensions offrent une belle façon raisonnable portable d'accéder à des instructions SIMD sur différents architectures matérielles sans avoir recours à (ou auto-vectorisation) .

Un cas réel d'utilisation, calcule une somme de contrôle simple additif. La seule chose qui ne sait pas comment charger des données en toute sécurité dans un vecteur.

typedef char v16qi __attribute__ ((vector_size(16)));

static uint8_t checksum(uint8_t *buf, size_t size)
{
    assert(size%16 == 0);
    uint8_t sum = 0;

    vec16qi vec = {0};
    for (size_t i=0; i<(size/16); i++)
    {
        // XXX: Yuck! Is there a better way?
        vec += *((v16qi*) buf+i*16);
    }

    // Sum up the vector
    sum = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5] + vec[6] + vec[7] + vec[8] + vec[9] + vec[10] + vec[11] + vec[12] + vec[13] + vec[14] + vec[15];

    return sum;
}

Castings un pointeur sur le type de vecteur semble fonctionner, mais je suis inquiet que cela pourrait exploser dans une horrible façon si le matériel SIMD attend les types de vecteurs à aligner correctement.

La seule autre option que j'ai pensé à utiliser est un vecteur temp et charger explicitement les valeurs (soit par une affectation memcpy ou élément par élément), mais à tester cette utilisation la plupart d'entre Contrer gagné speedup d'instructions SIMD. Idéalement, j'imagine que ce serait quelque chose comme une fonction générique __builtin_load(), mais aucun ne semble exister.

Quelle est une façon plus sûre des données de chargement dans un vecteur risque de problèmes d'alignement?

Était-ce utile?

La solution

Vous pouvez utiliser un initialiseur pour charger les valeurs, à savoir faire

const vec16qi e = { buf[0], buf[1], ... , buf[15] }

et l'espoir que GCC transforme ceci en une instruction de charge SSE. Je vérifie que, avec un dissassembler, bien ;-). En outre, pour une meilleure performance, vous essayez de faire aligner buf 16 octets et informer que le compilateur via un attribut aligned. Si vous ne pouvez pas garantir que le tampon d'entrée sera aligné, le traiter jusqu'à ce que vous avez par octet atteint un boundard de 16 octets.

Autres conseils

Modifier (merci Peter Cordes) Vous pouvez lancer des pointeurs:

typedef char v16qi __attribute__ ((vector_size (16), aligned (16)));

v16qi vec = *(v16qi*)&buf[i]; // load
*(v16qi*)(buf + i) = vec; // store whole vector

Cette compiles à vmovdqa à charge et vmovups pour stocker. Si les données ne sont pas connus pour être aligné, ensemble aligned (1) pour générer vmovdqu. ( Godbolt )

Notez qu'il existe également plusieurs fonctions intégrées à usage de spécial pour le chargement et le déchargement de ces registres ( Edit 2 ):

v16qi vec = _mm_loadu_si128((__m128i*)&buf[i]); // _mm_load_si128 for aligned
_mm_storeu_si128((__m128i*)&buf[i]), vec); // _mm_store_si128 for aligned

Il semble nécessaire d'utiliser -flax-vector-conversions pour aller de chars à v16qi avec cette fonction.

Voir aussi: C - Comment les éléments d'accès du vecteur en utilisant le vecteur SSE GCC l'extension
Voir aussi: ESS chargement ints en __m128

(Astuce:. La meilleure phrase Google est quelque chose comme "chargement gcc __m128i")

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top