Анимация
JavaScript


Главная  Библионтека 

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

Ассемблер в задачах защиты

гую для тех, которые их не поддерживают (см. разд. 6.27.10, чтобы узнать, как лить, поддерживает ли процессор условные переходы). Р

Потери из-за неправильного предсказания перехода могут быть настолько выс что имеет смысл заменить их условными перемещениями данных, даже если это б стоить несколько дополнительных инструкций. У инструкций условного перехода

один недостаток: они делают цепочки зависимости длинее. Условное перем ждет готовности обоих операндов-регистров, даже если требуется только один из Условное перемещение ждет готовности трех операндов: флаг условия и еще дц ранда перемещения. Нужно точно знать, может ли один из этих трех операндов вести к задержкам из-за ошибок в работе с кешем или из-за цепочек зависимости F флаг условия доступен задолго до операндов операции перемещения, можно исполь-зовать инструкции перехода, потому что возможное неправильное предсказание может быть преодолено, пока ожидается готовность операндов перемещения. В тех ситуаци ях, где нужно долго ждать операнд перемещения, который потом еще может и не понадобиться, инструкция перехода будет быстрее, чем условный переход, несмотря на потери, связанные с возможным неправильным предсказанием. Обратная ситуация возникает, когда флаг условия задерживается, а оба операнда перемещения доступны ранее. В этой ситуации условный перенос данных более предпочтителен, чем инструкция перехода, если вероятно неправильно предсказание.

623. Уменьшение размера кода

Как уже говорилось в разделе 6.7, размер кэша кода в зависимости от поколения процессоров Pentium равен 8 или 16 килобайтам. Если есть подозрение, что критические части кода не поместятся в кэш, тогда можно подумать о том, чтобы уменьшить их размер.

32-битный код обычно больше по размеру, чем 16 битный, потому что в нем адреса и константы занимают 4 байта, а в 16-битном режиме только два. Тем не менее, в 16-битном коде есть другие потери, такие как префиксы и проблемы с соседнеми словами памяти (см. разд. 6.10.2). Некоторые дополнительные методы уменьшения размера кода будут обсуждаться в этом разделе.

Адреса перехода, адреса данных и константы занимают меньше места, если их значе ние находится между-128 до-(-127.

Для адресов переходов это означает, что короткие переходы занимают два байта, в время как переходы более чем 127 байт занимают 5 байтов, если переход безусловны и 6 байтов, если условный. g.

Таким же образом адреса данных занимают меньше места, если они могут выражены как указатель в интервале от -128 до -t-127.

0"У,..V?.!.4"?,Я."P?Jf..:°P° семейства Pentium 4., g

пример

M OV ЕВХ,DS: [ 100000 ] / ADD ЕВХ, DS : [ 10 О О О 4 ] ; 12 байт уменьшаем размер:

(<0V ЕАХ, 100000 / MOV ЕВХ, [ЕАХ] / ADD ЕВХ,[ЕАХ + 41 ; 10 байт еимуЩество использования указателя становится еще более очевидным, если он зуется повторно. Хранение данных в стеке и использование ЕВР или ESP в каче-у(азателя сделает код меньше, чем если бы использовались абсолютные адреса. ?1ользование PUSH и POP для записи и чтения временных данных еще оказывается ще короче.

]онстанты могут также занимать меньше места, если их значения лежат в диапазоне -78 и +- Большинство инструкций с числовыми операндами имеют короткую форму, je операнд - это один байт со знаком.

Примеры

PUSH 200 ; 5 байт

PUSH 100 ; 2 байт

ADD ЕВХ,128 ; 6 байт SUB ЕВХ,-128 ; 3 байт

Самая важная инструкция с числовым операндом, у которой нет короткой формы, это MOV. Примеры

MOV ЕАХ, О ; 5 байт

Можно заменить на: XQR ЕАХ,ЕАХ

MOV ЕАХ, 1 Можно заменить на:

; 2 байта ; 5 байтов

или:

XOR ЕАХ,ЕАХ / INC ЕАХ ; 3 байта

PUSH 1 / POP ЕАХ

MOV ЕАХ, -1 ""« заменить на:

OR ЕАХ, -1

; 3 байта ; 5 байта ; 3 байта

"«Теги" ™ " используется несколько раз, ее можно зафу-

""Укц! числовым операндом иногда можно заменить на арфметическую

и«o, если известно значение регисфа до MOV. Рфметическую



5 Оптимизащи;! для процессоров семейства Pentium ....................л.......................................................

Пример

MOV [meml],200 ; 10 байтов

MOV [mem2],200 ; 10 байтов

MOV [тетЗ],201 ; 10 байтов

MOV ЕАХ,100 ; 5 байтов

MOV ЕВХ,150 ; 5 байтов

Предполагая, что значения meml и тетЗ находятся в пределах -128/127 байтов ет2, это можно изменить на:

ЕВХ, OFFSET mem2

байтов

ЕАХ,200

байтов

[EBX+meml-mem2],ЕАХ

байта

[ЕВХ],ЕАХ

байта

байт

[EBX+mem3-mem2],ЕАХ

байта

ЕАХ,101

• 3

байта

ЕВХ, [ЕАХ+50]

; 3

байта

Следует остерегаться задержек AGI в инструкции LEA (для Р1 и РММХ).

Также стоит учитывать то, что разные инструкции имеют разную длину. Следующие инструкции занимают только один байт и поэтому очень привлекательны: PUSH reg, POP reg, INC reg32, DEC reg32. INC и DEC с 8-битовыми регистрами занимают 2 байта, поэтому INC ЕАХ короче, чем TNC AL.

XCHG EAX,reg также однобайтовая инструкция и поэтому занимает меньше места, чем MOV EAX,reg, но это медленнее.

Некоторые инструкции занимают на один байт меньше, когда они используют аккумулятор, а не другой регистр:

MOV ЕАХ,DS: [ 1 0 00 0 0 ] меньше, чем MOV ЕВХ,DS: [ 10 О О О О] ADD ЕАХ,1000 меньше, чем ADD ЕВХ,1000

Инструкции с указателями занимают на один байт меньше, чем когда они используют адресацию по базе (не ESP) со сдвигом, а не косвенную адресацию с масштабированием, или и то, и другое вместе, или ESP в качестве базы:

MOV ЕАХ, [array] [ЕВХ] меньше, чем MOV ЕАХ, [агray] [ЕВХМ] MOV ЕАХ,[ЕВР+12] меньше, чем MOV EAX,[ESP+12]

Инструкции с ЕВР в качестве базы без смещения занимают на один байт больше, чем при использовании других регистров:

MOV ЕАХ,[ЕВХ] меньше чем MOV ЕАХ,[ЕВР], но MOV ЕАХ,[ЕВХ+4] такого же размера, как и MOV ЕАХ,[ЕВР+4] Также адресация со сдвигом бывает выгоднее, чем адресация с масштабированием. LEA ЕАХ,[ЕВХ+ЕВХ] короче, чем LEA ЕАХ,[2*ЕВХ]

24. Работа с числами с плавающей запяггой (PlnPMMX)

Инструкции с плавающей запятой не могут спариваться так, как это делают целочис-.jjHHbie инструкции, не считая некоторых случаев, определяемых следующими правилами:

первая инструкция (выполняющаяся в U-конвейере) должна быть FLD, FADD, FSUB, FMUL, FDIV, FCOM, FCHS или FABS; g вторая инструкция (в V-конвейере) должна быть FXCH;

I инструкция, следующая за FXCH, должна быть инструкцией плавающей запятой, иначе FXCH спарится несовершенно и займет лишний такт.

Это особенное спаривание играет важную роль, что вкратце будет объяснено ниже.

Хотя, как правило, инструкции с плавающей запятой не могут спариваться, лногие из них конверизуются, т. е. одна инструкция может начать выполнение до того, как будет закончена предыдущая инструкция.

FADD ST (1) ,ST (0) FADD ST(2),ST(0) FADD ST (3) , ST (0) FADD ST(4),ST(0)

такты 1-3

такты 2-4

такты 3-5

такты 4-6

Очевидно, что выполнение двух инструкциий не может пересекаться, если второй инструкции нужен результат первой. Так как почти все инструкции плавающей запятой работают с вершиной стека регистров ST(0), возможностей сделать их независимыми друг от друга не очень много. Решение этой проблемы состоит в переименовании регистров. Инструкция FXCH в реальности не обменивает содержимое двух регистров, она только меняет их имена. Инструкции, которые помещают или извлекают значение из стека регистров также работают с помощью переименования. Переименование реги-(тров на Pentium настолько хорошо оптимизировано, что даже желательно использование переименования регистров. Переименование регистров никогда не вызывает задержек, возможно даже переименовать регистр более чем один раз за такт, например, когда спаривается FLD шти FCOMPP с FXCH.

Правильно используя инструкции FXCH, можно создать условия, чтобы инструкции плавающей запятой были более независимыми друг от друга.

[al]

; такт

FADD

[a2]

; такт

,; такт

FADD

[b2]

; такт

[cl]

; такт

FADD

[c2]

; такт



FXCH

ST (2)

; такт

FADD

[аЗ]

; такт

FXCH

ST(1)

; такт

FADD

[b3]

; такт

8-10

FXCH

ST(2)

; такт

FADD

[c3]

; такт

9-11

FXCH

ST (1)

; такт

FADD

[a4]

; такт

10-12

FXCH

ST(2)

; такт

FADD

[b4]

; такт

11-13

FXCH

ST(1)

; такт

FADD

[c4]

; такт

12-14

FXCH

ST(2)

; такт

В вышеприведенном примере создаются три независимые ветви. Каждая инструкция FADD занимает 3 такта, поэтому можно каждый такт начинать с выполнения новой FADD. Когда начинается выполнение ветви а, есть время, чтобы начать выполнение двух новых инструкций FADD в ветвях Ъ и с до возвращения к ветви а, поэтому каждый третий FADD принадлежит той же ветви. Можно использовать инструкции FXCH каждый раз, когда необходимо, чтобы ST(0) стал равен регистру, который принадлежет к желаемой ветви. Как видно из примера, это образует регулярную последовательность, но нужно уяснить, что инструкции FXCH повторяются с периодом, равным двум, в то время как у ветвей период равен трем. Поэтому следует проработать этот пример, чтобы понять, где находится какой из регистров.

Все версии инструкций FADD, FSUB, FMUL и FILD занимают три такта и конвейеризу-кэтся, поэтому вышеописанный метод можно применять и с этими инструкциями. Использование переменных в памяти не отнимает больше времени, чем использование регистров, если переменная в памяти находится в кэше первого уровня и правильно выравнена.

У всех правил есть исключения, и у вышеизложенного правила они тоже есть: нельзя начать выполнение инструкции FMUL на следующем такте после другой инструкции FMUL, потому что FMUL не может спариваться совершенно. Рекомендуется поместить некоторую инструкцию между двумя FMUL.

[al]

; такт 1

; такт 2

[cl]

; такт 3

FXCH

sr(2)

; такт 3

FMUL

[a2]

; такты 4-

FXCH

; такт 4

FMUL

[b2]

; такты 5-

FXCH

ST (2)

; такт 5

FMUL

[c2]

; такты 7-

FXCH

; такт 7

FSTP

[аЗ]

; такты 8-

(задержка)

(задержка]

FXCH ; такт 10 (неспарены)

FSTP [ЬЗ] ; такты 11-12 FSTP [сЗ] ; такты 13-14

Здесь есть задержка между FMUL [Ь2] и между FMUL [с2], потому что другая FMUL

между

FMULaMH.

[al]

; такт

FMUL

[a2]

; такт

; такт

FMUL

[b2]

; такт

[cl]

; такт

FMUL

[c2]

; такт

FXCH

ST(2)

; такт

FSTP

[аЗ]

; такт

FSTP

[ЬЗ]

; такт

9-10

FSTP

[сЗ]

; такт

11-12

В другом случае можно поместить FADD, FSUB или что-нибудь еще между инструкциями FMUL, чтобы избежать задержек.

Если выполнение инструкций с плавающей запятой пересекается, требуется, чтобы были независимые ветви, выполнение которых можно совместить. Если задана только одна большая формула, которую надо вычислить, можно попробовать просчитать ее части формулы. Например, чтобы сложить шесть чисел, эту операцию нужно разделить на две ветви с тремя числами в каждой и сложить две ветви в конце.

; такт 1

FADD

; такты 2-4

; такт 3

FADD

; такты 4-6

FXCH

; такт 4

FADD

; такты 5-7

FXCH

; такт 5

FADD

; такты 7-9

(задержка

FADD

; такты 10-12

(задержка

Здесь есть задержка в один такт перед FADD [fj, потому что она ожидает результат, выполнения FADD .[d] и задержка в два такта перед последней FADD, потому что он; ожидает результата FADD [fj. Более поздняя задержка может быть опущена путел заполнения её несколькими целочисленными инструкциями, но с первой задержкой это "О не получится, так как целочисленная инструкция в этом месте приведет к тому, чт( FXCH будет спариваться несовершенно.

Первой задержки можно избежать, создав три ветви вместо двух, но это будет стоит дополнительной FLD, в этом случае не будет выигрыша, если только не нужно буде •«адывать 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