2015-11-26 6 views
2

Je voudrais fusionner tous les éléments dans un __vector bool long long en un seul int, dans lequel chaque bit est réglé sur le bit le plus significatif du vecteur d'entréeSur Powerpc, y a-t-il un équivalent des éléments intrinsèques de movelask d'intel?

exemple:

__vector bool long long vcmp = vec_cmplt(a, b); 
int packedmask = /*SOME FUNCTION GOES HERE*/ (vcmp); 

avec

packedmask = x|y|0000000000000000.... 

où x est égal à 1 si VCMD [0] = 0 0xFFFFF ... ou si VCMP [0] = 0; même pour y.

Sur intel, nous pouvons le faire en utilisant des instructions _mm_movemask (intrinsic for intel)

Est-il possible de faire la même chose sur PowerPC?

Merci pour toute aide

Répondre

2

Sons comme l'instruction vbpermq (et vec_vbpermq() intrinsèque) serait approprié ici. Étant donné un vecteur d'indices "char" non signés (c'est-à-dire, 0 - 128), il utilise ces index pour sélectionner un bit dans un vecteur de sortie. Si l'index est supérieur à 128, un bit zéro est utilisé à la place.

Les 16 bits résultants sont mis à zéro pour former une valeur de 64 bits dans le premier double mot du vecteur résultat.

Quelque chose comme cela pourrait fonctionner:

/* 
* our permutation indicies: the MSbit from the first bool long long, 
* then the MSbit from the second bool long long, then the rest as 
* >=128 (which gives a zero bit in the result vector) 
*/ 
vector unsigned char perm = { 0, 64, 128, 128, 128, /*...*/}; 

/* compare the two-item vector into two bools */ 
vcmp = (vector unsigned char)vec_cmplt(a, b); 

/* select a bit from each of the result bools */ 
result = vec_vbpermq(vcmp, perm); 

Obtenir le int hors du vecteur de résultat dépendra de ce que vous voulez faire. Si vous en avez besoin, un vec_extract(result, 0) peut fonctionner, mais puisque vous êtes uniquement intéressé par les deux premiers bits du résultat, vous pouvez peut-être simplifier la constante perm et/ou déplacer le résultat selon les besoins.

En outre, soyez conscient des considérations endian de votre résultat.

vbpermq est décrite à la section 5.15 du PowerISA.

+0

merci beaucoup Jeremy. Exactement ce dont j'ai besoin. –

3

Vous pouvez essayer quelque chose comme ceci:

typedef __vector uint8_t v128_u8; 
typedef __vector uint32_t v128_u32; 

const v128_u8 KS = {1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128}; 
const v128_u8 K0 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
const v128_u8 K1 = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 
//const v128_u8 KP = {0, 8, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};//little endian 
const v128_u8 KP = {3, 11, 7, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};//big-endian 

unit Tmp 
{ 
    uint32_t u32; 
    uint16_t u16[2]; 
}; 

uint16_t vec_movemask(v128_u8 value) 
{ 
    Tmp tmp 
    tmp.u32 = vec_extract(vec_perm(vec_msum(vec_and(value, KS), K1, K0), KP), 0); 
    return tmp.u16[0] + tmp.u16[2]; 
} 

détaillée:

value: 
{0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff , 0x00, 0xff, 0x00, 0xff}; 
vec_and(value, KS): 
{0x00, 0x02, 0x00, 0x00, 0x10, 0x20, 0x00, 0x80, 0x00, 0x00, 0x04, 0x08 , 0x00, 0x20, 0x00, 0x80}; 
vec_msum(vec_and(value, KS), K1, K0): 
{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x0C , 0x00, 0x00, 0x00, 0xA0}; 
vec_perm(vec_msum(vec_and(value, KS), K1, K0): 
{0x02, 0x0C, 0xB0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00}; 
vec_extract(vec_perm(vec_msum(vec_and(value, KS), K1, K0): 
{0x02, 0x0C, 0xB0, 0xA0} 
tmp.u16[0] + tmp.u16[2]: 
{0xB2, 0xAC} 
+0

whoa. Merci. Mais je suppose que je vais rester avec le code scalaire s'il n'y a pas moins d'instructions/constantes. –

+3

Power7/8 dispose de 64 registres vectoriels. Les vecteurs constants seront dans les registres s'ils seront utilisés souvent. – ErmIg