在 Powerpc 上,是不是有任何等效于英特尔的 movemask 内在函数?
Posted
技术标签:
【中文标题】在 Powerpc 上,是不是有任何等效于英特尔的 movemask 内在函数?【英文标题】:On Powerpc, is there any equivalent of intel's movemask intrinsics?在 Powerpc 上,是否有任何等效于英特尔的 movemask 内在函数? 【发布时间】:2015-11-26 12:20:18 【问题描述】:我想将 __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....
其中 x 等于 1 如果 vcmd[0] = 0XFFFFF... 或 0 如果 vcmp[0] = 0; y 也一样。
在 intel 上,我们可以使用 _mm_movemask 指令来实现这一点 (intrinsic for intel)
有没有办法在 PowerPC 上做同样的事情?
感谢您的帮助
【问题讨论】:
【参考方案1】:你可以试试这样的:
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
【讨论】:
哇。谢谢。但我想如果不涉及更少的指令/常量,我会继续使用标量代码。 Power7/8 有 64 个向量寄存器。如果经常使用常量向量,它们将在寄存器中。【参考方案2】:听起来像 vbpermq
指令(和 vec_vbpermq()
内在)在这里是合适的。给定一个无符号字符“索引”向量(即 0 - 128),它使用这些索引将位选择到输出向量中。如果索引大于 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 常量,和/或根据需要移动结果。
另外,请注意您的结果的字节序考虑。
vbpermq
在 PowerISA 的第 5.15 节中进行了描述。
【讨论】:
以上是关于在 Powerpc 上,是不是有任何等效于英特尔的 movemask 内在函数?的主要内容,如果未能解决你的问题,请参考以下文章
Azure Synapse 专用 SQL 池中的“sp_refreshview”是不是有任何等效项
对于 std::tr1::unordered_map,是不是有任何等效的 std::algorithm 类似于 std::map::lower_bound?