Вот два способа установить отдельный бит в C на x86-64:
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
версия C занимает примерно 90% больше времени при использовании с постоянной bit
. (Обе версии компилируются с одинаковым ассемблерным кодом, за исключением того, что версия 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
также дает аналогичные результаты.