SSE,AVX不缺少?

时间:2017-03-05 20:50:47

标签: x86 sse simd avx

这是我的想象,还是SSE和AVX遗失的PNOT指令?也就是说,一个翻转向量中每一位的指令。

如果是,是否有更好的方法来模拟它而不是PXOR的向量为全1?非常烦人,因为我需要设置所有1的向量来使用该方法。

4 个答案:

答案 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, 0xffthe 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);