Я пытаюсь написать небольшую библиотеку для высокооптимизированного кода операции x86-64 bit и возился со встроенным asm.
Во время тестирования мое внимание привлек этот конкретный случай:
unsigned long test = 0;
unsigned long bsr;
// bit test and set 39th bit
__asm__ ("btsq\t%1, %0 " : "+rm" (test) : "rJ" (39) );
// bit scan reverse (get most significant bit id)
__asm__ ("bsrq\t%1, %0" : "=r" (bsr) : "rm" (test) );
printf("test = %lu, bsr = %d\n", test, bsr);
компилируется и отлично работает как в gcc, так и в icc, но когда я проверяю сборку, я получаю различия
gcc -S -fverbose-asm -std=gnu99 -O3
movq $0, -8(%rbp)
## InlineAsm Start
btsq $39, -8(%rbp)
## InlineAsm End
movq -8(%rbp), %rax
movq %rax, -16(%rbp)
## InlineAsm Start
bsrq -16(%rbp), %rdx
## InlineAsm End
movq -8(%rbp), %rsi
leaq L_.str(%rip), %rdi
xorb %al, %al
callq _printf
Интересно, а почему так сложно? Я пишу высокопроизводительный код, в котором критично количество инструкций. Мне особенно интересно, почему gcc делает копию моей переменной test
перед передачей ее второму встроенному asm?
Тот же код, скомпилированный с помощью icc, дает гораздо лучшие результаты:
xorl %esi, %esi # test = 0
movl $.L_2__STRING.0, %edi # has something to do with printf
orl $32832, (%rsp) # part of function initiation
xorl %eax, %eax # has something to do with printf
ldmxcsr (%rsp) # part of function initiation
btsq $39, %rsi #106.0
bsrq %rsi, %rdx #109.0
call printf #111.2
несмотря на то, что gcc решает хранить мои переменные в стеке, а не в регистрах, я не понимаю, зачем делать копию test
перед ее передачей второму asm? Если я добавлю test
в качестве переменной ввода / вывода во втором asm
__asm__ ("bsrq\t%1, %0" : "=r" (bsr) , "+rm" (test) );
затем эти линии исчезают.
movq $0, -8(%rbp)
## InlineAsm Start
btsq $39, -8(%rbp)
## InlineAsm End
## InlineAsm Start
bsrq -8(%rbp), %rdx
## InlineAsm End
movq -8(%rbp), %rsi
leaq L_.str(%rip), %rdi
xorb %al, %al
callq _printf
Это gcc облажался с оптимизацией или мне не хватает некоторых важных переключателей компилятора? У меня есть icc для моей производственной системы, но если я решу распространить исходный код в какой-то момент, он также должен будет скомпилироваться с gcc.
используемые компиляторы:
gcc версии 4.2.1 (на основе сборки 5658 Apple Inc.) (сборка LLVM 2336.1.00)
icc Версия 12.0.2
__builtin_clzll(0)
равно 64 при компиляции с помощью gcc и 63 в icc. У меня вопрос в этой теме о том, как оптимизировать встраивание встроенного asm. - person Sergey L.   schedule 26.09.2012main()
и скомпилировать его с различными версиями gcc, начиная с 3.2.3 и заканчивая 4.7.2, и ни одна из них не воспроизводит код, который помещаетtest
в стек на уровне-O3
opt. Пожалуйста, дайте больше контекста. - person FrankH.   schedule 26.09.2012main()
. Это действительно похоже на проблему с комплектом разработчика Apple gcc, потому что gcc в нашем кластере Linux не имеет этой проблемы. См. Мой комментарий ниже. - person Sergey L.   schedule 27.09.2012