идиомы ассемблера x86

Я пытался хорошо освоить язык ассемблера x86, и мне было интересно, есть ли быстрый и короткий эквивалент movl $1, %eax. Именно тогда я подумал, что список идиом, часто используемых в языке, возможно, будет хорошей идеей.

Это может включать предпочтительное использование xorl %eax, %eax вместо movl $0, %eax или testl %eax, %eax вместо cmpl $0, %eax.

О, и, пожалуйста, размещайте по одному примеру в сообщении!


person Community    schedule 15.04.2010    source источник
comment
movl $1, %eax довольно быстрый и короткий. На некоторых процессорах xorl %eax, %eax на самом деле медленнее, чем movl $0, %eax. На других incl %eax медленнее, чем addl $1, %eax. Если вы собираетесь писать ассемблер в 2010 году, вы должны знать, для какой архитектуры вы пишете, и, следовательно, выбрать свой диалект (в соответствии с лингвистической метафорой).   -  person Pascal Cuoq    schedule 15.04.2010
comment
@Pascal Cuoq, не могли бы вы объяснить, какие факторы влияют на такую ​​разницу в производительности? Я особенно озадачен тем, что incl %eax медленнее, чем addl $1, %eax. Кроме того, если бы вы могли указать мне какую-либо ссылку, в которой подробно описывается такое поведение, я был бы признателен!   -  person susmits    schedule 15.04.2010
comment
Для всех архитектур x86 в 2010 году xor eax,eax быстрее или эквивалентен, но в любом случае короче. Взгляните на stackoverflow.com/questions/1396527/. Это почти со времен 486 года.   -  person Gunther Piez    schedule 07.03.2011
comment
Голосование за закрытие слишком широкое. Упомянутые отдельные примеры уже поднимались в других сообщениях.   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 12.08.2015


Ответы (10)


Вот еще одна интересная "идиома". Надеюсь, все знают, что деление — это большая трата времени даже по сравнению с умножением. Используя немного математики, можно умножить на обратную константу вместо того, чтобы делить на нее. Это выходит за рамки трюков shr. Например, чтобы разделить на 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).

person Community    schedule 16.04.2010

Использование LEA, например. умножение, например:

lea eax, [ecx+ecx*4]   

для EAX = 5 * ECX

person Community    schedule 15.04.2010
comment
Кстати: это очень медленно для NetBurst, потому что Intel убрала бочкообразный переключатель, чтобы получить более высокие тактовые частоты. По иронии судьбы, когда вышел P4, это все еще было задокументировано в руководствах Intel по оптимизации. - person Jörg W Mittag; 15.04.2010
comment
Спасибо за комментарий ре. скорость. Я понимаю, что идиома не обязательно означает оптимизацию. Тем не менее, как идиома, я думаю, LEA довольно широко (ab) используется. - person PhiS; 15.04.2010
comment
Ну, это это оптимизация. И даже официально рекомендован Intel. Просто после того, как официально рекомендовали его в течение 15 лет, они внезапно выпускают новый процессор, на котором он работал медленно, что, по сути, требует перекомпиляции каждой программы, когда-либо написанной. К счастью, NetBurst умер быстрой и мучительной смертью, и все современные микроархитектуры являются эволюцией Pentium III, а не Pentium4, так что все современные процессоры снова имеют механизм переключения бочек. По сути, он есть у всех процессоров Intel начиная с 80385 и всех Athlon, только у Pentium4 его нет. - person Jörg W Mittag; 16.04.2010

on x64:

xor eax, eax 

за

xor rax, rax

(первый также неявно очищает верхнюю половину rax, но имеет меньший код операции)

person Community    schedule 15.04.2010

Вы могли бы, а также как оптимизировать в сборке. Тогда вам придется спросить, для чего вы оптимизируете: размер или скорость? Во всяком случае, вот моя "идиома", замена xchg:

xor eax, ebx
xor ebx, eax
xor eax, ebx
person Community    schedule 15.04.2010
comment
ВНИМАНИЕ: Если eax == ebx - Оба будут обнулены! - person LiraNuna; 15.04.2010
comment
Вы уверены, что? 42 ^ 42 = 0; 42 ^ 0 = 42; 0 ^ 42 = 42 - person Sparafusile; 15.04.2010

Расширение моего комментария:

Для неразборчивого процессора, такого как Pentium Pro, xorl %eax, %eax кажется зависимым от %eax и поэтому должен ждать, пока значение этого регистра станет доступным. Более поздние процессоры фактически имеют дополнительную логику для распознавания этой инструкции как не имеющей никаких зависимостей.

Инструкции incl и decl устанавливают некоторые флаги, но оставляют без изменений другие. Это наихудшая ситуация, если флаги моделируются как один регистр для переупорядочивания инструкций: любая инструкция, которая считывает флаг после incl или decl, должна рассматриваться как зависящая от incl или decl (в случае, если она читает один из флагов). который устанавливает эта инструкция), а также на предыдущую инструкцию, которая устанавливает флаги (в случае, если она читает один из флагов, которые эта инструкция не устанавливает). Решением было бы разделить регистр флагов на два и рассмотреть зависимости с более мелким зерном... но у AMD была идея получше, и они полностью удалили эти инструкции из 64-битного расширения, которое они предложили несколько лет назад.

Что касается ссылок, я нашел это либо в руководствах Intel, на которые бесполезно давать ссылку, поскольку они находятся на корпоративном веб-сайте, который реорганизуется каждые шесть месяцев, либо на сайте Агнера Фога: http://www.agner.org/optimize/#manuals

person Community    schedule 15.04.2010

На петлях...

  dec     ecx 
  cmp     ecx, -1       
  jnz     Loop              

is

  dec     ecx  
  jns     Loop 

Быстрее и короче.

person Community    schedule 16.04.2010
comment
Разве цикл .Loop не проще? - person Hasan Saad; 19.11.2013
comment
@Hasan Saad: Это так, но он медленнее, использование цикла в x86 не рекомендуется. - person GJ.; 19.11.2013
comment
Большое спасибо :) Я понятия не имел об этом, так что спасибо за информацию. Высоко оценен :) - person Hasan Saad; 20.11.2013

Использование SHL и SHR для умножения/деления на степень 2

person Community    schedule 15.04.2010
comment
Его можно распространить и на другие номера. Например, y*320 = (y << 8) + (y << 6). Однако это не всегда может быть быстрее, чем простое умножение. Зависит от вашего процессора. - person csl; 23.06.2016

Еще один (рядом с xor) для

mov eax, 0   ; B800000000h

is

sub eax, eax ; 29C0h

Обоснование: меньший код операции

person Community    schedule 15.04.2010

Не знаю, считается ли это идиомой, но на большинстве процессоров до i7

movq xmm0, [eax]
movhps xmm0, [eax+8]

или, если доступен SSE3,

lddqu xmm0, [eax]

быстрее для чтения из невыровненной области памяти, чем

movdqu xmm0, [eax]
person Community    schedule 15.04.2010

Самое раннее упоминание о делении на инвариантные целые числа, которое представляет собой нечто большее, чем просто обратное умножение, находится здесь: Торбьорн Гранлунд из The Королевский технологический институт в Стокгольме. Посмотрите его публикации

person Community    schedule 07.03.2011