我是做闭源的在许多情况下,启用AVX和类似的扩展具有有价值的性能益处,但是这样做当然防止了二进制分布式软件在可能不支持那些指令集的较旧硬件上运行。我也不想为每个CPU特性集提供单独的捆绑包。我正在使用C(使用GCC),目标平台是Linux/x86_64。
如果可以的话,我想写这样的代码:
void do_expensive_thing(args) {
if (cpu_has_avx512()) {
// inline AVX512 implementation, using SIMD intrinsics
} else if (cpu_has_avx()) {
// inline AVX implementation, using SIMD intrinsics
} else {
// pure C implementation
}
}
根据我的经验,除非启用相关的指令集,否则intrinsic将无法工作(例如-mavx 512 f),但这只在翻译单元级别起作用,所以理论上编译器可能会在代码的其他部分发出这些指令,我没有检查支持。所以当然我可以将每个实现分解到它自己的翻译单元中,这样我就可以单独控制标志,但是编译器不能内联它们(在少数情况下可能会有问题),更重要的是,从源代码组织的Angular 来看,这有点令人头痛。
1条答案
按热度按时间ymdaylpp1#
在一个函数中混合使用伊萨扩展是不可能的。(ymm/zmm)个寄存器对于作为整体的函数是允许的还是不允许的。另一个重要的原因是您不能让
cpu_has_avx
检查代码移动障碍(例如,不允许在检查中提升vpxor
指令)。出于同样的原因,GCC将在内部禁止内联调用,其中允许的ISA扩展对于调用者和被调用者不同。
因此,你必须将代码的变体放在单独的函数中。将这些函数放在单独的编译单元中赠款你更好地兼容Clang,并且可能会缩短编译时间(在GCC中,在编译单元中切换目标是非常昂贵的)。如果你无论如何都需要在同一个翻译单元中使用它们,你必须使用
__attribute__((target("...")))
或#pragma GCC target "..."
。