Функция write()
не имеет возвращаемого значения и не имеет побочных эффектов (не записывается ни в одну глобальную переменную, никаких системных вызовов, а устанавливается только некоторые локали, которые отбрасываются при возврате функции). Вы можете и должны оптимизировать его до пустой функции, just like gcc does.
global write
write:
ret
Давайте представим, что ваша функция возвращает переменную write1
, так что вы должны вычислить его.
gcc -Og
(оптимизация для отладки) делает приятным читаемым asm, который не сохраняет/перезагружается из памяти все время. gcc -m32 -Og -fverbose-asm -masm=intel
emits:
# see the godbolt link for colour-coded mapping of source lines to asm lines
write(int, unsigned short):
mov edx, DWORD PTR [esp+4] # bitpos, bitpos
lea eax, [edx+15] # tmp98,
test edx, edx # bitpos
cmovns eax, edx # tmp98,, bitpos, bitpos
sar eax, 4 # tmp99,
neg eax # tmp101
sal eax, 4 # tmp102,
mov ecx, eax # tmp102, tmp102
add ecx, edx # posA, bitpos
movzx eax, WORD PTR [esp+8] # D.2591, sample
sar eax, cl # D.2591, posA
ret
Обратите внимание, как он загружает параметры функции из стека, потому что они параметры функции, а не глобал. (Ваши ссылки на код [bitpos]
, глобальная, а не первая позиция в стеке после обратного адреса, [esp+4]
.) 64-битная ABI передает аргументы в регистры, поэтому вы получаете более чистый код.
Код условного перемещения существует потому, что семантика C для целочисленного деления отрицательного числа дает разные результаты из арифметического сдвига вправо (они вращаются по-разному). Поскольку idiv
очень дорогой по сравнению со сменой, все равно стоит использовать дополнительные инструкции для настройки сдвига. Если bitpos
был неподписанным, он мог бы просто использовать shr
.
С полной оптимизацией, gcc находит более эффективный способ делать вещи и складывает часть арифметики вместе. (т. е. разделить на 16, а затем умножить на 16, округлить до ближайшего кратного 16, реализован с одним and
, чтобы скрыть эти биты.)
Мораль истории: вы всегда можете посмотреть на компилятор вывод для вдохновения о том, как что-то сделать, и часто будет видеть трюки, о которых вы не думали изначально.
Попробуйте использовать 'sar' вместо' shr'. Это сохраняет знак. – drum
Хорошая ссылка на ассемблер должна указывать на то, что единственным регистром, указывающим изменение переменной, является [в CL] (http://x86.renejeschke.de/html/file_module_x86_id_285.html). – usr2564301
Вы можете заменить 'битпот/16' на« битпоты >> 4' и 'pos * 16' с' pos << 4'. –