Иерархии сборки x86
Я пытаюсь хорошо разбираться в ассемблере x86 и задавался вопросом, был ли быстрый и короткий эквивалент movl $1, %eax
. Это, когда я думал, что список идиом, часто используемых на этом языке, может быть хорошей идеей.
Это может включать в себя предпочтительное использование xorl %eax, %eax
в отличие от movl $0, %eax
или testl %eax, %eax
от cmpl $0, %eax
.
О, и любезно отправьте один пример за сообщение!
Ответы
Ответ 1
Вот еще одна интересная "идиома". Надеюсь, все знают, что разделение - это большая потеря времени даже по сравнению с умножением. Используя небольшую математику, можно умножить на инверсию константы, а не на ее деление. Это выходит за рамки трюков. Например, чтобы разделить на 5:
mov eax, some_number
mov ebx, 3435973837 // 32-bit inverse of 5
mul ebx
Теперь eax был разделен на 5 без использования медленного кода операции div. Вот список полезных констант для раздела бесстыдных украденных из http://blogs.msdn.com/devdev/archive/2005/12/12/502980.aspx
3 2863311531
5 3435973837
7 3067833783
9 954437177
11 3123612579
13 3303820997
15 4008636143
17 4042322161
Для чисел, не входящих в список, вам может потребоваться сделать сдвиг заранее (разделить на 6, shr 1, а затем умножить на инверсию 3).
Ответ 2
Использование LEA
для, например, умножение, например:
lea eax, [ecx+ecx*4]
для EAX = 5 * ECX
Ответ 3
на x64:
xor eax, eax
для
xor rax, rax
(первый также неявно очищает верхнюю половину rax
, но имеет меньший код операции)
Ответ 4
Вы можете как и как оптимизировать сборку. Тогда вы должны спросить, для чего вы оптимизируете: размер или скорость? Во всяком случае, здесь моя "идиома", замена для xchg
:
xor eax, ebx
xor ebx, eax
xor eax, ebx
Ответ 5
Расширение моего комментария:
Для нескромного процессора, такого как Pentium Pro, xorl %eax, %eax
, похоже, имеет зависимость от %eax
и, следовательно, должен дождаться, когда будет доступно значение этого регистра. Более поздние процессоры фактически имеют дополнительную логику, чтобы распознать эту инструкцию как не имеющую зависимости.
В инструкциях incl
и decl
устанавливаются некоторые флаги, но остальные остаются неизменными. Это худшая ситуация, если флаги моделируются как один регистр для переупорядочения команд: любая инструкция, которая считывает флаг после incl
или decl
, должна рассматриваться как зависящая от incl
или decl
( в случае, если он читает один из флагов, который устанавливает эта инструкция), а также в предыдущей инструкции, устанавливающей флаги (в случае, если он читает один из флагов, который эта инструкция не устанавливает). Решение состояло бы в том, чтобы разделить регистр флагов на два и рассмотреть зависимости с этим более тонким зерном... но у AMD была лучшая идея и полностью удалены эти инструкции из 64-битного расширения, которое они предложили несколько лет назад.
Что касается ссылок, я нашел это либо в руководствах Intel, для которых бесполезно предоставлять ссылку, потому что они находятся на корпоративном веб-сайте, который реорганизован каждые шесть месяцев, или на сайте Agner Fog: http://www.agner.org/optimize/#manuals
Ответ 6
В цикле...
dec ecx
cmp ecx, -1
jnz Loop
является
dec ecx
jns Loop
Быстрее и короче.
Ответ 7
Используя SHL
и SHR
для умножения/деления на мощность 2
Ответ 8
Другой (помимо xor
) для
mov eax, 0 ; B800000000h
есть
sub eax, eax ; 29C0h
Обоснование: меньший код операции
Ответ 9
Не знаю, считается ли это как идиома, но на большинстве процессоров до i7
movq xmm0, [eax]
movhps xmm0, [eax+8]
или, если SSE3 доступен,
lddqu xmm0, [eax]
быстрее считываются из неизолированной ячейки памяти, чем
movdqu xmm0, [eax]
Ответ 10
Самая ранняя ссылка на деление на инвариантные целые числа, которая больше, чем просто обратное умножение:
Торбьёрн Гранлунд Королевского технологического института в Стокгольме. Ознакомьтесь с его публикациями.