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

167

I(n1) = {n1} I(n2) = {n2} I(n3) = {n3}

В соответствие с рассмотренным алгоритмом, находим, что граф F несводим.

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

6.4.2.Анализ потоков данных с помощью интервалов

Проблема, которую мы будем изучать, состоит в том, что для каж-

дого участка и для каждой переменнойA сводимого графа управле-

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

участка .

Будем исходить из априорного утверждения, что анализ потоков данных с помощью интервалов связан с трактовкой графов как упакованных векторных битов. Для вычисления пересечения, объединения и дополнения множеств используются логические операцииAND, OR и NOT на векторах битов.

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

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

.

Определим четыре функции, отображающие участки во множест-

ва.

Определение. Путем вычислений из оператора s1 в оператор s2 назо-

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

Пусть участок программы P. Определим четыре множества, связанные с операторами определения:

1)IN( ) = {d Î P ½ существует такой путь вычисления из опера-

тора определения d в первый оператор в , что никакой оператор на

168

этом пути, кроме может быть первого оператора в , не переопределяет переменную, определенную в d}.

2)OUT( ) = {d Î P ½ существует такой путь вычисления изd в

последний оператор , что никакой оператор на нем не переопределяет переменную, определенную в d}.

3)TRANS( ) = {d Î P ½ переменная, определенная в d, не опре-

деляется никаким оператором в }.

4)GEN( ) = {d Î P ½ переменная, определенная в d, не опреде-

ляется никаким оператором в }.

Таким образом, IN( ) содержит определения, которые могут быть

активными при входе в , OUT( ) содержит определения, которые

могут быть активными при выходе из , TRANS( ) содержит опреде-

ления, передаваемые через без определения в , GEN( ) содержит

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

ходе из .

Легко видеть, что

OUT( ) = (IN( ) Ç TRANS( )) È GEN( ).

Пример. Рассмотрим программу

S1: I ¬ 1

S2: J ¬ 0

S3: J ¬ J + 1

S4: read I

S5: if I < 100 goto S8

S6: write J S7: halt

S8: I ¬ I*I S9: goto S3

Граф программы изображен на рис. 11.29.

Определим для 2 множества IN, OUT, TRANS и GEN. Оператор S1 определяет I, а S1, S2, S3 – путь вычислений, на котором I не определяется (кроме как в S1). Поскольку этот путь ведет изS1 в первый

оператор участка 2, ясно, что S1 Î IN( 2). Аналогично можно показать, что

IN( 3) = {S1, S2, S3, S8}

169

Отметим, что S4 не принадлежит IN( 2), поскольку нет пути вычисления из S4 в S3 не переопределяющего I после S4.

OUT( 2) не содержит S1, поскольку все пути вычисления из S1 в S5 переопределяют I. Далее легко проверить, что

OUT( 2) = { S3, S4}

TRANS( 2) = Æ

GEN( 2) = { S3, S4}

S1: I ¬ 1 B1

S2: J ¬ 0

S3: J ¬ J + 1

S4: read I B2

S5: if I < 100 goto S8

B3

S8: I ¬ I*I

 

S6: write J

B4

 

S9: goto S3

 

S7: halt

 

Рис. 11.29. Граф управления.

Предположим, что 1, …., k – все прямые потомки участка в P. Ясно, что

k k

IN( ) = È OUT( i) = È [(IN( i) Ç TRANS( i)) È GEN( i)].

l =1 l =1

Для вычисления IN( ) можно было бы выписать это уравнение для

каждого участка программы вместе с уравнениемIN( 0) = Æ, где 0 - начальный участок, затем попытаться разрешить систему уравнений. Однако существует более удобный метод, учитывающий преимущества представления графов управления в виде интервалов.

Дадим вначале определения понятий «вход» и «выход» интервала. Определение. Пусть P – программа, а F0 ее граф управления. Пусть

F0, F1,…, Fn – производная последовательность от F0. Каждая вершина в Fi, i ³ 1, является интервалом в Fi-1 и называется интервалом порядка i.

170

Входом интервала порядка 1 служит заголовок интервала. Вход интервала порядка i > 1 – это вход в заголовок интервала. Таким образом, вход любого интервала – это линейный участок исходной программы

P.

Выходом интервала I(n) порядка 1 служит такой последний опера-

тор участка в I(n), что имеет прямого потомка, который является либо заголовком интервала n, либо участком вне I(n). Выход интервала

I(n) порядка i ³ 1 – это последний оператор участка , содержащегося

в I(n) и такого, что в F0 есть дуга, ведущая из либо в заголовок интервала n, либо в участок вне I(n).

Отметим, что каждый участок имеет один вход и ноль или более выходов.

Пример. Пусть F0 – граф управления программы рис. 11.29. С помощью алгоритма разбиения графа на непересекающиеся интервалы, построим его разбиение на интервалы

I1 = I( 1) ={ 1}

I2 = I( 2) = { 2, 3, 4}

Из этих интервалов можно построить первый производный граф управления F1, показанный на рис11.30. Из F1 можно построить его интервалы

I3 = I(I1) = { I1, I2} = { 1, 2, 3, 4}

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

I1

F1

I3

F2

 

I2

Рис. 11.30. Производная последовательность от графа F0.

Интервалами порядка 1 являются I1 и I2. Вход для I2 – это 2. Вход для I3 – это 1. Единственный выход для I1 – это оператор S2. Единст-

171

венный выход для I2 – это оператор S9. Интервалом порядка 2 является

I3 с входом 1. Интервал I3 не имеет выходов.

Продолжим теперь функции IN, OUT, TRANS и GEN на интервалы. Пусть F0, F1,…, Fn - производная последовательность от F0, где F – граф управления для P, а I – интервал некоторого графа Fi, i ³ 1. Введем следующие основные определения:

ìIN( ), если I имеет порядок 1, а - заголовок для I,

1)IN(I) = í

îIN(I¢), если I имеет порядок i > 1, а I¢ заголовок для I.

В2) – 4) ниже s – вход для I.

2)OUT(I, s) = OUT( ), где участок Î I таков, что s – его последний оператор.

3)(а) TRANS( , s) = TRANS( ), если s – последний оператор в

.

(б) TRANS(I, s) – множество таких операторов d Î P, что существует путь без циклов I1, I2,…, Ik, состоящих исключительно из вершин в I, и такая последовательность выходов s1, s2, …, sk для I1, I2,…, Ik, соответственно, что

(i)I1 – заголовок для I,

(ii) в F0 участок sj является прямым предком входа дляIj+1

при 1 £ j < k,

(iii)d Î TRANS(Ij, sj) при 1 £ j £ k,

(iv)sk = s.

Эти условия иллюстрированы на рис. 11.31.

Интервал I

s1

в Fi

 

 

S2

 

Интервалы в Fi-1

 

Sk

s

Рис. 11.31. TRANS(Ij, sj).

172

4)(а) GEN( , s) = GEN( ), если s - последний оператор в .

(б) GEN(I, s) - множество таких операторов d Î P, что существует путь без циклов I1, I2,…, Ik, состоящих исключительно из вершин в I, и такая последовательность выходов s1, s2, …, sk для I1, I2,…, Ik, соответственно, что

(i)d Î GEN(I, s),

(ii)в F0 участок sj является прямым предком входа для Ij+1 при 1 £

j < k,

(iii)d Î TRANS(Ij, sj) при 2 £ j £ k,

(iv)sk = s.

Таким образом, TRANS(I, sj) – это множество определений, которое можно передать с входа I на выход s без переопределения в I. GEN(I, s)

– это множество определенийI, которые без переопределений могут достичь s.

Пример. Рассмотрим F0 на рис 11.29 и F1 и F2 на рис. 11.30. В F1

интервал I2 это { 2, 3, 4}, и он имеет выход S9. Таким образом,

IN(I2) = IN( 2) = {S1, S2, S3, S8} и OUT(I2, s) = OUT( 2) = {S3, S8}. TRANS(I2, S9) = Æ.

GEN(I2, S9) содержит S8, поскольку существует последователь-

ность участков, состоящая только из 2, в которой S8 Î GEN( 3, S9). Кроме того, S3 Î GEN(I2, S9) , поскольку существует последователь-

ность участков 2, 3 с выходом на S5 и S9. Это означает, что S3 Î GEN( 2, S5), 2 – прямой предок участка 3, S3 Î GEN( 3, S9).

На основании этих определений дадим алгоритм вычисленияIN( ) для всех участков программыP. Он обрабатывает программы только со сводимыми графами управления.

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

Вход. Сводимый граф F0 для программы P.

Выход. IN( ) для каждого участка Î P.

Метод.

1)Пусть F0, F1,…, Fk - производная последовательность отF0.

Вычислим TRANS( ) и GEN( ) для всех участков из F0.

2)Для i = 1, 2, …, k последовательно вычисляем TRANS(I, s) и GEN(I, s) для всех интервалов порядка i и выходов s для I. Рекурсивное определение этих функций гарантирует, что это можно сделать.

3)Полагаем IN(I) = Æ, где I – одиночный интервал порядкаk. Устанавливаем i=k.

173

4)Для всех интервалов порядка i выполняем следующее. Пусть I

={I1, …, In} – интервал порядка i (I1, …, In – интервалы порядка i-1 или участки, если i=1). Можно считать, что эти интервалы перечислены в том порядке, в котором из них составлен интервалI в алгоритме опре-

деления непересекающихся интервалов. Иными словами, I1 – это заголовок и для каждогоj > 1 множество {I1, …, Ij-1} содержит все вершины из Fi-1, являющиеся прямыми предками интервала Ij.

(а) Пусть s1, s2, …, sr – выходы интервала I, каждый из которых принадлежит участку в F0, являющемуся прямым предком входа для I. Полагаем

r

IN(I1) = IN(I) È È GEN(I, si)

i=1

(б) Для всех s Î I1 полагаем

OUT(I1, s) = (IN(I1) Ç TRANS(I1, s) È GEN(I, s))

(в) Для j=2, 3, …, n пусть sr1, sr2, …, srkr – выходы интервала Ir, 1 £ r < j, каждый из которых принадлежит участку вF0, являющемуся пря-

мым предком для входа Ir. Полагаем

IN(Ij) = È OUT(Ir, srl)

r,l

OUT(Ij, s) = (IN(Ij) Ç TRANS(Ij, s)) È GEN(Ij, s)

для всех интервалов, входящих в Ij.

5)Если i = 1 остановиться. В противном случае уменьшить i на 1

ивернуться к шагу 4).

Пример. Применим данный алгоритм к графу управления на рис. 11.29. Для четырех участков в F0 GEN и TRANS вычисляются просто. Результаты приведены в табл. 11.6.

Таблица 11.6.

Участок

GEN

TRANS

1

{S1, S2}

Æ

2

{S3, S4}

Æ

{S8}

{S2, S3}

3

Æ

{S1, S2, S3, S4, S8}

4

 

 

Поскольку 3 определяет только переменнуюI 3 «убивает» предыдущие ее определения, но передает определение переменнойJ, а именно S2 и S3. Поскольку никакой из участков не определяет переменную дважды, все операторы внутри участка принадлежат множеству GEN для данного участка.

174

Интервал I1, состоящий из одного участка 1, имеет один выход – оператор S2. Так как пути в I1 тривиальны, то GEN(I1, S2) = {S1, S2} и TRANS(I1, S2) = Æ.

Интервал I2 имеет один выход S9. GEN(I2, S9) = {S3, S8} и TRANS(I2, S9) = Æ.

Теперь можно начать вычисление функцииIN. Первоначально IN(I3) = Æ. Затем к двум подынтервалам в I3 можно применить шаг4) алгоритма. Это можно сделать только в порядкеI1, I2. На шаге 4а) вычисляем IN(I1) = IN(I3) = Æ, на шаге 4в) –

OUT(I1, S2) = (IN(I1) Ç TRANS(I1, S2)) È GEN(I1, S2) = {S1, S2}.

Далее, на шаге 4в)

IN(I2) = OUT(I1, S2) = {S1, S2}.

Проходя по интервалам порядка 1, мы должны рассмотреть состав-

ляющие для I1 и I2. Интервал I2 состоит из участков 2, 3 и 4, которые в таком порядке и можно рассматривать. На шаге 4а)

IN( 2) = IN(I2) È GEN(I1, S9) = {S1, S2, S3, S8}.

На шаге 4б)

OUT( 2, S5) = IN( 2) Ç TRANS( 2, S5)) È GEN( 2, S5) = {S3, S4}.

Поскольку S5 ведет к 3, находим

IN( 3) = OUT( 2, S5) = {S3, S4},

а так как S5 ведет к 4, то

IN( 4) = OUT( 2, S5) = {S3, S4}.

И так,

IN( 1) = Æ

IN( 2) = {S1, S2, S3, S8}. IN( 3) = {S3, S4}

IN( 4) = {S3, S4}.

Индукцией по порядку интервалов можно доказать, что

1)TRANS(I, s) – множество таких операторов определенийd Î P, что существует путь из первого оператора заголовка дляI вплоть до s, вдоль которого ни один из операторов не переопределяет переменную, определенную в d,

2)GEN(I, s) - множество таких операторов определенийd, что существует путь из d в s, вдоль которого ни один из операторов не переопределяет переменную, определенную в d.

Индукцией по числу переменных шага 4) можно показать, что