Анимация
JavaScript
|
Главная Библионтека 382 Ассемблер в задачах защиты информа .ga 6. Оптимизация для процессоров семейства Pentium 383 Например, можно изменить стзтовый адрес процедуры, чтобы избежать проблемы байтных границ. Расположение сегмента кода на фанице парафафа облегчает их нахождение Можно использовать директиву ALIGN 16 перед началом цикла, тогда ассембле поместит необходимую последовательность инсфукций NOP или им подобных, чтоб,, осуществить выравнивание. Больщинство ассемблеров используют инсфукцию XCHq ЕВХ, ЕВХ в качестве двухбайтного заполнителя (иногда ее называют "двухбайтны)!, NOPom"). Кому бы ни прищла в голову эта идея, лучще данную инсфукцию не использовать, потому что она занимает больще времени, чем два NOPa на больщинстве про-цессоров. Если цикл выполняется многократно, необходимо заботиться о том, какую инсфукцию использовать в качестве заполнителя. Можно использовать инсфукции, которые делают что-нибудь полезное, например обновляют регисфы, дабы избежать задержек при чтении регисфа. Например, если используется ЕВР для адресации операн-дов и он дастаточно редко изменяется, можно использовать команды MOV ЕВР,ЕВР или ADD ЕВР, О в качестве заполнителя, чтобы снизить влияние выщеупомянутых задержек. Можно также в качестве заполнителя использовать команду FXCH ST(0), потому что она не создает никакой нафузки на усфойства выполнения, при условии что ST(0) содержит верное значение с плавающей запятой. Помочь может перефуппировка инсфукций таким образом, чтобы переход 16-байтных фаниц между БДИ не вносил задержек. Однако это может стать очень сложной задачей и найти приемлемое рещение не всегда возможно. Еще одна возможность оптимизации - манипуляция с длинами используемых инструкций. Иногда можно заменить одну инсфукцию другой, имеющей отличную от нее длину кода операции. Транслятор ассемблера всегда выбирает наиболее короткую версию инсфукции. Например, DEC ЕСХ занимает один байт, SUB ЕСХ, Г - фи байта, однако можно приметить и 6-байтовую версию, которая даст аналогичный результат, используя чиловой парамеф размером в двойное слово. SUB ЕСХ, 9999 ORG $-4 DD 1 Инсфукции с операндами в памяти можно сделать на один байт длинее с помошью SIB-байта, но самым легким путем сделать инсфукцию на один байт длинее будет добавление сегментного префикса DS (DB 3Eh). Микропроцессоры обычно принимают избыточные и ничего не значащие префиксы (не считая LOCK), если длина инсфукЦИИ не превыщает 15-байт. Даже инсфукции без операндов памяти могут иметь сегментный префикс. Поэтому если нужно, чтобы инсфукция DEC ЕСХ была два байта длиной, можно записать: DB 3Eh DEC ЕСХ Следует помнить, что могут быть потери при раскодировке инсфукции, если у окажется более одного префикса. Возможно, что инсфукции с ничего не значашим!* факсами, особенно префиксами повторения и закрытия, будут использоваться в бу-!!LmHX процессорах для расщирения их набора, когда не останется свободных кодов, (.дедовательно, использование сегментных префиксов с уже существующими инсфук- циями более безопасно. 5Д6. Переименование регистров (РРго, Р2 и РЗ) 6.16.1. Уничтожение зависимостей Переименование регисфов - это технология, используемая в современных микро-[фоцессорах для минимизации взаимного влияния результатов инсфукций при их парал-леиьном выполнении. MOV ЕАХ, IMUL ЕАХ, MOV [МЕМ2 MOV ЕАХ, INC ЕАХ MOV [МЕМ4 [МЕМ1] 6 ] , ЕАХ [МЕМЗ] 1 , ЕАХ Здесь последние фи инсфукции независимы от фех первых в том смысле, что результат первых никак не влияет на результат последних. Чтобы оптимизировать этот код на процессорах Р1 для параллельного исполнения, фебовалось привлечение дополнительных регисфов. РРго, Р2 и РЗ делают это автоматически. Они, в нащем примере, выделят новый теневой регисф для ЕАХ второй фойке инсфукций. Таким образом, инсфукция MOV [МЕМ4], ЕАХ может быть выполнена до окончания обработки медленной инсфукции IMUL. Переименование регисфов осуществляется автоматически. Новый временный регисф назначается как псевдоним постоянному регисфу каждый раз, когда инсфукция пишет в него. Например, инсфукция INC ЕАХ использует один временный регисф для ввода и другой временный регисф для вывода. Это, разумеется, не решает полностью проблему зависимостей инсфукций, но имеет определенное значение для последующих считываний из регисфа, о чем будет вестись разговор ниже. Все регисфы общего назначения, указатель на стек, регисф флагов, регисфы плавающей апятой, регисфы ММХ, регисфы ХММ и сегментные регисфы могут быть переименованы. Конгрольные слова и слово статуса плавающей запятой не могут быть переименованы. Общей практикой установки значений регисфов в ноль является использование Операций типа XOR ЕАХ,ЕАХ или SUB ЕАХ, ЕАХ. Эти инсфукции не распознаются ак независимые от предыдущего значения регисфа, что приводит к замедлению начала MOV ЕАХ, SUB ЕСХ, INC ЕВХ MOV EDX, ADD ESI, ADD EDI, EBX EAX [EAX; Эти шесть инсфукций генерируют 1 моп каждая. Предположим, что первые фи а идут через RAT одновременно. Они читают регистры ЕВХ, ЕСХ и ЕАХ. Но так как изводиться запись в ЕАХ до того, как начинается из него чтение, то это не фебует н ких затрат. Следующие три мопа читают ЕАХ, ESI, ЕВХ, EDI и ЕСХ. Так как ЕАХ, I и ЕСХ были изменены предыдущим триплетом и еще не были выфужены, из них мо свободно читать, и поэтому учитываются только ES1 и EDI и, соответственно, нет за, жек и во втором триплете. Если инструкцию SUB ЕСХ, ЕАХ в первом фиплете з; нить на СМР ЕСХ, ЕАХ, тогда в ЕСХ не будет производиться запись и, следовател будет происходить задержка во втором фиплете при чтении ESI, ED1 и ЕСХ. Подобг же образом, если инсфукцию TNC ЕВХ в первом триплете поменять на NOP, возниь задержка во втором фиплете при чтении ES1, ЕВХ и ED1. Ни один МОП не может читать больше, чем из двух регисфов. Поэтому все инст: ции, читающие больше, чем из двух регисфов, разбиваются на два или больше мопа. Чтобы подсчитать количество читаемых регисфов, нужно учесть все регистры, кс рые используются инсфукцией. Сюда входят все целочисленные регистры, флаго! регисфы, указатель стека, регисфы плавающей запятой и регистры ММХ. Реги ХММ нужно принимать за два, кроме тех случаев, когда используется только его час например в командах ADDSS и MOVHLPS. Сегментные регисф и указатель на инстр цию не учитываются. Например, в SETZ AL должен учитываться флаговый регистр, не AL. В ADD ЕВХ, ЕСХ учитываются и ЕВХ, и ЕСХ, но не регисф флагов, поэте в него производится только запись. В команде PUSH ЕАХ считывается ЕАХ и указат( стека, а затем осуществляется запись в последний. Инсфукщтя FXCH является особым случаем. Она работает с помощью переимено ния, но не считывает никаких значений, поэтому она не попадает под действие какого-лт правила о задержке чтения из регстра. Инсфукция FXCH ведет себя как один моп, котор не читает, не пишет в регисф, когда дело касается правил задержек чтения из регисфа. Не следует путать фиплеты мопов с декодируемыми фуппами. Последние могут гене] ровать от одного до шести мопов, и в случае если раскодировываемая фуппа имеет фи ин РУкции и генерирует фИ мопа, нет никакой гарантии, что эти фи мопа попадут в RAT вмес была произведена запись в одном фиплете, можно свободно читать как минимум в последующих. Если выфузка (writeback) была задержена перефуппировкой, медле инструкциями, цепочками зависимости, задержкой кэша или по какой-то другой, 51ше, то из регисфа можно свободно считывать значение еще некоторое время. их исполнения. Чтобы избавиться от зависимости от предшествующих инструкций, еде-дует использовать MOV ЕАХ, О. Переименование регистров контролируется таблицей псевдонимов регистров (НЛТ register alias table) и буфером перефуппировки (ROB - reorder buffer). Мопы из декоде, ров поступают в RAT через очередь, затем в ROB, а после в резервационную станцщ, (reservation station). RAT может обрабатывать только 3 мопа за такт. Это означает, что суммарная производительность процессора не может превышать 3 мопа за такт. Практически нет никаких офаничений на количество переименований. RAT может переименовывать фи регисфа за такт и может переименовать один и тот же регистр три раза за один такт. 6.16.2. Задержки чтения регистров Но существует другое офаничение, которое может быть весьма серьзеным - то, что за один такт могут быть считаны значения только из двух постоянных регистров. Это Офаничение относится ко всем регистрам, которые могут быть использованы в инсфук-циях, не считая тех, в которые эти инсфукции только пишут. MOV [EDI + ESI], ЕАХ MOV ЕВХ, [ESP + ЕВР] Первая инсфукция генерирует два мопа: один считывает ЕАХ, а другой - EDI и ES1. Вторая инсфукция генерирует один моп, который читает ESP и ЕВР. ЕВХ не учитывается, поскольку инструкция только пишет в него. Предположим, что эти фи мопа обрабатываются RAT. Обозначит термином фиплет фуппу из фех последовательных мопов. обрабатываемых RAT. Так как ROB может обрабатывать только два чтения из постоянных регисфов за такт, а нам нужно пять чтений, наш фиплет будет задержен на два дополнительных такта, прежде чем он попадет в резервационную станцию. При фех или четырех чтениях из постоянных регисфов он был бы задержен на один такт. Из одного регистра в одном фиплете можно читать больше одного раза без ущерба Если осуществить замену предыдущих инсфукций на: MOV [EDI + ESI], EDI MOV ЕВХ, [EDI + EDI] В этом случае произойдет только два чтения из регистров (EDI и ESI) и триплет не будет задержен. Регисф, в который будет произведена запись текущим мопом, сохраняется в ROB поэтому из него можно свободно читать, пока он не будет выфужен, что занимает, меньшей мере, фи такта, а чаще и еще больше. Выфузка из ROB является финальной стадией выполнения, когда значение в регисфе становится актуальным. Другими слова ми, возможно произвольное считывание из регисфа в RAT без задержек, если их значение еще не стало доступным модулю выполнения, это значит, что из регисфа, в которы" ит дополнительный мои, поэтому его стоит применять только, если среднее предпола гаемое количество предотвращенных задержек чтения больше 1/3. Для инсфукций, которые генерируют больше одного мопа, можно узнать количестве мопов, чтобы сделать предсказание возможных задержек чтения регисфа более точным Ниже приводятся наиболее общие случаи. 6.16.2.1 Запись в память. Запись в память генерирует два мопа. Первый (в порт 4) -это операция сохранения, считывающая регисф, который нужно сохранить, второй мог вычисляет адрес памяти, при считывании любых регисфов-указателей. MOV [EDI], ЕАХ Первый моп читает ЕАХ, второй читает EDI. FSTP QWORD PTR [ЕВХ+8*ЕСХ] Первый моп читает ST(0), второй мои читает ЕВХ и ЕСХ. 6.16.2.2. Чтение и модифицирование. Инсфукция, которая считывает операнд из па мяти и модифицирует регисф с помощью какой-либо арифметической или логическо! операции, генерирует два мопа. Первый (порт 2) - это инсфукция зафузки из памяти читающая любой регисф-указатель, второй мои - это арифметическая инсфукция (пор-1 или 2), читающая и пишущая в регисф назначения и, возможно, модифицирующш регисф флагов. ADD ЕАХ, [ESr+20] Первый МОП читает ESI, второй мои читает ЕАХ и пишет ЕАХ и регисф флагов. 6.16.2.3. Чтение/модифицирование/запись. Такие инсфукции генерируют четыре мо па. Первый мои (порт 2), считывание регисфа-указателя, второй (порт О или 1) читает i производит запись в исходный регисф и, возможно, пишет в регисф флагов, фетий moi (порт 4) считывает только временный результат, который не учитывается здесь, четвер тый (порт 3) читает все регисфы-указатели снова. Так как первый и четвертый регист] не могут идти в RAT вместе, получаем преимущество от того, что они читают один и то же регисф-указатель. OR [ESI+EDI], ЕАХ Первый МОП читает EST и EDI, второй читает ЕАХ и пишет в ЕАХ и в регисф флагоЕ третий читает только временный результат, четвертый читает ESI и EDI снова. Вне зави симости о того, в каком порядке эти мопы пойдут в RAT, можно быть увереными, чт МОП, который читает ЕАХ, пойдет вместе с тем, который читает ESI и EDI. Поэтому за Держка чтения регисфа неизбежна в этой инсфукции, если только один из регисфов н был изменен ранее. 6.16.2.4. Сохранение регисфа в стек. Сохранение регисфа в стек генерирует 3 мопа. Первы (порт 4) - это инсфукция сохранения, чтение регисфа. Второй мои (порт 4) генерирует адре( счтътая указатель на стек. Третий (порт О или 1) вычитает размер слова из указателя на ста читая и модифицируя его. Очередь между декодерами и RAT так коротка (10 мопов), что невозможно предположить, что задержки чтения регистров не оказывают влияния на декодеры или какие-тс изменения в выводе декодеров не задерживают RAT. Очень трудно предсказать, какие мопы пройдут через RAT параллельно, если очеред, не пуста, а для оптимизированного кода очередь должна быть пуста только после непра ВИЛЬНО предсказанного перехода. Несколько мопов, генерируемых одной инструкцией, не обязательно пойдут через RAT одновременно; мопы просто выбираются последовательно из очереди по три за раз. Последовательность не нарушается предсказанным переходом: мопы до и после перехода могут пойти через RAT одновременно. Только неправильно предсказанный переход сбросит очередь и начнет все сначала, поэтому три следующих мопа точно попадут в RAT вместе. Если три последовательных мопа читают более, чем из двух регистров, было бы лучше, чтобы они не попадали одновременно в RAT. Вероятность того, что они попадут туда одновременно - одна третья. Задержка чтения трех или четырех регистра в одной тройке мопов - один такт. Можно считать задержку в один такт эквивалентом загрузки еще трех мопов в RAT. С вероятностью в 1/3, что три мопа пойдут в RAT вместе, средняя задержка будет эквивалентна 3/3 = 1 мои. Чтобы посчитать среднее время, которое займет для некоторого кода проход через RAT, следует к к количеству мопов добавить число потенциальных задержек чтения регистров и поделить на три. Нет смысла убирать задержки путем добавления дополнительных регистров, пока нет точной уверенности в том, какие мопы пойдут в RAT одновременно. В ситуациях, когда требуется достижение производительности в 3 мопа за такт, ограничение в чтении только двух постоянных регистров за такт может стать узким местом, которое будет трудно обойти. Приведем возможные пути избавления от задержек чтения регистров. Ш Располагать мопы, которые считывают один и тот же регистр последовательно друг за другом, чтобы они попадали в один триплет. Ш Располагать мопы, которые считывают разные регистры подальше друг от друга, чтобы они не могли попадать в один триплет. а Располагать мопы, которые читают регистр не дальше трех-четырех триплетов от инструкции, которая записывает или изменяет этот регистр, чтобы он не был вы-фужен прежде, чем будут произведены все необходимые операции чтения (не важно, если есть переход, если он будет правильно предсказан). Если есть основания полагать, что запись в регисф будет задержена, можно смело читать из него еще некоторое количество инструкций. Использовать абсолютные адреса вместо указателей, чтобы снизить количество считываемых регисфов. в Можно спровоцировать переименование регисфа в фиплете, если это не вызывает задержку, чтобы предотвратить задержку чтения для этого регисфа в одном или более следующих за ним фиплетов: MOV ESP,ESP /... / MOV EAX,[ESP+8]. Этот метод сто- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 [ 62 ] 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |