在 Powerpc 上,是否有任何与英特尔的 movemask 内在函数等效的东西?
On Powerpc, is there any equivalent of intel's movemask intrinsics?
我想将 __vector bool long long 中的所有元素合并为一个 int,其中每个位都设置为输入向量的最高有效位
示例:
__vector bool long long vcmp = vec_cmplt(a, b);
int packedmask = /*SOME FUNCTION GOES HERE*/ (vcmp);
和
packedmask = x|y|0000000000000000....
其中,如果 vcmd[0] = 0XFFFFF...,则 x 等于 1,如果 vcmp[0] = 0,则 x 等于 0;
y 也一样。
在intel上,我们可以使用_mm_movemask指令(intrinsic for intel)
来实现
有什么方法可以在 PowerPC 上做同样的事情吗?
感谢您的帮助
您可以尝试这样的操作:
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];
}
详细:
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}
听起来 vbpermq
指令(和 vec_vbpermq()
内在指令)在这里很合适。给定一个 unsigned char "indicies" 向量(即 0 - 128),它使用这些索引 select 位到输出向量中。如果索引大于 128,则使用零位代替。
16 个结果位被零扩展以在结果向量的第一个双字中形成一个 64 位值。
类似这样的方法可行:
/*
* 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);
从结果向量中获取 int
将取决于您要用它做什么。如果您按原样需要它,vec_extract(result, 0)
可能会起作用,但由于您只对结果的前两位感兴趣,因此您可以简化 perm 常量,and/or 移动结果视情况而定。
此外,请注意您的结果的字节序考虑因素。
vbpermq
在 PowerISA 的第 5.15 节中有描述。
我想将 __vector bool long long 中的所有元素合并为一个 int,其中每个位都设置为输入向量的最高有效位
示例:
__vector bool long long vcmp = vec_cmplt(a, b);
int packedmask = /*SOME FUNCTION GOES HERE*/ (vcmp);
和
packedmask = x|y|0000000000000000....
其中,如果 vcmd[0] = 0XFFFFF...,则 x 等于 1,如果 vcmp[0] = 0,则 x 等于 0; y 也一样。
在intel上,我们可以使用_mm_movemask指令(intrinsic for intel)
来实现有什么方法可以在 PowerPC 上做同样的事情吗?
感谢您的帮助
您可以尝试这样的操作:
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];
}
详细:
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}
听起来 vbpermq
指令(和 vec_vbpermq()
内在指令)在这里很合适。给定一个 unsigned char "indicies" 向量(即 0 - 128),它使用这些索引 select 位到输出向量中。如果索引大于 128,则使用零位代替。
16 个结果位被零扩展以在结果向量的第一个双字中形成一个 64 位值。
类似这样的方法可行:
/*
* 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);
从结果向量中获取 int
将取决于您要用它做什么。如果您按原样需要它,vec_extract(result, 0)
可能会起作用,但由于您只对结果的前两位感兴趣,因此您可以简化 perm 常量,and/or 移动结果视情况而定。
此外,请注意您的结果的字节序考虑因素。
vbpermq
在 PowerISA 的第 5.15 节中有描述。