Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Теория языков программирования методов трансляции.-1.pdf
Скачиваний:
13
Добавлен:
05.02.2023
Размер:
1.36 Mб
Скачать

138

вершин, возникающих из S, минимально и значит метка корня минимальна.

6.3. Программы с циклами

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

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

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

Главная цель – уменьшение времени выполнения объектной программы.

6.3.1.Модель программы

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

Существует пять основных типов операций: присвоение, переход, условный переход, ввод-вывод и останов.

1)Оператор присвоения – это условие вида A ¬ Q B1 B2 . . Br, где А

-переменная, B1, B2,. . Br – переменные либо константs, q - r местная операция.

2)Оператор перехода

goto <метка>

где <метка>- цепочка букв. Будем предполагать, что одна и та же метка может быть только у одного оператора программы.

3) Условный оператор

if A <условие> В goto <метка>

где А и В - переменные или константы, а <отношение >- бинарное отношение, такое как <,<=,=,¹.

4) Оператор ввода-вывода – это либо оператор чтения вида

139

read A

где А переменная, либо оператор записи write B

где В - переменная, либо константа.

5) Оператор останова – это команда halt.

Пример:

if A r B goto L

означает, что между текущими значениямиА и В выполняется отношение r, то управление передается оператору, помеченному L. В противном случае управление следующему оператору.

Оператор определения – это оператор вида read А или A ¬ q B1 B2 .

. Br.

Оба этих оператора определяют переменную А. Сделаем несколько предположений.

Переменная – это либо простая переменная, либо индексирование простой переменной, либо константой, например А(1), А(2), …, А(i), либо А(j).

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

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

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

Будем считать , что входные переменные программы – это те, которые связаны с оператором чтения, а выходные – с оператором записи.

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

Это определение эквивалентности обобщает эквивалентность бло-

ков. Предположим, что два блока 1=(P1, I1, U1) и 2 = (P2, I2, U2) эквивалентны. Преобразуем блоки 1 и 2 в программы P1 и P2. Иными словами, поставим операторы чтения для переменныхI1 и I2 перед P1 и P2 соответственно, а операторы записи для переменныхU1 и U2 – после P1 и P2. Затем к каждой программе присоединим оператор останова. Операторы записи к P1 и P2 нужно добавить так, чтобы каждая выходная переменная печаталась хотя бы один раз и последова-

140

тельности напечатанных значений дляP1 и P2 были одинаковыми.

Поскольку блоки 1 и 2 эквивалентны, это всегда можно сделать. Легко видеть, что программы P1 и P2 эквивалентны независимо от

того, что именно берется в качестве множества входных присвоения и как интерпретируются функции, представленные операторами входящими в P1 и P2. Например, можно взять в качестве входного множества префиксных выражений и считать, что применение операцииq к выражениям e1, e2,... er дает qe1e2 er.

Однако, если 1 и 2 не эквивалентны, но всегда найдется множество типов данных для переменных и интерпретации для операторов, приводящих к тому, что программы P1 и P2 будут вырабатывать различные выходные последовательности.

Пример. Рассмотрим программу (алгоритм Евклида). Выходом может быть наибольший общий делитель двух положительных чиселp и q:

read p read q

цикл: r ¬ remainder(p, q) (остаток от деления) if r = 0 goto выход

p ¬ q q ¬ r

goto цикл

выход: write q halt.

Если, например, входным переменным p и q присвоить значения 72 и 76 соответственно, то при обычной интерпретации выходная переменная к моменту выполнения оператора записи будет иметь значение 8. Таким образом, значением этой программы для входного присвоения p ¬ 72, q ¬ 56 служит «последовательность», вырабатываемая выходной переменной q.

Если заменить оператор goto цикл на if q¹0 goto цикл, то получим эквивалентную программу. Это следует из того, что оператора goto цикл нельзя достичь, если в четвертом операторе не выполняется условие r¹0. Поскольку в шестом оператореq принимает значение r, то выполнение седьмого оператора равенство q=0 невозможно.

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

141

Пример. Для некоторых типов данных можно считать, что a*a=0, тогда и только тогда, когда a=0. Если принять такой закон, то новая эквивалентная программа будет:

read p read q

цикл: r ¬ remainder(p, q) t ¬ r * r

if t = 0 goto выход p ¬ q

q ¬ r goto цикл

выход: write q halt

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

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

сформулированной задачи будет нахождение такой эквивалентной программы P², что ожидаемое число машинных команд, меньше числа команд в P.

В большинстве программ одни последовательности операторов исполняются значительно чаще других. Кнут на большом числе программ Фортрана обнаружил, что в типичной программе около половины времени тратится менее чем на 4% программы. Таким образом, практике достаточно применять оптимизирующие процедуры только к многократно проходимым участкам программы. В частности оптимизация может состоять в том, что операторы перемещаются из многократно проходимых областей, редко проходимые, а число операторов в самой программе не меняется или даже не учитывается.

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