以下是在 x86-64 上用 C 语言设置单个位的两种方法:
inline void SetBitC(long *array, int bit) {
//Pure C version
*array |= 1<<bit;
}
inline void SetBitASM(long *array, int bit) {
// Using inline x86 assembly
asm("bts %1,%0" : "+r" (*array) : "g" (bit));
}
将 GCC 4.3 与 -O3 -march=core2
结合使用选项,当与常量 bit
一起使用时,C 版本花费大约 90% 以上的时间 . (两个版本编译成完全相同的汇编代码,除了 C 版本使用 or [1<<num],%rax
指令而不是 bts [num],%rax
指令)
与变量一起使用时 bit
,C 版本的性能更好,但仍然明显慢于内联汇编。
重置、切换和检查位具有相似的结果。
为什么 GCC 对这种常见操作的优化如此糟糕?我在 C 版本上做错了吗?
编辑: 抱歉让您久等了,这是我用来进行基准测试的代码。它实际上是从一个简单的编程问题开始的……
int main() {
// Get the sum of all integers from 1 to 2^28 with bit 11 always set
unsigned long i,j,c=0;
for (i=1; i<(1<<28); i++) {
j = i;
SetBit(&j, 10);
c += j;
}
printf("Result: %lu\n", c);
return 0;
}
gcc -O3 -march=core2 -pg test.c
./a.out
gprof
with ASM: 101.12 0.08 0.08 main
with C: 101.12 0.16 0.16 main
time ./a.out
也给出了类似的结果。
最佳答案
Why does GCC optimize so poorly for such a common operation?
前言:自 20 世纪 80 年代末以来,对编译器优化的关注已经从关注单个操作的微基准测试转移到 macrobenchmarks它专注于人们关心速度的应用程序。如今,大多数编译器编写者都专注于宏基准测试,开发良好的基准套件是一件很认真的事情。
回答:gcc 上没有人使用基准测试,其中 or
和 bts
之间的差异对实际程序的执行时间很重要.如果你能制作这样的程序,你可能会引起 gcc-land 的人们的注意。
Am I doing something wrong with the C version?
不,这是非常好的标准 C。事实上,非常可读和惯用。
关于c - GCC优化对位操作的有效性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2039592/