2017-04-30 11 views
8

Que pouvez-vous faire avec SSE4.1 ptest autre que de tester si un seul registre est tout à zéro? Pouvez-vous utiliser une combinaison de SF et CF pour tester quelque chose d'utile sur deux registres d'entrée inconnus?PTEST peut-il être utilisé pour tester si deux registres sont à la fois zéro ou une autre condition?

À quoi sert PTEST? On pourrait penser qu'il serait bon de vérifier le résultat d'une comparaison emballés (comme PCMPEQD ou CMPP), mais au moins sur les processeurs Intel, it costs more uops to compare-and-branch using PTEST + JCC than with PMOVMSK(B/PS/PD) + macro-fused CMP+JCC.

Voir aussi Checking if TWO SSE registers are not both zero without destroying them

Répondre

5

Non, à moins que je suis absent Quelque chose d'intelligent, ptest avec deux registres inconnus n'est généralement pas utile pour vérifier certaines propriétés sur les deux. (Autre que des choses évidentes que vous auriez déjà besoin d'un bit-AND pour, comme l'intersection entre deux bitmaps).

Pour tester deux registres pour les deux étant tout à zéro, OU les ensemble et PTEST que contre lui-même.


ptest xmm0, xmm1 produit deux résultats:

  • ZF = est xmm0 & xmm1 tout à zéro?
  • CF = est (~xmm0) & xmm1 tout-zéro?

Si le deuxième vecteur est entièrement nul, les indicateurs ne dépendent pas du tout des bits du premier vecteur.

Il peut être utile de considérer les vérifications "tout-zéro" comme NOT(bitwise horizontal-OR()) des résultats AND et ANDNOT. Mais probablement pas, parce que c'est trop d'étapes pour que mon cerveau puisse y réfléchir facilement. Cette séquence de AND vertical et d'OR-OU peut-être plus facile à comprendre pourquoi PTEST ne vous en dit pas beaucoup sur une combinaison de deux registres inconnus, tout comme l'instruction TEST entière.

Voici une table de vérité pour un ptest a,mask à 2 bits. Espérons que cela aide à penser à des mélanges de zéros et de zéros avec des entrées 128b.

Notez que CF(a,mask) == ZF(~a,mask).

a mask  ZF CF 
00 00  1  1 
01 00  1  1 
10 00  1  1 
11 00  1  1 

00 01  1  0 
01 01  0  1 
10 01  1  0 
11 01  0  1 

00 10  1  0 
01 10  1  0 
10 10  0  1 
11 10  0  1 

00 11  1  0 
01 11  0  0 
10 11  0  0 
11 11  0  1 

Intel's intrinsics guide lists 2 interesting intrinsics for it. Notez le nom des arguments: a et mask sont un indice qu'ils vous disent sur les parties de a sélectionnés par un masque AND connu.

  • _mm_test_mix_ones_zeros (__m128i a, __m128i mask): retourne (ZF == 0 && CF == 0)
  • _mm_test_all_zeros (__m128i a, __m128i mask): retourne ZF

Il y a aussi les versions plus simplement nommées:

  • int _mm_testc_si128 (__m128i a, __m128i b): retourne CF
  • int _mm_testnzc_si128 (__m128i a, __m128i b): retour s (ZF == 0 && CF == 0)
  • int _mm_testz_si128 (__m128i a, __m128i b): retourne ZF

Il y a AVX2 __m256i versions de ces intrinsics, mais le guide répertorie uniquement les all_zeros et mix_ones_zeros des versions noms pour __m128i opérandes.

Si vous voulez tester une autre condition de C ou C++, vous devez utiliser testc et testz avec les mêmes opérandes, et nous espérons que votre compilateur se rend compte qu'il n'a besoin que de faire un PTEST, et je l'espère même utiliser un seul JCC , SETCC ou CMOVCC pour implémenter votre logique. (Je vous recommande de vérifier l'asm, au moins pour le compilateur le plus pour vous.)


Notez que _mm_testz_si128(v, set1(0xff)) est toujours le même que _mm_testz_si128(v,v), parce que c'est et comment fonctionne. Mais ce n'est pas vrai pour le résultat des FC.

Vous pouvez vérifier un vecteur étant tous-les utilisant

bool is_all_ones = _mm_testc_si128(v, _mm_set1_epi8(0xff)); 

Ceci est probablement pas plus rapide, mais plus petite taille du code, qu'un PCMPEQB contre un vecteur de tous-les, puis l'habituel movemask + cmp. Cela n'évite pas la nécessité d'une constante vectorielle. PTEST présente l'avantage de ne détruire aucun opérande d'entrée, même sans AVX.