如何指示 MS Visual C++ 编译器使用未初始化的 __m512i 寄存器

HJL*_*ink 4 c++ intrinsics micro-optimization visual-c++ avx512

如何指示 Visual C++ 编译器 (1926) 使用未初始化的__m512i寄存器。在下面的代码片段not(or(A,B))中计算了a ,内容dummy无关紧要。

__m512i dummy;
const __m512i n8 = _mm512_ternarylogic_epi64(dummy, A, B, 0x11);
Run Code Online (Sandbox Code Playgroud)

不知何故,编译器假定寄存器需要有一些内容,(它没有),并为以下生成昂贵且不必要的内存引用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  
Run Code Online (Sandbox Code Playgroud)

ICC 19.0.1 了解这种情况并且不会生成vmovdqu32.

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

C5 F1 EF C9          vpxor       xmm1,xmm1,xmm1
Run Code Online (Sandbox Code Playgroud)

这仍然给出了不必要的指令和停顿。

因此问题是:如何指示 Visual C++ 编译器执行与 Intel 编译器相同的操作?只是不要初始化虚拟寄存器。

Pet*_*des 6

和一个摊位

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


如果AB在此之后死亡,请使用其中之一作为虚拟输入,如下所示

__m512i nor_A(__m512i A, __m512i B) {
    return _mm512_ternarylogic_epi64(A, A, B, 0x11);
}
Run Code Online (Sandbox Code Playgroud)

当未内联时,因此输入 reg 之后就失效了,并且它必须在接收到的同一个 reg 中返回A,所有 4 个主要的 x86 编译器都为这个简单的情况制作了理想的代码。(有些优化了直接到5而不是0x11,我想使用第一个输入。)

; MSVC 19.24 -O2 -arch:AVX512 -Gv    (vectorcall calling convention)
# gcc10/clang10/ICC19 -O3 -march=skylake-avx512
nor_A:
        vpternlogq      zmm0, zmm0, zmm1, 17
        ret
Run Code Online (Sandbox Code Playgroud)

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


如果你想冒一个虚假的依赖,_mm512_undefined_epi32()是你对你想要的最好的希望。它安全地表达您想要的内容(任意寄存器),同时避免未定义行为读取未初始化的 C 变量。(不,IDK 为什么英特尔认为epi32si512like更有意义_mm_undefined_si128()。没有它的掩码版本!)

ICC 将其编译为零额外指令。但是,Clang、GCC 和 MSVC 对目标寄存器执行异或零处理,可能在实现它时就_mm512_setzero_si512好像它们在其内部并不真正支持未定义的输入一样。 神箭

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

__m512i nor_undef(__m512i A, __m512i B) {
    return _mm512_ternarylogic_epi64(_mm512_undefined_epi32(), A, B, 0x11);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会 10.1:

nor_undef:
    vmovdqa64       zmm2, zmm0
    vpxor   xmm0, xmm0, xmm0
    vpternlogq      zmm0, zmm2, zmm1, 17
    ret
Run Code Online (Sandbox Code Playgroud)

叮当 10.0

nor_undef:
    vpxor   xmm2, xmm2, xmm2
    vpternlogq      zmm0, zmm2, zmm1, 5
    ret
Run Code Online (Sandbox Code Playgroud)

国际商会 19.0.1

nor_undef:
    vpternlogq zmm0, zmm2, zmm1, 5                          #15.12
    ret                                                     #15.12
Run Code Online (Sandbox Code Playgroud)