AVX2 编译的程序是否仍可以使用支持 AVX-512 的 32 个寄存器CPU?
Can AVX2-compiled program still use 32 registers of an AVX-512 capable CPU?
假设针对 AVX2 的编译和 C++ 内在函数,如果我编写一个 nbody 算法,每次 body-body 计算使用 17 个寄存器,第 17 个寄存器可以间接(寄存器重命名硬件)或直接(visual studio编译器、gcc 编译器)映射到 AVX-512 寄存器以切断内存依赖?例如,skylake 架构有 1 个或 2 个 AVX-512 fma 单元。这个数字是否也改变了可用的总寄存器? (特别是 xeon silver 4114 cpu)
如果这有效,它是如何工作的?当所有指令都是 AVX2 或更少时,第一个硬件线程使用每个 ZMM 向量的前半部分,第二个硬件线程使用每个 ZMM 向量的后半部分?
编辑: 如果目标机器(例如使用 OpenCL)上有 online-compilation 怎么办?司机可以帮我注册使用吗?
没有。如果您的目标是 AVX2 架构,那么生成的代码必须能够 运行 在 任何 支持 AVX2 的 CPU 上。其中许多不支持 AVX-512,因此它们没有您想要使用的额外寄存器。
话虽如此,您没有理由不能使用 AVX512VL 支持(即 gcc 中的 -mavx512vl
进行编译)并使用 AVX2 内在函数编写代码。在这种情况下,编译器将能够使用额外的寄存器,因为它针对的是 AVX-512 架构,所有架构都包含 32 [xyz]mm
个寄存器。
TL:DR:使用 -march=skylake-avx512
进行编译,让编译器使用 EVEX 前缀访问 ymm16-31,这样它就可以(希望)为具有 17 个 __m256
值的代码制作更好的 asm " 立刻。
-march=skylake-avx512
包括 -mavx512vl
For example, skylake architecture has 1 or 2 AVX-512 fma units. Does this number change total registers available too?
不,无论存在多少个 FMA 执行单元,所有 Skylake CPU 中的物理寄存器文件大小都相同。这些东西是完全正交的。
64位AVX2的架构YMM寄存器数量为16个,64位AVX512VL为32个。在 32 位代码中,始终只有 8 个向量寄存器可用,即使是 AVX512。 (所以 32 位对于大多数 high-performance 计算来说已经过时了。)
使用 AVX512VL1 + AVX2 的 YMM16-31 需要更长的 EVEX 编码,但是所有操作数都在低 16 位的指令可以使用更短的 VEX 前缀 AVX/AVX2指令的形式。 (混合 VEX 和 EVEX 编码没有惩罚,所以 VEX 更适合 code-size。但是如果你避免 y/zmm0-y/zmm15,你不需要 VZEROUPPER;legacy-SSE 指令不能触及 xmm16 -31 所以不可能有问题。)
同样,none 这与存在的 FMA 执行单元的数量有关。
脚注 1:
AVX512F 只包含大部分指令的 ZMM 版本;大多数 YMM 指令的 EVEX 编码需要 AVX512VL。仅有 CPU 具有 AVX512F 而不是 AVX512VL 的是 Xeon Phi、KNL / KNM,现已停产;所有主流 CPU 支持它们支持的所有 AVX512 指令的 xmm/ymm 版本。
if I write an nbody algorithm using 17 registers per body-body computation, can 17th register be indirectly(register rename hardware) mapped
不,这不是 CPU 和机器代码的工作方式。 在机器代码中,只有一个 4 位(不使用仅 AVX512 编码)或 5 位(使用 AVX512 编码)字段来指定指令的寄存器操作数。
如果您的代码需要同时“激活”17 个向量值,编译器将不得不向 spill/reload 其中之一发出指令,当以 x86-64 AVX2 为目标时, 架构上 只有 16 个 YMM 寄存器。即它有 16 个不同的名称,CPU 可以将其重命名到其更大的内部寄存器文件中。
如果寄存器重命名解决了整个问题,x86-64 就不会费心将架构寄存器的数量从 8 个整数/8 xmm 增加到 16 个整数/16 xmm。
这就是为什么 AVX512 花费了 3 个额外位(dst、src1 和 src2 各 1 位)以允许访问超过 VEX 前缀可以编码的 32 个架构向量寄存器。 (仅在 64 位模式下;32 位模式仍然只有 8 个。在 32 位模式下,VEX 和 EVEX 前缀是现有指令的无效编码,翻转那些额外的 register-number 位会使它们解码为 那些旧指令的有效编码,而不是作为前缀。)
寄存器重命名允许重复使用相同的体系结构寄存器以获得不同的值,而没有任何错误的依赖性。即 avoids WAR and WAW hazards;它是使 out-of-order 执行工作的“魔法”的一部分。在考虑 ILP 和 out-of-order 执行时,它有助于在飞行中保持更多价值,但它 不会 帮助您在简单的程序执行顺序中的任何时候在架构寄存器中拥有更多价值.
例如,下面的循环只需要3个架构寄存器,每次迭代都是独立的(没有loop-carried依赖,除了pointer-increment)。
.loop:
vaddps ymm0, ymm1, [rsi] ; ymm0 = ymm1, [src]
vmulps ymm0, ymm0, ymm2 ; ymm0 *= ymm2
vmovaps [rsi+rdx], ymm0 ; dst = src + (dst_start - src_start). Stays micro-fused on Haswell+
add rsi, 32
cmp rsi, rcx ; }while(rsi < end_src)
jb .loop
但是从第一次写入 ymm0 到一次迭代中的最后一次读取有 8 个周期的延迟链(Skylake addps/mulps 各有 4 个周期),它会在 CPU 上成为瓶颈无需注册重命名。在本次迭代中的 vmovaps
读取值之前,下一次迭代无法写入 ymm0。
但是在 out-of-order CPU 上,多次迭代是 in-flight 一次,每次写入 ymm0 重命名以写入不同的物理寄存器。忽略 front-end 瓶颈(假装我们展开了),CPU 可以保持足够的飞行迭代以每个时钟 2 addps/mulps 微指令使 FMA 单元饱和,使用大约 8 个物理寄存器。 (或者更多,因为它们在退休之前实际上不能被释放,而不仅仅是最后一个 uop 读取该值)。
限制物理寄存器文件大小can be the limit on the out-of-order windows size, instead of the ROB or scheduler size。
(我们考虑了一段时间,Skylake-AVX512 使用 2 个 PRF 条目用于 ZMM 寄存器,基于 , but later more detailed experiments revealed that AVX512 mode powers up a wider PRF, or upper lanes to complement the existing PRF, so SKX in AVX512 mode still has the same number of 512-bit physical registers as 256-bit physical registers. See discussion between @BeeOnRope and @Mysticial。我认为在某处有更好的 write-up 实验 + 结果但是我在 ATM 上找不到它。)
相关:(答案:它没有;OP 对 register-reuse 感到困惑。我的答案解释得很详细,并进行了一些有趣的多向量累加器性能实验。)
假设针对 AVX2 的编译和 C++ 内在函数,如果我编写一个 nbody 算法,每次 body-body 计算使用 17 个寄存器,第 17 个寄存器可以间接(寄存器重命名硬件)或直接(visual studio编译器、gcc 编译器)映射到 AVX-512 寄存器以切断内存依赖?例如,skylake 架构有 1 个或 2 个 AVX-512 fma 单元。这个数字是否也改变了可用的总寄存器? (特别是 xeon silver 4114 cpu)
如果这有效,它是如何工作的?当所有指令都是 AVX2 或更少时,第一个硬件线程使用每个 ZMM 向量的前半部分,第二个硬件线程使用每个 ZMM 向量的后半部分?
编辑: 如果目标机器(例如使用 OpenCL)上有 online-compilation 怎么办?司机可以帮我注册使用吗?
没有。如果您的目标是 AVX2 架构,那么生成的代码必须能够 运行 在 任何 支持 AVX2 的 CPU 上。其中许多不支持 AVX-512,因此它们没有您想要使用的额外寄存器。
话虽如此,您没有理由不能使用 AVX512VL 支持(即 gcc 中的 -mavx512vl
进行编译)并使用 AVX2 内在函数编写代码。在这种情况下,编译器将能够使用额外的寄存器,因为它针对的是 AVX-512 架构,所有架构都包含 32 [xyz]mm
个寄存器。
TL:DR:使用 -march=skylake-avx512
进行编译,让编译器使用 EVEX 前缀访问 ymm16-31,这样它就可以(希望)为具有 17 个 __m256
值的代码制作更好的 asm " 立刻。
-march=skylake-avx512
包括 -mavx512vl
For example, skylake architecture has 1 or 2 AVX-512 fma units. Does this number change total registers available too?
不,无论存在多少个 FMA 执行单元,所有 Skylake CPU 中的物理寄存器文件大小都相同。这些东西是完全正交的。
64位AVX2的架构YMM寄存器数量为16个,64位AVX512VL为32个。在 32 位代码中,始终只有 8 个向量寄存器可用,即使是 AVX512。 (所以 32 位对于大多数 high-performance 计算来说已经过时了。)
使用 AVX512VL1 + AVX2 的 YMM16-31 需要更长的 EVEX 编码,但是所有操作数都在低 16 位的指令可以使用更短的 VEX 前缀 AVX/AVX2指令的形式。 (混合 VEX 和 EVEX 编码没有惩罚,所以 VEX 更适合 code-size。但是如果你避免 y/zmm0-y/zmm15,你不需要 VZEROUPPER;legacy-SSE 指令不能触及 xmm16 -31 所以不可能有问题。)
同样,none 这与存在的 FMA 执行单元的数量有关。
脚注 1: AVX512F 只包含大部分指令的 ZMM 版本;大多数 YMM 指令的 EVEX 编码需要 AVX512VL。仅有 CPU 具有 AVX512F 而不是 AVX512VL 的是 Xeon Phi、KNL / KNM,现已停产;所有主流 CPU 支持它们支持的所有 AVX512 指令的 xmm/ymm 版本。
if I write an nbody algorithm using 17 registers per body-body computation, can 17th register be indirectly(register rename hardware) mapped
不,这不是 CPU 和机器代码的工作方式。 在机器代码中,只有一个 4 位(不使用仅 AVX512 编码)或 5 位(使用 AVX512 编码)字段来指定指令的寄存器操作数。
如果您的代码需要同时“激活”17 个向量值,编译器将不得不向 spill/reload 其中之一发出指令,当以 x86-64 AVX2 为目标时, 架构上 只有 16 个 YMM 寄存器。即它有 16 个不同的名称,CPU 可以将其重命名到其更大的内部寄存器文件中。
如果寄存器重命名解决了整个问题,x86-64 就不会费心将架构寄存器的数量从 8 个整数/8 xmm 增加到 16 个整数/16 xmm。
这就是为什么 AVX512 花费了 3 个额外位(dst、src1 和 src2 各 1 位)以允许访问超过 VEX 前缀可以编码的 32 个架构向量寄存器。 (仅在 64 位模式下;32 位模式仍然只有 8 个。在 32 位模式下,VEX 和 EVEX 前缀是现有指令的无效编码,翻转那些额外的 register-number 位会使它们解码为 那些旧指令的有效编码,而不是作为前缀。)
寄存器重命名允许重复使用相同的体系结构寄存器以获得不同的值,而没有任何错误的依赖性。即 avoids WAR and WAW hazards;它是使 out-of-order 执行工作的“魔法”的一部分。在考虑 ILP 和 out-of-order 执行时,它有助于在飞行中保持更多价值,但它 不会 帮助您在简单的程序执行顺序中的任何时候在架构寄存器中拥有更多价值.
例如,下面的循环只需要3个架构寄存器,每次迭代都是独立的(没有loop-carried依赖,除了pointer-increment)。
.loop:
vaddps ymm0, ymm1, [rsi] ; ymm0 = ymm1, [src]
vmulps ymm0, ymm0, ymm2 ; ymm0 *= ymm2
vmovaps [rsi+rdx], ymm0 ; dst = src + (dst_start - src_start). Stays micro-fused on Haswell+
add rsi, 32
cmp rsi, rcx ; }while(rsi < end_src)
jb .loop
但是从第一次写入 ymm0 到一次迭代中的最后一次读取有 8 个周期的延迟链(Skylake addps/mulps 各有 4 个周期),它会在 CPU 上成为瓶颈无需注册重命名。在本次迭代中的 vmovaps
读取值之前,下一次迭代无法写入 ymm0。
但是在 out-of-order CPU 上,多次迭代是 in-flight 一次,每次写入 ymm0 重命名以写入不同的物理寄存器。忽略 front-end 瓶颈(假装我们展开了),CPU 可以保持足够的飞行迭代以每个时钟 2 addps/mulps 微指令使 FMA 单元饱和,使用大约 8 个物理寄存器。 (或者更多,因为它们在退休之前实际上不能被释放,而不仅仅是最后一个 uop 读取该值)。
限制物理寄存器文件大小can be the limit on the out-of-order windows size, instead of the ROB or scheduler size。
(我们考虑了一段时间,Skylake-AVX512 使用 2 个 PRF 条目用于 ZMM 寄存器,基于
相关: