如何指导MS Visual C++;编译器使用未初始化的m512i寄存器 如何指导VisualC++编译器(1926)使用未初始化的 > M512i < /Cord>寄存器。在下面的代码段anot(或(a,B))计算中,dummy的内容是无关的 __m512i dummy; const __m512i n8 = _mm512_ternarylogic_epi64(dummy, A, B, 0x11);

如何指导MS Visual C++;编译器使用未初始化的m512i寄存器 如何指导VisualC++编译器(1926)使用未初始化的 > M512i < /Cord>寄存器。在下面的代码段anot(或(a,B))计算中,dummy的内容是无关的 __m512i dummy; const __m512i n8 = _mm512_ternarylogic_epi64(dummy, A, B, 0x11);,c++,visual-c++,intrinsics,micro-optimization,avx512,C++,Visual C++,Intrinsics,Micro Optimization,Avx512,不知何故,编译器假定寄存器需要一些内容(它没有),并且为zmm0生成了一个昂贵且不必要的内存引用: 62 F1 7E 48 6F 45 00 vmovdqu32 zmm0,zmmword ptr [rbp] 62 F3 DD 48 25 C5 11 vpternlogq zmm0,zmm4,zmm5,11h ICC 19.0.1理解这种情况,不会生成vmovdqu32 我尝试了什么:用0初始化dummy将vmovdqu32替换为: C5 F1 EF C9 vpx

不知何故,编译器假定寄存器需要一些内容(它没有),并且为
zmm0
生成了一个昂贵且不必要的内存引用:

62 F1 7E 48 6F 45 00 vmovdqu32   zmm0,zmmword ptr [rbp]  
62 F3 DD 48 25 C5 11 vpternlogq  zmm0,zmm4,zmm5,11h  
ICC 19.0.1理解这种情况,不会生成
vmovdqu32

我尝试了什么:用0初始化
dummy
vmovdqu32
替换为:

C5 F1 EF C9          vpxor       xmm1,xmm1,xmm1
这仍然会给出不必要的指令和暂停

< > > <强>问题>强>:如何指导Visual C++编译器与英特尔编译器进行相同的操作?只是不要初始化虚拟寄存器

还有一个摊位

。它实际上也和当前Intel CPU上的NOP一样便宜,并且避免了输出依赖性将此dep链耦合到另一个dep链的风险。它不会导致暂停(除非是间接的,比如I-cache未命中),但它可能会浪费前端吞吐量的一个融合域uop


如果
A
B
在此之后失效,则使用其中一个作为虚拟输入,如下所示

__m512i nor_A(__m512i A, __m512i B) {
    return _mm512_ternarylogic_epi64(A, A, B, 0x11);
}
如果不是内联的,那么输入reg随后就失效了,并且它必须返回它在中接收到的相同reg
A
,所有4个主要的x86编译器都是这种简单情况下的理想代码。(我猜使用第一个输入时,有些人将立即数优化为
5
,而不是
0x11
。)

或者,如果您在循环中使用这个,您可以通过使用目标作为第一个输入,有意创建一个循环携带的dep链。在循环外声明向量。如果在包装器函数中使用ternlog,则需要将对向量的引用传递到该函数中,以使其正常工作


如果你想冒一个虚假依赖的风险,是你想要的东西的最大希望。它安全地表示您想要的内容(任意寄存器),同时避免读取未初始化的C变量时出现未定义的行为。(不,IDK为什么英特尔认为
epi32
si512
更合理,比如
\u mm\u undefined\u si128()
。它没有屏蔽版本!)

ICC将其编译为零额外指令。Clang、GCC和MSVC对目标寄存器进行异或归零,如果它们的内部不真正支持未定义的输入,则可能将其实现为
\u mm512\u setzero\u si512

我还包括实际UB版本;ICC和clang在那里做你想做的事情,选择
zmm0
作为虚拟输入

__m512i nor_undef(__m512i A, __m512i B) {
    return _mm512_ternarylogic_epi64(_mm512_undefined_epi32(), A, B, 0x11);
}
MSVC 19.24
-O2-arch:AVX512-Gv
-不太好,但基本上很好,因此相同的源代码可以编译成您想要的ICC,而不会在任何地方变得糟糕

__m512i nor_undef(__m512i,__m512i) PROC             ; nor_undef, COMDAT
    vpxor   xmm2, xmm2, xmm2
    vpternlogq zmm2, zmm0, zmm1, 17
    vmovdqu32 zmm0, zmm2
    ret     0
GCC 10.1:

nor_undef:
    vmovdqa64       zmm2, zmm0
    vpxor   xmm0, xmm0, xmm0
    vpternlogq      zmm0, zmm2, zmm1, 17
    ret
叮当声10.0

nor_undef:
    vpxor   xmm2, xmm2, xmm2
    vpternlogq      zmm0, zmm2, zmm1, 5
    ret
国际商会19.0.1

nor_undef:
    vpternlogq zmm0, zmm2, zmm1, 5                          #15.12
    ret                                                     #15.12

还有一个摊位xor归零正在破坏依赖关系。它实际上和当前Intel CPU上的NOP一样便宜,并且避免了输出依赖性将此dep链耦合到另一个dep链的风险。但是,如果您想冒险,
\u mm512\u undefined\u si512()
可能会用作虚拟参数。这些都是有用的实验,谢谢!如果阅读本文的人知道如何指示(或强制)MSVC遵守_mm_undefined_si128(),并且不生成任何指令;请添加一个新答案。
nor_undef:
    vpternlogq zmm0, zmm2, zmm1, 5                          #15.12
    ret                                                     #15.12