11.2.1. Intel 80x86

Вверх  Предыдущий  Следующий

Здесь приводится список методов оптимизаций, используемых в компиляторе:

1.При оптимизации для указанного процессора (-Op1, -Op2, -Op3) выполняется следующее:

В операторе case выполняется проверка, является ли оптимальным для выполнения переход по таблице или последовательность условных переходов.

Определяется ряд стратегий, когда выполняется визуальная оптимизация, например, movzbl (%ebp), %eax будет заменено на xorl %eax,%eax; movb (%ebp),%al для Pentium и PentiumMMX.

2.При оптимизации по скорости (-OG, по умолчанию) или размеру (-Og) будет сделан выбор между использованием наиболее коротких инструкций (по размеру), таких как enter $4, или длинных инструкций subl $4,%esp для оптимизации по скорости. Если требуется наименьший размер, данные выравниваются по минимальной границе. Если требуется скорость, данные выравниваются по наиболее эффективной границе, насколько это возможно.

3.Быстрые оптимизации (-O1): активируют визуальный оптимизатор.

4.Медленные оптимизации (-O2): также активируют общие выражения ликвидации (раньше называлось «перезагрузка оптимизатора»).

5.Неопределённые оптимизации (-OoUNCERTAIN ): с этим переключателем алгоритм общих выражений ликвидации может быть форсирован для создания неопределённых оптимизаций.

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

ПРИМЕЧАНИЕ

Если неопределённые оптимизации включены, CSE алгоритм предполагает, что

Если что-то записано в локальный/глобальный регистр или параметр процедуры/функции, это значение не перезапишет значение, для которого имеется указатель.

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

Практическим следствием этого является то, что вы не можете использовать неопределённые оптимизации, если вы читаете/записываете переменные как напрямую, так и использованием указателей (включая как параметры Var, так и указатели).

Следующий пример создаёт плохой код, если вы включите неопределённые оптимизации:

Var
  temp: Longint;
 
Procedure Foo(Var Bar: Longint);
Begin
  If (Bar = temp) Then
    Begin
        Inc(Bar);
        If (Bar <> temp) then Writeln('bug!')
    End
End;
 
Begin
  Foo(Temp);
End.

В этом примере создаётся плохой код, потому что вы работаете с переменной Temp как через её имя. Так и через указатель, используя в этом случае параметр Bar, который является указателем на Temp в вышеописанном коде.

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

Пример

Type TMyRec = Record
    a, b: Longint;
End;
PMyRec = ^TMyRec;
 
TMyRecArray = Array [1..100000] of TMyRec;
PMyRecArray = ^TMyRecArray;
 
Var MyRecArrayPtr: PMyRecArray;
  MyRecPtr: PMyRec;
  Counter: Longint;
 
Begin
New(MyRecArrayPtr);
For Counter := 1 to 100000 Do
  Begin
    MyRecPtr := @MyRecArrayPtr^[Counter];
    MyRecPtr^.a := Counter;
    MyRecPtr^.b := Counter div 2;
  End;
End.

Это пример создаёт правильный код, потому что глобальная переменная MyRecArrayPtr не доступна непосредственно, а только через указатель (MyRecPtr в данном примере).

В заключение можно сказать, что вы можете использовать неопределённые оптимизации только тогда, когда вы знаете, что делаете.