[英]Choose assembly implementation to use based on supported instructions
我正在开发一个C库,它编译/链接到.a
文件,用户可以静态链接到他们的代码。 库的性能非常重要,因此我在x86-64汇编中编写性能关键的例程来优化性能。
对于某些例程,如果使用BMI2指令,我可以获得明显更好的性能,而不是坚持使用“标准”x86-64指令集。 麻烦的是,BMI2最近刚推出,我的一些用户使用不支持这些指令的处理器。
所以,我写了两次优化例程,一次使用BMI2指令,一次不使用它们。 在我目前的设置中,我将分发两个版本的.a
文件:一个需要支持BMI2指令的“快速”版本,以及一个不需要支持BMI2指令的“慢”版本。
我问是否有办法通过分发单个.a
文件来简化这一过程,该文件将根据最终应用程序运行的CPU是否支持BMI2指令动态选择正确的实现。
与StackOverflow上的类似问题不同,这里有两个特点:
if
语句也可能很重要。 我到目前为止提出的最快解决方案是执行以下操作:
cpuid
指令检查CPU是否支持BMI2指令。 true
或false
。 我对这种方法不满意,因为它有两个缺点:
cpuid
并在程序开头设置一个全局变量,因为我正在分发一个.a
文件并且无法控制最终二进制文件中的main
函数。 如果它提供了更好的解决方案,我很高兴在这里使用C ++,只要最终的库仍然可以与C程序链接和调用。 有没有比我上面详述的更有效的解决方案?
x264使用init函数(在调用其他任何东西之前需要调用库的用户,或类似的东西)来根据CPUID结果设置函数指针的结构。 包括考虑到pshufb
在一些支持它的早期CPU上pshufb
缓慢。
如果你的功能依赖于pdep
/ pext
,你可能想要检测AMD与英特尔,因为AMD的pdep
/ pext
非常慢,并且可能不值得在Ryzen上使用,即使它可用。 (有关说明表,请参阅https://agner.org/optimize/ 。)
函数指针的开销相当低,与调用共享库或DLL中的函数大致相同。 call [rel funcptr]
而不是call func
。 (在编译器生成的asm中调用您的函数)。
CPU依赖代码:如何避免函数指针? 在C中展示了一个非常简单的例子,并且正在寻找避免它的方法。 通过动态链接,您可以在动态链接时进行CPU检测,因此动态链接间接也成为您的CPU调度间接(就像glibc选择优化的memcpy
实现一样)。
但是对于.a
静态链接,只需创建静态初始化为基线版本的函数指针,并且您的CPU初始化函数(希望在任何函数指针被解除引用之前运行)将其重写为指向最佳版本的当前的CPU。
如果您使用的是gcc,则可以让编译器自动实现所有样板代码。 关于函数多版本化的gcc手册页
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.