AVX512似乎不提供以下功能:
__m512i _mm512_sign_epi16 (__m512i a, __m512i b)
它将很快可用还是有替代选择?
答案 0 :(得分:5)
如果不需要调零部分,则只需要2条指令(和调零寄存器)即可:
您可以_mm512_movepi16_mask()
将符号位放入掩码(pmovmskb
的AVX512版本)中,并进行从零开始的合并掩码减法,以基于另一个的符号取反向量。
#ifdef __AVX512BW__
// does *not* do anything special for signs[i] == 0, just negative / non-negative
__m512i conditional_negate(__m512i target, __m512i signs) {
__mmask32 negmask = _mm512_movepi16_mask(signs);
// vpsubw target{k1}, 0, target
__m512i neg = _mm512_mask_sub_epi16(target, negmask, _mm512_setzero_si512(), target);
return neg;
}
#endif
vector->掩码在Skylake-X(具有vpmovw2m
,vptestmw
或vpcmpw
上具有3个周期的延迟,但是使用该掩码仅具有1个周期的延迟。因此,从输入到输出的延迟为:
signs
-> SKX结果中target
开始1个周期->在SKX上得到结果(只是从零开始屏蔽的vpsubw
。)也要应用等零条件:您可以对向量执行的下一个操作零屏蔽或合并屏蔽,因此未使用的元素应为零
您需要进行额外的比较才能创建另一个蒙版,但是您可能不需要浪费第二条额外的说明来立即应用它。
如果您真的想以这种方式构建一个独立的vpsignw
,我们可以做最后的零掩码,但这是4个内在函数,可编译为4条指令,并且吞吐量可能比@wim的min差。 / max /相乘。但这具有良好的关键路径延迟,在SKX上总共大约有5个周期(如果可以将最终的掩模折叠成其他东西,则为4个周期)。关键路径是迹象->遮罩,然后是遮罩子。符号-> nonzeromask可以与任何一个并行运行。
__m512i mm512_psignw(__m512i target, __m512i signs) {
__mmask32 negmask = _mm512_movepi16_mask(signs);
// vpsubw target{negmask}, 0, target merge masking to only modify elements that need negating
__m512i neg = _mm512_mask_sub_epi16(target, negmask, _mm512_setzero_si512(), target);
__mmask32 nonzeromask = _mm512_test_epi16_mask(signs,signs); // per-element non-zero?
return _mm512_maskz_mov_epi16(nonzeromask, neg); // zero elements where signs was zero
}
可能的是,编译器可以将vmovdqu16
的零掩码{in1}折叠为add
/ or
/ xor
的合并掩码,或将乘法\ {{ 1}}。但是,自己动手做可能是个好主意。
答案 1 :(得分:4)
可能的解决方案是:
__m512i mm512_sign_epi16(__m512i a, __m512i b){
/* Emulate _mm512_sign_epi16() with instructions */
/* that exist in the AVX-512 instruction set */
b = _mm512_min_epi16(b, _mm512_set1_epi16(1)); /* clamp b between -1 and 1 */
b = _mm512_max_epi16(b, _mm512_set1_epi16(-1)); /* now b = -1, 0 or 1 */
a = _mm512_mullo_epi16(a, b); /* apply the sign of b to a */
return a;
}
此解决方案应具有合理的吞吐量,但由于整数乘法,延迟可能不是最佳的。 Peter Cordes' solution是一个很好的选择,它具有更好的延迟。 但是实际上,高吞吐量通常比低延迟更受关注。
无论如何,不同替代方案(此处的解决方案,彼得·科德斯的答案以及chtz' comment中的拆分思路)的实际性能取决于周围的代码和执行指令的CPU类型。您必须对其他选择进行基准测试,以查看在您的特定情况下哪种选择最快。