如何在不让 gcc 到处插入其他 BMI2 指令的情况下使用 __bzhi_uxx 内在函数?

How to use the __bzhi_uxx intrinsic without letting gcc to insert other BMI2 instructions everywhere?

我想使用 _bzhi_u32 内部函数,但我不想使用 -mbmi2 标志,因为这使得 gcc 可以使用其他 BMI2 指令(特别是 SHLX 在许多 << 轮班中)如果运行可执行文件的主机不支持 BMI2,这将产生 SIGILL(非法指令)。

我只在一个函数中使用 _bzhi_u32,我通过在运行时检查是否支持 _builtin_cpu_is("corei7") 来保护它的使用,如果不支持则默认为另一个实现。但是我无法保护 gcc 在使用 -mbmi2 时插入的其他 BMI2 指令。

问题是 _bzhi_u32 内在函数不会在 x86intrin.h 中定义,除非指定了 -mbmi2(具有 gcc 散布 SHLX 的不良影响地方)。

有两种可能的替代方法可以避免全局指定 -mbmi2

  1. 如果使用 GCC 4.9 或更高版本,您可以只包含 x86intrin.h 并声明函数使用 _bzhi_u32__attribute__((target ("bmi2")))。这样 gcc 将在该函数上生成 BMI2 指令。 这在 4.8 和更低版本上不起作用_bzhi_u32 未定义,除非设置 __BMI2__,即使它是链接器也会抱怨 undefined reference to '_bzhi_u32').
  2. 将函数的定义放在它自己的.c文件中,并将#pragma GCC target "bmi2"放在顶部。这定义了 __BMI2__ 并仅为该翻译单元启用 BMI2 指令生成。
  3. 像选项 2 一样将函数放在它自己的文件中,并只用 -mbmi2 编译该文件(相当于 #pragma GCC target 选项。
  4. 使用内联汇编而不是其他 中解释的内部函数。

选项 2 和 3 限制了您的 inlinestatic 选项。如果您使用的是 GCC 4.9 或更高版本,则选项 1 是可行的方法。

引自gcc 4.9 release notes

It is now possible to call x86 intrinsics from select functions in a file that are tagged with the corresponding target attribute without having to compile the entire file with the -mxxx option. This improves the usability of x86 intrinsics and is particularly useful when doing Function Multiversioning.

与其使用内部函数,不如嵌入汇编代码更容易...

uint32_t val, i;

asm ("bzhi %0,%1,%2" : "=r"(val) : "r"(val), "r"(i) : );