实现同一功能的多个版本的最佳方法是使用特定的CPU指令(如果在运行时进行了测试,或者如果没有,则回退到较慢的实现?
例如,x86 BMI2提供了非常有用的PDEP指令。我将如何编写C代码,以便在启动时测试正在执行的CPU的BMI2可用性,并使用两种实现方式之一-一种使用_pdep_u64
调用(可用于-mbmi2
),另一种使用位操作“手工”使用C代码。是否有针对此类情况的内置支持?在提供对较新的内在函数的访问权限时,我将如何使GCC为较旧的arch编译?我怀疑如果通过全局函数指针而不是每次if / else调用函数,执行速度会更快?
Intel的ICC已有automatic function dispatching来为每种体系结构选择优化版本。我不知道细节,但显然它仅适用于Intel CPU,应该是unfair to other manufacturers。 Dr. Agner Fog's blog]中有许多补丁和解决方法
[后来在Function Multiversioning中引入了称为GCC 4.8的功能。它将target
或target_clones
属性添加到函数,并同时编译为函数的多个版本。然后,Clang和ICC采用了语法。在运行时,将自动确定当前体系结构以分发有效版本。这是Intel's Clear Linux runs so fast的原因之一。 ICC也可以在自动矢量化过程中创建multiple versions of a single loop
这是The one with multi-versioning (Part II)及其demo的示例,它与popcnt有关,但您知道了]
inline int popcount64_builtin_multiarch_loop(uint64_t data) { return __builtin_popcountll(data); } __attribute__((target_clones("popcnt","default"))) int runPopcount64_builtin_multiarch_loop(const uint8_t* bitfield, int64_t size, int repeat) { int res = 0; const uint64_t* data = (const uint64_t*)bitfield; for (int r=0; r<repeat; r++) for (int i=0; i<size/8; i++) { res += popcount64_builtin_multiarch_loop(data[i]); } return res; }
请注意,
PDEP
andPEXT
are very slow on current AMD CPUs仅应在Intel上启用它们