有没有办法自动将 avx512 替换为 avx2?

Is there way to automatically replace avx512 with avx2?

根据 Linus Torvalds 的建议(以及跨平台性能),我不希望使用 avx512。如果我正在使用的库试图从内在函数或编译器优化中使用 axv512,我是否可以向编译器(gcc 和 msvc)指定一个标志,以便将所有 avx512 指令分成成对的 avx2 指令?

不,通过告诉编译器它不能,首先编译你的代码不要使用 AVX-512;您只需对使用需要 AVX-512 的内部函数的代码做任何事情。


但是,如果您正在为支持 AVX-512 的 CPU 进行编译,通常值得使用它,尤其是使用 256 位向量以避免 turbo-frequency and other penalties that come with 512-bit vectorsGCC 的默认调优已经 -mprefer-vector-width=256 用于 CPU s like -march=skylake-avx512.

如果你想制作一个可以 运行 在 CPU 上不使用 AVX-512 的二进制文件,那么是的,显然你需要确保它永远不会执行,并且没有它就会出错的指令。例如gcc -O3 -march=znver2-march=skylake 或其他。这些目标架构选项都不包括 AVX-512。或者 -march=native 如果编译任何 CPU 你有。

但是如果你有一个支持 AVX-512 的 CPU,但你不想使用它,你可以使用像 -march=native -mno-avx512f 这样的东西(所有其他 AVX-512 扩展都依赖于“Foundation”AVX-512F,因此禁用它甚至会阻止 AVX-512VL 用于 128 位和 256 位向量。)

-march=native 然后禁用某些东西的部分好处是还可以设置调整选项。如果你想要一个 运行 在 Skylake 和 Zen2 上都很好的二进制文件,我不是确定推荐什么;可能 -march=skylake-march=znver2 都可以;有默认的“tune=generic”,但它太在意甚至不支持 AVX2 的真正旧的 CPU , 像 Sandybridge: )


内在函数

即使使用内在函数,GCC 也只会发出目标选项支持的指令,因此 -mno-avx512f 可以确保您没有遗漏任何内容。你会得到编译时错误,而不是 EVEX 指令从裂缝中溜走。

(MSVC 不同,它是围绕单一二进制模型设计的,在该模型中使用新的指令集是在只有 CPU 支持时才调用的函数中完成的,因此它不会阻止你使用 AVX-512。据我所知,MSVC 仍然没有使用 AVX-512 自动矢量化的选项,只有 /arch:AVX2。但是无论如何,如果您不这样做,MSVC 不会自行发出 AVX-512 指令不要告诉它,如果你不使用 /arch:AVX512 之类的任何选项,如果存在这样的东西;据我所知,不幸的是它没有 /arch:native。使用 MSVC,你必须确保你抓住了内在函数的所有用途,尽管使用 GCC 编译可以帮助确保您的代码库不会那样做。)

如果您仍想编译使用 _mm512_add_epi32_mm256_ternlog_epi32 或其他任何内容的代码,您将需要 immintrin.h 的一个版本,该版本将 __m512i 定义为 struct/class 有两个 __m256i 成员并模拟所有内在函数。 某些 AVX512 内在函数的仿真成本并不低,尤其是掩码操作, 以及通过比较掩码获取整数而不是向量的整个概念。因此,尝试让这一切完全透明地发生可能不是一个好主意;取而代之的是让 GCC 阻止你使用任何 AVX-512 指令,同时你制作任何还没有 AVX2 版本的内在函数代码的仅 AVX2 版本。

上次出现这个问题时,,我找到了一个 avxintrin-emu.h 可以让你在只为 SSE4 编译的同时为 AVX 开发。但我没有找到 AVX-512 的等效项。 (通常你会编译一个 AVX-512 二进制文件并在像 SDE 这样的模拟器上测试它,它在 运行 时模拟,而不是编译时。)

Agner Fog 的 VectorClass 包装器库 (https://www.agner.org/optimize/#vectorclass) 支持 + - * / 等基本操作,以及混洗和混合,并且具有使用一对 AVX2 向量模拟的 512 位向量版本。 (并且 VCL 类型可以隐式转换为 __m256i 或 __m512i 等等,因此对于它没有自己的函数的操作,您可以使用 Intel 内在函数。但是你又回到了同样需要一个仅使用 AVX2 指令模拟 __m256_ternlog_epi32 的库。)


这不会阻止 libc 在 strcmplog/exp 等函数中使用手写 AVX-512 指令,因为动态 CPU 调度发生在 运行 时间,你无法阻止你的 CPU 报告它支持 AVX-512。 (除非使用 VM,或者告诉内核不要在启动时启用 AVX-512,如果 Linux 有一个选项。)