2012-05-09 2 views
9

Я работаю над очень низким уровнем части приложения, в котором производительность имеет решающее значение.Почему инструкции по сборке содержат умножения в инструкции «lea»?

При исследовании сгенерированного сборки, я заметил следующую инструкцию:

lea eax,[edx*8+8] 

Я привык видеть дополнения при использовании ссылки на память (например, [EDX + 4]), но это первый раз, когда я вижу умножение.

  • Означает ли это, что процессор x86 может выполнять простые умножения в инструкции lea?
  • Это умножение влияет на количество циклов, необходимых для выполнения инструкции?
  • Является ли умножение ограничено степенями 2 (я бы предположил, что это так)?

Заранее спасибо.

+5

Обратите внимание, как это умножается на мощность двух. – Mysticial

+0

См. Также [Что предназначено для инструкции LEA?] (Https://stackoverflow.com/questions/1658294/whats-the-purpose-of-the-lea-instruction) для более общих вещей об использовании его для других вещей чем строго адресные вычисления. –

ответ

11

Чтобы развернуть на мой комментарий и ответить на остальные вопросы ...

Да, он ограничивается силами двух. (2, 4 и 8). Поэтому не требуется множитель, так как это просто сдвиг. Дело в том, что он быстро генерирует адрес из индексной переменной и указатель - где тип данных - это простое 2, 4 или 8 байтовое слово. (Хотя его часто злоупотребляют и для других целей.)

Что касается количества циклов, которые необходимы: согласно Agner Fog's tables, инструкция на рабочем столе постоянна на некоторых машинах и переменной на других.

На Sandy Bridge есть штраф в 2 цикла, если он «сложный или рип-родственник». Но он не говорит, что означает «сложный» ... Поэтому мы можем только догадываться, если вы не станете эталоном.

+0

Спасибо. Также понравилась ссылка на Agner Fog (хотя ссылка в вашем ответе не кажется правильной). – Patrick

+0

К сожалению, плохая копия + вставка. Исправлено. – Mysticial

+0

@Mysticial - AFAIK, это не 'lea'. Проверьте мой ответ :) – ArjunShankar

8

Собственно, это не что-то специфическое для инструкции lea.

Этот тип адресации называется Scaled Addressing Mode. Умножение достигается за счет битового сдвига, который является тривиальным:

A Left Shift

Вы могли бы сделать «масштабируемого решения» с mov тоже, к примеру (обратите внимание, что это не та же самая операция, единственное сходство тот факт, что ebx*4 представляет собой адрес умножение):

mov edx, [esi+4*ebx] 

(источник: http://www.cs.virginia.edu/~evans/cs216/guides/x86.html#memory)

Для более полного списка, см this Intel document. Таблица 2-3 показывает, что допускается масштабирование 2, 4 или 8. Ничего больше.

Задержка (с точки зрения количества циклов): Я не думаю, что это должно быть затронуто вообще. Сдвиг - это вопрос соединений, и выбор между тремя возможными сдвигами зависит от стоимости одного мультиплексора.

+1

Это 'mov' получает ** содержимое ** памяти при сгенерированном« адресе », тогда как' lea' получает ** сгенерированный «адрес» ** – ninjalj

+0

@ninjalj - Точка * не *, что делает mov, но тот факт, что «масштабированная адресация» (т.е. указательная математика с умножением указателя на 2,4,8) не является специфичной для 'lea'. – ArjunShankar

+0

@ninjalj - И так как мне кажется, что формулировка той части моего ответа была несколько расплывчатой, я объяснил, что «мов» несколько лучше теперь. Благодарю. – ArjunShankar

6

Чтобы расширить ваш последний вопрос:

ограничен ли умножение степеней 2 (я бы предположить, что это так)?

Обратите внимание, что вы получите результат base + scale * index, так что в то время как scale должен быть 1, 2, 4 или 8 (размер x 86 целочисленных типов данных), вы можете получить эквивалент умножения на некоторых различных констант используя тот же регистр, как base и index, например:

lea eax, [eax*4 + eax] ; multiply by 5 

Это используется компилятором, чтобы сделать снижение прочности, например: для умножения на 100, в зависимости от опций компилятора (целевой модели процессора, варианты оптимизации), вы можете получить:

lea (%edx,%edx,4),%eax ; eax = orig_edx * 5 
lea (%eax,%eax,4),%eax ; eax = eax * 5 = orig_edx * 25 
shl $0x2,%eax   ; eax = eax * 4 = orig_edx * 100 
+1

Смотрите этот вопрос: http://stackoverflow.com/questions/6120207/imul-or-shift-instruction, почему вы должны оставить сокращение силы компилятору. – ninjalj

+1

+1, мне нравится второй ответ на этот связанный вопрос. :) – Mysticial

Смежные вопросы