Оптимизация для процессоров семейства Pentium: 23. Уменьшение размера кода (все процессоры)

Дата публикации 22 авг 2002

Оптимизация для процессоров семейства Pentium: 23. Уменьшение размера кода (все процессоры) — Архив WASM.RU

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

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

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

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

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

Пример:

Код (Text):
  1.  
  2. MOV EBX,DS:[100000] / ADD EBX,DS:[100004] ; 12 байт

Уменьшаем размер:

Код (Text):
  1.  
  2. MOV EAX,100000 / MOV EBX,[EAX] / ADD EBX,[EAX+4] ; 10 байт

Преимущество использования указателя становится еще более очевидным, если вы используете его много раз. Хранение данных в стеке и использование EBP или ESP в качестве указателя сделает ваш код меньше, чем если бы вы использовали абсолютные адреса, если только, конечно, ваши данные в пределах +/-127 байтах указателя. Использование PUSH и POP для записи и чтения временных данных еще короче.

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

Примеры:

Код (Text):
  1.  
  2.     PUSH 200      ; 5 байт
  3.     PUSH 100      ; 2 байт
  4.  
  5.     ADD EBX,128   ; 6 байт
  6.     SUB EBX,-128  ; 3 байт

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

Примеры:

Код (Text):
  1.  
  2.     MOV EAX, 0              ; 5 байт

Можно заменить на:

Код (Text):
  1.  
  2.     XOR EAX,EAX             ; 2 байта

И

Код (Text):
  1.  
  2.     MOV EAX, 1              ; 5 байтов

Можно заменить на:

Код (Text):
  1.  
  2.     XOR EAX,EAX / INC EAX   ; 3 байта

или:

Код (Text):
  1.  
  2.     PUSH 1 / POP EAX        ; 3 байта

И

Код (Text):
  1.  
  2.     MOV EAX, -1             ; 5 байта

Можно заменить на:

Код (Text):
  1.  
  2.     OR EAX, -1              ; 3 байта

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

Пример:

Код (Text):
  1.  
  2.         MOV     [mem1],200             ; 10 байтов
  3.         MOV     [mem2],200             ; 10 байтов
  4.         MOV     [mem3],201             ; 10 байтов
  5.         MOV     EAX,100                ;  5 байтов
  6.         MOV     EBX,150                ;  5 байтов

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

Код (Text):
  1.  
  2.         MOV     EBX, OFFSET mem2       ;  5 байтов
  3.         MOV     EAX,200                ;  5 байтов
  4.  
  5.         MOV     [EBX+mem1-mem2],EAX    ;  3 байта
  6.         MOV     [EBX],EAX              ;  2 байта
  7.         INC     EAX                    ;  1 байт
  8.         MOV     [EBX+mem3-mem2],EAX    ;  3 байта
  9.         SUB     EAX,101                ;  3 байта
  10.         LEA     EBX,[EAX+50]           ;  3 байта

Остерегайтесь задержек AGI в инструкции LEA (для PPlain и PMMX).

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

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

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

Пример:

Код (Text):
  1.  
  2.     MOV EAX,DS:[100000]  меньше, чем  MOV EBX,DS:[100000]
  3.     ADD EAX,1000         меньше, чем  ADD EBX,1000

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

Примеры:

Код (Text):
  1.  
  2.     MOV EAX,[array][EBX]  меньше, чем  MOV EAX,[array][EBX*4]
  3.     MOV EAX,[EBP+12]      меньше, чем  MOV EAX,[ESP+12]

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

Код (Text):
  1.  
  2.     MOV EAX,[EBX]    меньше чем  MOV EAX,[EBP], но
  3.     MOV EAX,[EBX+4]  такого же размера, как и MOV EAX,[EBP+4]

Также адресация со сдвигом бывает выгоднее, чем адресация с масштабированием:

Код (Text):
  1.  
  2.     LEA EAX,[EBX+EBX]  короче, чем  LEA EAX,[2*EBX]
© Агнер Фог, пер. Aquila

0 682
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532