有没有办法用avx2自动替换avx512?

Posted

技术标签:

【中文标题】有没有办法用avx2自动替换avx512?【英文标题】:Is there way to automatically replace avx512 with avx2? 【发布时间】:2021-03-20 13:42:01 【问题描述】:

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

【问题讨论】:

Linus 建议不要在有 AVX-512 的 CPU 上使用它?我知道他说 AVX-512 是 CPU 设计人员的“强力病毒”(这有一定道理;将漂亮的掩码功能添加到 256 位向量会很好,让更多的 CPU 更早拥有它)。避免 512 位向量也是有道理的,但是在已经花费晶体管/折衷的 CPU 上,为什么要完全避免 AVX-512?它有时可以保存 256 位向量的指令。你能链接你所指的吗?也许 Linus 说的是一般意义上的 AVX-512,而他实际上只是指全宽 512 位向量。 【参考方案1】:

不,首先通过告诉编译器不能使用 AVX-512 来编译您的代码;您只需使用需要 AVX-512 的内部函数对代码执行任何操作。


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

如果你想制作一个可以在没有 AVX-512 的 CPU 上运行的二进制文件,那么显然你需要确保它永远不会执行以及没有它会出错的指令。例如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:Why doesn't gcc resolve _mm256_loadu_pd as single vmovupd?)


内在函数

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

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

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

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

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


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

【讨论】:

以上是关于有没有办法用avx2自动替换avx512?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法用 AVX2 编写 _mm256_shldi_epi8(a,b,1) ? (向量之间每 8 位元素移位一位)

如何编译 TensorFlow 二进制文件以使用 AVX2、AVX512F、FMA?

使用 AVX512 或 AVX2 计算所有压缩 32 位整数之和的最快方法

AVX2 等效于 std::clamp

出于测试目的在 CPU 中禁用 AVX2

你能调试自动矢量化循环吗?