5 votes

Existe-t-il un moyen de soustraire des mots doubles non signés emballés, saturés, sur x86, en utilisant MMX/SSE ?

Je me suis penché sur MMX/SSE et je me pose des questions. Il existe des instructions pour la soustraction emballée et saturée d'octets et de mots non signés, mais pas de mots doubles.

Existe-t-il un moyen de faire ce que je veux, ou sinon, pourquoi n'y en a-t-il pas ?

3voto

chtz Points 6357

Si vous disposez de SSE4.1, je ne pense pas qu'il soit possible de faire mieux que d'utiliser la fonction pmaxud + psubd approche suggérée par @harold. Avec AVX2, vous pouvez bien sûr aussi utiliser les variantes 256 bits correspondantes.

__m128i subs_epu32_sse4(__m128i a, __m128i b){
    __m128i mx = _mm_max_epu32(a,b);
    return _mm_sub_epi32(mx, b);
}

Sans SSE4.1, vous devez comparer les deux arguments d'une manière ou d'une autre. Malheureusement, il n'y a pas de epu32 (pas avant AVX512), mais vous pouvez en simuler une en ajoutant d'abord 0x80000000 (ce qui est équivalent à un xor-ing dans ce cas) aux deux arguments :

__m128i cmpgt_epu32(__m128i a, __m128i b) {
    const __m128i highest = _mm_set1_epi32(0x80000000);
    return _mm_cmpgt_epi32(_mm_xor_si128(a,highest),_mm_xor_si128(b,highest));
}

__m128i subs_epu32(__m128i a, __m128i b){
    __m128i not_saturated = cmpgt_epu32(a,b);
    return _mm_and_si128(not_saturated, _mm_sub_epi32(a,b));
}

Dans certains cas, il pourrait Il serait préférable de remplacer la comparaison par un embrouillage du bit le plus élevé et de le diffuser à chaque bit à l'aide d'un décalage (ce qui remplace un pcmpgtd et de trois opérations bit-logiques (et de devoir charger 0x80000000 au moins une fois) par un psrad et cinq opérations bit-logiques) :

__m128i subs_epu32_(__m128i a, __m128i b) {
    __m128i r = _mm_sub_epi32(a,b);
    __m128i c = (~a & b) | (r & ~(a^b)); // works with gcc/clang. Replace by corresponding intrinsics, if necessary (note that `andnot` is a single instruction)
    return _mm_srai_epi32(c,31) & r;
}

Godbolt-Link, comprenant également adds_epu32 variantes : https://godbolt.org/z/n4qaW1 Étrangement, clang a besoin de plus de copies de registre que gcc pour les variantes non-SSE4.1. D'autre part, clang trouve le pmaxud l'optimisation pour le cmpgt_epu32 lorsqu'il est compilé avec SSE4.1 : https://godbolt.org/z/3o5KCm

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X