在 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 内在函数?的主要内容,如果未能解决你的问题,请参考以下文章

Erlang 问题

JSON - 是不是有任何等效的 XML CDATA?

Azure Synapse 专用 SQL 池中的“sp_refreshview”是不是有任何等效项

对于 std::tr1::unordered_map,是不是有任何等效的 std::algorithm 类似于 std::map::lower_bound?

Java 8流限制功能是否有任何等效的Kotlin函数[重复]

Scala 相当于 wsdl2java?