Pau*_*l R 10
对于诸如此类的情况,查看编译器将生成什么是有益的.
例如,对于以下功能:
#include <immintrin.h>
__m256i test(const __m256i v)
{
return ~v;
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang似乎都生成了相同的代码:
test(long long __vector(4)):
vpcmpeqd ymm1, ymm1, ymm1
vpxor ymm0, ymm0, ymm1
ret
Run Code Online (Sandbox Code Playgroud)
AVX512F vpternlogd/_mm512_ternarylogic_epi32(__m512i a, __m512i b, __m512i c, int imm8)最终提供了一种无需任何额外常量即可实现 NOT 的方法,使用可在 Skylake-avx512 上的任何矢量 ALU 端口上运行的单个指令。
对于 AVX512VL,也适用于 128 和 256 位向量,而不会弄脏 ZMM 的上部。(除 Xeon Phi 之外的所有 AVX512 CPU 均具有 AVX512VL)。
在 Intel CPU 上,它可以在端口 0、1 或 5 中的任何一个上运行,因此 128 和 256 位版本的吞吐量为 3/时钟。或者像往常一样,512 位向量为 2/时钟,因为当任何 512 位微指令运行时,端口 1 会关闭。 https://www.uops.info/html-instr/VPTERNLOGD_XMM_XMM_XMM_I8.html)。
vpternlogd zmm,zmm,zmm, imm8有 3 个输入向量和 1 个输出,可就地修改目的地。使用正确的立即数,您仍然可以在不同的寄存器中实现复制与非,但它将对输出寄存器有“错误”依赖(这vpxord dst, src, all-ones不会)。
TL:DR:可能仍然使用全 1 的异或作为循环的一部分,除非你用完了寄存器。 vpternlog如果稍后需要输入,可能会花费额外的vmovdqa寄存器复制指令。
在循环之外,编译器首先创建全 1 的 512b 向量的最佳选择vpternlogd zmm,zmm,zmm, 0xff,因为 AVX512 比较指令比较掩码 ( ),因此与全 1 的异或可能已经涉及,或者可能是广播常数从内存中,对于 512 位向量。或者是 128 或 256 位的深度破坏 ALU uop 。k0-k7vpternlogdvpcmpeqd same,same
对于每个位位置i,输出位为imm[ (DEST[i]<<2) + (SRC1[i]<<1) + SRC2[i]],其中imm8被视为 8 元素位图。
因此,如果我们希望结果仅取决于 SRC2(即操作zmm/m512/m32bcst数),我们应该选择重复 1,0 的位图,1在偶数位置(由 选定src2=0)。
vpternlogd zmm1,zmm1, zmm2, 01010101b ; 0x55 ; false dep on zmm1
Run Code Online (Sandbox Code Playgroud)
如果你幸运的话,编译器会为你优化,_mm512_xor_epi32(v, _mm512_set1_epi32(-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);
Run Code Online (Sandbox Code Playgroud)
如果您不确定这是一个好主意,只需保持简单并为所有 3 个输入使用相同的变量即可:
__m512i t2_inv = _mm512_ternarylogic_epi32(t2, t2, t2, 0b01010101);
Run Code Online (Sandbox Code Playgroud)
如果您使用 Intrinsics,您可以使用这样的内联函数来单独进行 not 操作。
inline __m256i _mm256_not_si256 (__m256i a){
//return _mm256_xor_si256 (a, _mm256_set1_epi32(0xffffffff));
return _mm256_xor_si256 (a, _mm256_cmpeq_epi32(a,a));//I didn't check wich one is faster
}
Run Code Online (Sandbox Code Playgroud)