问题 如果你在一个快速乘法的架构上,有没有办法在编译时检查?


有没有办法让C代码判断它是否在乘法快速的架构上编译?有一些宏 __FAST_MULT__ 或者在这些架构上定义的东西?

例如,假设您正在实现一个函数,通过shift-and-add方法*确定64位整数的汉明权重。有 两个最佳算法:一个需要17个算术运算,而另一个只需要12个,但其中一个是乘法运算。第二种算法因此快30%, 如果 你在硬件上运行,其中乘法所需的时间与加法相同 - 但是在将乘法实现为重复加法的系统上要慢得多。
因此,在编写这样的函数时,能够在编译时检查是否是这种情况并在适当时在两种算法之间切换是有用的:

unsigned int popcount_64(uint64_t x) {
    x -= (x >> 1) & 0x5555555555555555;                             // put count of each 2 bits into those 2 bits
    x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); // put count of each 4 bits into those 4 bits
    x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;                        // put count of each 8 bits into those 8 bits
#ifdef __FAST_MULT__
    return (x * 0x0101010101010101)>>56;                            // returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
#else // __FAST_MULT__
    x += x >>  8;                                                   // put count of each 16 bits into their lowest 8 bits
    x += x >> 16;                                                   // put count of each 32 bits into their lowest 8 bits
    x += x >> 32;                                                   // put count of each 64 bits into their lowest 8 bits
    return x & 0x7f;
#endif // __FAST_MULT__
}

有没有办法做到这一点?

*是的,我知道 __builtin_popcount() 功能;这只是一个例子。


7573
2018-06-09 14:31


起源

我相信大多数做这样的事情的软件包要么在编译之前使用配置标志,要么执行某种自动性能测试来正确设置这些标志。 - Jeremy West
这正是编译器内置存在的原因。 - too honest for this site


答案:


有没有办法让C代码判断它是否在乘法快速的架构上编译?有一些宏 __FAST_MULT__ 或者在这些架构上定义的东西?

不,标准C不提供任何此类设施。特定的编译器可能提供扩展这样的东西,但我并没有特别注意到实际的任何扩展。

这种事情可以在构建配置期间进行测试,例如通过Autoconf或CMake,在这种情况下,您可以在适当的时候自己提供符号。

或者,某些C编译器肯定会提供指示编译代码的体系结构的宏。您可以结合对各种机器架构细节的了解,在两种算法之间进行选择 - 毕竟这就是这些宏的用途。

或者,您可以依赖构建程序的人员,通过配置选项,通过定义宏或其他任何内容来选择。


7
2018-06-09 14:50



对于Autoconf / Cmake +1 - 如果你这通常是最好的选择 真 想要从你的应用程序中挤出最后一点性能 - 在第一次启动时动态,全自动编译,通过预编译的辅助二进制文件......这些不需要“快速”,它们只需要触发构建:-) - specializt


我不相信有一个专门针对快速乘法功能的预定义宏。

然而,有很多 用于不同体系结构的预定义编译器宏 所以 如果你事先已经知道了 什么体系结构或CPU支持快速乘法指令,您可以使用这些宏来定义您自己的特定于应用程序的宏,表示快速乘法。

例如。:

#if (defined __GNUC__ && defined __arm__ && defined __ARM_ARCH_'7'__) ||
    (defined __CC_ARM && (__TARGET_ARCH_ARM == 7))
#define FAST_MULT
#endif

2
2018-06-09 14:52