这是我的想象,还是SSE和AVX遗失的PNOT
指令?也就是说,一个翻转向量中每一位的指令。
如果是,是否有更好的方法来模拟它而不是PXOR
的向量为全1?非常烦人,因为我需要设置所有1的向量来使用该方法。
答案 0 :(得分:9)
对于这样的情况,看看编译器会产生什么是有益的。
E.g。对于以下功能:
#include <immintrin.h>
__m256i test(const __m256i v)
{
return ~v;
}
gcc和clang似乎generate much the same code:
test(long long __vector(4)):
vpcmpeqd ymm1, ymm1, ymm1
vpxor ymm0, ymm0, ymm1
ret
答案 1 :(得分:4)
如果使用Intrinsics,您可以使用这样的内联函数来单独执行not操作。
var widgetIframe = document.getElementById("soundcloud"),
widget = SC.Widget(widgetIframe);
widget.bind(SC.Widget.Events.FINISH, function() {
widget.play();
});
答案 2 :(得分:3)
您可以使用PANDN
OpCode。
PANDN
实现了操作
DEST = NOT(DEST) AND SRC ; (SSEx)
或
DEST = NOT(SRC1) AND SRC2 ; (AVXx)
将此操作与全1矢量结合使用可有效地导致 PNOT 操作。
某些x86(SSEx)汇编代码如下所示:
; XMM0 is input register
PCMPEQB xmm1, xmm1 ; Whole xmm1 reg set to 1's
PANDN xmm0, xmm1 ; xmm0 = NOT(xmm0) AND xmm1
; XMM0 contains NOT(XMM0)
某些x86(AVXx)汇编代码如下所示:
; YMM0 is input register
VPCMPEQB ymm1, ymm1, ymm1 ; Whole ymm1 reg set to 1's
VPANDN ymm0, ymm0, ymm1 ; ymm0 = NOT(ymm0) AND ymm1
; YMM0 contains NOT(YMM0)
两者都可以(当然)很容易地被翻译成内在函数。
答案 3 :(得分:2)
AVX512F vpternlogd
/ _mm512_ternarylogic_epi32(__m512i a, __m512i b, __m512i c, int imm8)
最后提供了一种实现NOT的方法,没有任何额外的常量,使用单个指令(Skylake-avx512和KNL上每个时钟吞吐量为2,所以它&# 39;对于256b和更小的向量,它不如PXOR / XORPS好。)
vpternlogd zmm,zmm,zmm, imm8
有3个输入向量和一个输出,修改目的地。通过正确的直接,您仍然可以将copy-and-NOT实现到不同的寄存器中,但它会有一个&#34; false&#34;依赖于输出寄存器(vpxord dst, src, all-ones
不会有)。
TL:DR:可能仍然使用xor和all-one作为循环的一部分,除非你的寄存器用完了。如果稍后需要输入,vpternlog
可能需要额外的vmovdqa
寄存器复制指令。在循环之外,vpternlogd zmm,zmm,zmm, 0xff
为the compiler's best option for creating a 512b vector of all-ones in the first place,因为AVX512将指令与掩码(k0-k7
)进行比较,因此与all-1的XOR可能已经涉及vpternlogd
,或者可能是来自记忆的广播常数。
对于每个位位置i
,输出位为imm[ (DEST[i]<<2) + (SRC1[i]<<1) + SRC2[i]]
,其中imm8
被视为8元素位图。
因此,如果我们希望结果仅依赖于SRC2(zmm/m512/m32bcst
操作数),我们应该选择重复1,0的位图,偶数位置1
(选中) src2=0
)。
vpternlogd zmm1, zmm2,zmm2, 01010101b ; 0x55
如果您很幸运,编译器会为您优化_mm512_xor_epi32(v, set1(-1))
至vpternlogd
,如果它有利可图。
// To hand-hold a compiler into saving a vmovdqa32 if needed:
__m512i tmp = something earlier;
__m512i t2 = _mm...(tmp);
// use-case: tmp is dead, t2 and ~t2 are both needed.
__m512i t2_inv = _mm512_ternarylogic_epi32(tmp, t2, t2, 0b01010101);
如果您不确定这是一个好主意,请保持简单并为所有3个输入使用相同的变量:
__m512i t2_inv = _mm512_ternarylogic_epi32(t2, t2, t2, 0b01010101);