Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Руководство по языку Паскаль 1.doc
Скачиваний:
12
Добавлен:
22.04.2019
Размер:
2.48 Mб
Скачать

Глава 23. Автоматическая оптимизация

─────────────────────────────────────────────────────────────────

В Borland Pascal выполняется несколько различных типов опти-

мизации кода, начиная от свертывания констант и вычисления бу-

левских выражений по короткой схеме и кончая эффективной компо-

новкой. Рассмотрим некоторые виды оптимизации.

Свертывание констант

─────────────────────────────────────────────────────────────────

Если участвующие в операции операнды представляют собой

константы перечислимого типа, то в Borland такое выражение вычис-

ляется во время компиляции. Например, выражение:

Х := 3 + 4 * 2

приведет к генерации такого же кода, как выражение Х := 11, а вы-

ражение:

S := 'In' + 'Out'

генерирует тот же код, что S := 'InOut'.

Аналогично, если операнды функций Abs, Sqr, Succ, Pred, Odd,

Lo, Hi и Swap представляют собой константы перечислимого типа, то

функция вычисляется во время компиляции.

Если индексом массива является константа или выражение, сос-

тоящее из констант, то адрес элемента вычисляется во время компи-

ляции. Например, доступ к элементу Dаtа[5,5] так же эффективен,

как доступ к простой переменной.

Слияние констант

─────────────────────────────────────────────────────────────────

Использование одной и той же строковой константы два или бо-

лее раз приводит к генерации только одной копии константы. Напри-

мер, два или более оператора Write('Dоnе') в одной и той же части

программы приведет к ссылке на одну и ту же копию строковой конс-

танты 'Donе'.

Вычисление по короткой схеме

─────────────────────────────────────────────────────────────────

В Borland Pascal реализуется вычисление булевского выражения

по короткой схеме. Это означает, что вычисление булевского выра-

жения прекращается, как только результат всего булевского выраже-

ния становится очевидным. При этом обеспечивается минимальное

время выполнения и, обычно, минимальный размер объектного кода.

Вычисление по короткой схеме делает также возможным вычисление

конструкций, которые иначе были бы недопустимыми. Например:

B.Pascal 7 & Objects/LR - 406 -

while (I<=Length(S)) and (S[I]<>' ') do

Inc(I);

while (P<>nil) and (P^.Value<>5) do

P:=P^.Next;

В обоих случаях, если первая проверка имеет значение Falsе,

вторая проверка не вычисляется.

Противоположным вычислению по короткой схеме является полное

вычисление, которое можно выбрать с помощью директивы компилятора

{$В+}. В этом случае обеспечивается вычисление каждого операнда

булевского выражения.

Параметры-константы

─────────────────────────────────────────────────────────────────

Там, где это возможно, вместо параметров-значений следует

использовать параметры-константы. Параметры-константы настолько

же эффективны, что и параметры-переменные, а во многих случаях

превосходит их по эффективности. В частности, параметры-константы

генерируют получение кода меньшего размера и программы с ними вы-

полняются быстрее, чем программы с параметрами-значениями струк-

турного и строкового типов.

Параметры-константы более эффективны, чем параметры-значе-

ния, поскольку компилятору не приходится генерировать копии фак-

тических параметров на входе в процедуры и функции. Значения па-

раметров должны быть скопированы в локальные переменные, так что

модификации формальных параметров не приведут к модификации фак-

тических параметров. Поскольку формальные параметры-константы мо-

дифицироваться не могут, компилятору нет необходимости копировать

фактические параметры, что экономит код и пространство в стеке.

Устранение избыточной загрузки указателей

─────────────────────────────────────────────────────────────────

В определенных ситуациях генератор кода Borland Pascal может

устранить избыточные инструкции загрузки указателей, уменьшая тем

самым размер кода и обеспечивая более быстрое его выполнение.

Когда генератор кода может обеспечить, что указатель остается

постоянным на участке линейного кода (кода, не содержащего пере-

ходов на него), и когда указатель уже загружен в пару регистров

(например, ES:DI), генератор кода устраняет ненужные загрузки

указателей в блоке кода.

Указатель считается константой, если он получается из пара-

метра-переменной (параметры-переменные всегда передаются как ука-

затели) или из ссылки на переменную оператор with. Поэтому опера-

тор with часто является более эффективным (но никогда не будет

менее эффективным), чем запись для каждой ссылки на элемент пол-

ностью уточненной переменной.

B.Pascal 7 & Objects/LR - 407 -

Подстановка констант множественного типа

─────────────────────────────────────────────────────────────────

Когда правая часть оператор in является константой множест-

венного типа, компилятор генерирует включение проверки с помощью

команд CMP. Такие поставляемые проверки более эффективны чем код,

генерируемый в противном случае соответствующими булевскими выра-

жениями с использованием операций отношения. Например, оператор:

if ((Ch >= 'A') and (Ch <: 'Z')) or

((Ch >= 'a') and (Ch <= 'z')) then ...;

менее читаем и менее эффективен чем

if Ch in ['A'..'Z', 'a'..'z'] then ...;

Поскольку свертывание констант применяется к константам мно-

жественного типа также как к константам других типов, можно ис-

пользовать описания const без потери эффективности.

const

Upper = ['A'..'Z'];

Lower = ['a'..'z'];

Alpha = Upper + Lower;

С учетом данных описаний оператор if генерирует тот же код,

что и в случае предыдущего оператор if:

if Ch in Alpha then ... ;

Малые множества

─────────────────────────────────────────────────────────────────

Для операций с малыми множествами компилятор генерирует

очень эффективный код. Малое множество - это множество с нижним

порядковым значением в диапазоне 0..7 и верхним порядковым значе-

нием в диапазоне 0..15. Например, следующие множества TByteSet и

TWordSet являются малыми множествами:

type

TByteSet = set of 0..7;

TWordSet = set of 0..15;

Операции с малыми множествами, такие как объединение (+),

разность (-), пересечение (*) и проверка на включение in генери-

руют с помощью операций AND, OR, NOT и TEST вместо вызова библио-

тек исполняющей системы инструкции машинного кода. Аналогично,

стандартные процедуры Include и Exclude генерируют при применении

к малым множествам поставляемый код.

Порядок вычисления

─────────────────────────────────────────────────────────────────

Стандартами Паскаля допускается, что операнды в выражении

B.Pascal 7 & Objects/LR - 408 -

часто вычисляются в порядке, отличном от того, в котором они за-

писаны (слева направо). Например, оператор:

I := F(J) div G(J)

где F и G - функции целого типа, приводит к тому, что G вычисля-

ется перед вычислением F, так как это позволяет компилятору полу-

чить более оптимальный объектный код. Важно, поэтому, чтобы выра-

жение никогда не зависело от какого-то конкретного порядка

вычисления встроенных функций. Если вернуться к предыдущему при-

меру, то для того, чтобы вызвать функцию F перед функцией G, мож-

но использовать временную переменную:

T := F(J);

I := T div G(J);

Исключением из этого правила является вычисление по короткой

схеме (разрешенное директивой компилятора {$B-}, при котором опе-

ранды булевского типа, связанные операциями and или оr, всегда

вычисляются слева направо.

Проверка на допустимость границ

─────────────────────────────────────────────────────────────────

Присваивание константы переменной и использование константы

в качестве значения параметра проверяется во время компиляции на

допустимость нахождения в заданных границах. При этом генерирует-

ся такой код, что во время выполнения таких проверок не делается.

Например, Х := 999, где Х - переменная байтового типа (Bytе),

приводит к ошибке компиляции.

Использование сдвига вместо умножения

─────────────────────────────────────────────────────────────────

Операция X*C, где C - константа, являющаяся степенью числа

2, приводит к генерации объектного кода, в котором используется

инструкция Shl (сдвиг влево).

Аналогично, когда размерность массива представляет собой

степень числа 2, то для вычисления индексных выражений использу-

ется инструкция Shl (а не инструкция Мul).

Автоматическое выравнивание на границу слова

─────────────────────────────────────────────────────────────────

По умолчанию Borland Pascal выравнивает все переменные и ти-

пизованные константы, превышающие по размеру 1 байт, на границу

машинного слова. На всех 16-разрядных процессорах семейства 80х86

выравнивание на границу слова означает более быстрое выполнение,

поскольку доступ к элементам размером в слово или четным адресам

осуществляется быстрее, чем к словам по нечетному адресу.

Выравнивание данных управляется директивой компилятора $A.

B.Pascal 7 & Objects/LR - 409 -

По умолчанию в состоянии {$A+} переменные и типизованные констан-

ты выравниваются указанным выше образом. В состоянии {$A-} ника-

ких действий по выравниванию не производится.

Примечание: Дальнейшие подробности приведены в Главе 2

("Директивы компилятора") "Справочного руководства програм-

миста".

Удаление неиспользуемого кода

─────────────────────────────────────────────────────────────────

Операторы, о которых известно, что они никогда не будут вы-

полняться, не включаются в объектный код. Данные выражения, нап-

ример, не приведут к генерации объектного кода:

if false then

statement { оператор }

while false do

statement

Эффективная компоновка

─────────────────────────────────────────────────────────────────

Компоновщик Borland Pascal автоматически удаляет неиспользу-

емый код (по процедурам), то есть процедуры и функции, являющиеся

частью скомпилированной программы, но к которым нет обращений, не

включаются в файл типа .EXE. Процедуры, функции, переменные и ти-

пизованные константы, участвующие в процессе компиляции, но ссыл-

ки на которые отсутствуют, удаляются из файлa .EXE. Удаление не-

используемого кода выполняется по процедурам, а удаление неис-

пользуемых данных - по секциям, где эти данные описываются.

Рассмотрим следующую программу:

program SmartLink;

const

H: array[0..15] of char = '0123456789ABCDEF';

var

I,J : integer;

X,Y : real;

var

S: string[79];

var

A: array[1..10000] of integer;

procedure P1:

begin

A[1] = 1;

end;

procedure P2;

begin

I := 1;

B.Pascal 7 & Objects/LR - 410 -

end;

procedure P3;

begin

S := 'Borland Pascal';

P2;

end;

begin

P3;

end;

Основная программа вызывает процедуру P3, которая вызывает

процедуру P2, поэтому обе процедуры P2 и P3 включаются в файл

.EXE. Поскольку P2 ссылается на первый раздел описания перемен-

ных, а P3 ссылается на второй раздел описание переменных, пере-

менные I, J, X, Y, S также включаются в выполняемый файл. Однако

на процедуру P1 никаких ссылок нет, а включенные в выполняемый

файл процедуры не ссылаются на переменные Н и A, поэтому эти объ-

екты удаляются.

Эффективная компоновка имеет особую ценность в связи с ис-

пользованием модулей, которые реализуют библиотеки процедур и

функций. Примером такого модуля является стандартный модуль Dos,

который содержит ряд процедур и функций. При этом программа редко

использует все эти процедуры. Если она использует только одну или

две процедуры или функции, то только эти процедуры включаются в

полученный в результате код.

B.Pascal 7 & Objects/LR - 411 -

───────────────────────────────────────────────────────────────────────

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]