如何指导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随后就失效了,并且它必须返回它在中接收到的相同regA
,所有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