如何指示 MS Visual C++ 编译器使用未初始化的 __m512i 寄存器
How to instruct MS Visual C++ compiler to use an uninitialized __m512i register
如何指示 Visual C++ 编译器 (1926) 使用未初始化的 __m512i
寄存器。在下面的代码片段中计算了一个not(or(A,B))
,dummy
的内容无关紧要。
__m512i dummy;
const __m512i n8 = _mm512_ternarylogic_epi64(dummy, A, B, 0x11);
编译器以某种方式假设寄存器需要有一些内容,(它没有),并且为 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 编译器相同的操作?只是不要初始化虚拟寄存器。
and a stall
。它实际上与当前英特尔 CPU 上的 NOP 一样便宜,并且避免了将此 dep 链耦合到另一个 dep 链的输出依赖性风险。它不会导致停顿(除非是间接的,比如 I-cache 未命中),但它可能会浪费前端吞吐量的一个融合域微指令。
如果A
或B
在这之后死了,使用其中之一作为虚拟输入,像这样
__m512i nor_A(__m512i A, __m512i B) {
return _mm512_ternarylogic_epi64(A, A, B, 0x11);
}
当没有内联时,所以输入 regs 之后就死了,它必须 return 在它收到 A
的同一个 reg 中,所有 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
或者,如果您在循环中使用它,您可以通过使用目标作为第一个输入来有意创建一个循环携带的 dep 链。在循环外声明向量。如果您在包装函数中使用 ternlog,则需要将对向量的引用传递给该函数才能使其正常工作。
如果您想冒虚假依赖的风险,_mm512_undefined_epi32()
是您想要的最大希望。它安全地表达您想要的内容(任意寄存器),同时避免未定义的行为读取未初始化的 C 变量。 (不,IDK 为什么英特尔认为 epi32
比 si512
更有意义,比如 _mm_undefined_si128()
。它没有屏蔽版本!)
ICC 将其编译为零额外指令。不过,Clang、GCC 和 MSVC 对目标寄存器进行异或归零,如果它们在内部不真正支持未定义的输入,则可能将其实现为 _mm512_setzero_si512
。 Godbolt
我还包含了带有实际 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
海湾合作委员会 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
ICC 19.0.1
nor_undef:
vpternlogq zmm0, zmm2, zmm1, 5 #15.12
ret #15.12
如何指示 Visual C++ 编译器 (1926) 使用未初始化的 __m512i
寄存器。在下面的代码片段中计算了一个not(or(A,B))
,dummy
的内容无关紧要。
__m512i dummy;
const __m512i n8 = _mm512_ternarylogic_epi64(dummy, A, B, 0x11);
编译器以某种方式假设寄存器需要有一些内容,(它没有),并且为 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 编译器相同的操作?只是不要初始化虚拟寄存器。
and a stall
如果A
或B
在这之后死了,使用其中之一作为虚拟输入,像这样
__m512i nor_A(__m512i A, __m512i B) {
return _mm512_ternarylogic_epi64(A, A, B, 0x11);
}
当没有内联时,所以输入 regs 之后就死了,它必须 return 在它收到 A
的同一个 reg 中,所有 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
或者,如果您在循环中使用它,您可以通过使用目标作为第一个输入来有意创建一个循环携带的 dep 链。在循环外声明向量。如果您在包装函数中使用 ternlog,则需要将对向量的引用传递给该函数才能使其正常工作。
如果您想冒虚假依赖的风险,_mm512_undefined_epi32()
是您想要的最大希望。它安全地表达您想要的内容(任意寄存器),同时避免未定义的行为读取未初始化的 C 变量。 (不,IDK 为什么英特尔认为 epi32
比 si512
更有意义,比如 _mm_undefined_si128()
。它没有屏蔽版本!)
ICC 将其编译为零额外指令。不过,Clang、GCC 和 MSVC 对目标寄存器进行异或归零,如果它们在内部不真正支持未定义的输入,则可能将其实现为 _mm512_setzero_si512
。 Godbolt
我还包含了带有实际 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
海湾合作委员会 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
ICC 19.0.1
nor_undef:
vpternlogq zmm0, zmm2, zmm1, 5 #15.12
ret #15.12