Возможные усовершенствования триадной формы записи

Из предыдущего параграфа видно, что для удовлетворения всех требований, которые предъявляются к промежуточному языку с точки зрения оптимизации, в триадную форму представления программ необходимо вне­сти ряд существенных изменений.

Рассмотрим вначале возможности представления в триадной записи всех элементарных вычислений из вы­ражений или подвыражений, в которых имеется несколь­ко соседних знаков операций с одинаковыми приоритетами. В рассуждениях для простоты используем выражения, в которых имеется подряд только два знака, арифметических операций с одинаковыми приоритетами. Однако наши рассуждения будут справедливы и в тех случаях, когда число соседних операций с одинаковыми приоритетами больше двух.

Рассмотрим выражение общего вида

A=B Q1 C Q2 D, (*)

где Q1 и Q2 — знаки обобщенных арифметических операций с одинаковыми приоритетами. ОПЗ этого выражения будет иметь вид

ABC Q1 D Q2=

Заметим, что для выявления идентичности двух элементарных вычислений не имеет значения, какой вид имеет соответствующая триадная строка: mi Q a, b или mi Q b, a.

clip_image002

Если Q1 не является операцией деления или вычитания, то (*) может быть преобразовано в триадную форму тремя различными способами. В результате получим следующие триадные формы:

clip_image004

Если Q1 и Q2 — соответственно операции деления и умножения или вычитания и сложения, то формы 1) и 3) остаются без изменения, а форма 2) будет иметь вид:

clip_image006

Если Q1 и Q2 — обе операции деления или операции вычитания, то опять изменится только форма 2), которая будет иметь вид:

Форма 1) получается обычным методом получения триад из ОПЗ. Для получения из ОПЗ форм 2) и 3) необходимо придерживаться следующего простого правила. При просмотре ОПЗ, если рассматриваемый элемент и после него второй по счету элемент (обозначим его через J) являются знаками арифметической операции приоритеты этих знаков одинаковы, то для формы 2) первой выполняется операция Q2 (она представлена элементом J) над элементами (J—3) и (J—1), если операция Q1 (представленная элементом (J—2)) является знаком * или +. В случае, когда Q1 и Q2 — знаки операции/или —, то вместо операции Q2 выполняется операция clip_image008. Если же Q1 и Q2 соответственно знаки / и * или — и +, то для формы 2) первой выполняется операция clip_image010 над элементами (J—1) и (J—3). Для формы 3) первой выполняется операция Q2 над элементами (J–4) и (J–1).

Каким бы способом ни представлять в триадной форме рассматриваемое выражение (*), конечный результат будет одним и тем же — вычисление значения А. Это обстоятельство позволяет представлять арифметические выражения в триадной форме описываемом ниже способом, который дает возможность установить идентичность максимального числа выражений и (или) подвыражений, выполняющих одно и то же вычисление. Если при просмотре ОПЗ какого-нибудь арифметического выражения в нем не окажется подвыражений, содержащих соседние знаки операций с одинаковым приоритетом, то эти подвыражения и рассматриваемое выражение в целом преобразуются в триады обычным способом. В противном случае те подвыражения, в которых имеются два соседних знака операций с одинаковыми приоритетами, преобразуются в триады способами 1), 2) или 3) одно за другим. Эти формы являются различными триадными записями одного и того же выражения. Чтобы в процессе анализа учитывать это обстоятельство, при записи каждой из этих форм используются одни и те же номера строк, но они снабжаются различными признаками, например @, @@, @@@. Поэтому в триадах должно быть предусмотрено поле для этих признаков.

clip_image012

Рассмотрим этот способ триадной записи на примере фрагмента исходной программы:

Обратная польская запись этого фрагмента имеет вид:

clip_image016

После преобразования в триадную форму фрагмент будет иметь вид (здесь и далее рамкой выделены общие выражения):

clip_image019

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

clip_image021

Благодаря такой трансформации программы рассматриваемый фрагмент исходной программы после от оптимизации может выглядеть следующим образом:

Здесь может возникнуть следующий естественный вопрос. Как при преобразовании исходной программы в триадную форму учитывается то обстоятельство, что различные способы представления выражения (*) могу дать различные результаты вычисления в случаях, когда операнды существенно отличаются друг от друга по значению?

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

Например, если в рассмотренном выше фрагменте программы переменные D и Е— очень малые числа а С—очень большое число, то при выбранном способе 2) представления выражения D*C/E в триадной форме может возникнуть ситуация переполнения. Данная форма записи этого выражения выбрана из-за того, что в программе имеется подвыражение С/Е. Однако независимо от способа представления выражения D*C/E в триадной форме все равно из-за выражения С/Е возникнет ситуация переполнения. А это должен учитывать программист при написании программы.

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

clip_image023

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

Следует также заметить, что если при учете двух знаков рассматриваемое подвыражение можно представить тремя способами, то при учете трех знаков — уже двенадцатью способами. Это предъявляет повышенные требования к объему ЗУ и увеличивает затраты времени на обработку программы.

По этим же соображениям для выявления максимального числа повторных выражений подвыражения типа В**К, где К — целое число, 2£К£7, в триадной форме следует представлять с помощью К—1 строки операций умножения.

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

Для обеспечения такой возможности введем операции ВЫБОР ЭЛЕМЕНТА МАССИВА (ЭМ), операндами которой являются идентификатор массива и значения индексных выражений, а также операцию ФУНКЦИЯ (Ф), операндами которой являются идентификатор функции и идентификаторы аргументов. Кроме того, запятую «,» будем считать также знаком операции. Её аргументы — идентификаторы или индексы, которые она разделяет.

clip_image025

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

clip_image029

Обратная польская запись этого фрагмента будет следующей (Здесь унарный минус для отличия от обычного минуса представлен символом «И»):

Соответствующая триадная запись будет иметь вид

Такая запись программы позволит представить рассматриваемый фрагмент исходной программы в следующей оптимизированной форме:

clip_image032

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

Рассмотрим следующий фрагмент исходной программы:

clip_image034

Его обратная польская запись имеет вид

clip_image036

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

Пользуясь такой формой записи, легко установить, что линейность выполнения программы нарушается в строках т3, т6, т10, т14 и т25. Кроме того используемая форма развертывания оператора цикла позволяет легко определить его параметры и тип, что имеет большое значение для сбора начальной информации и выполнения оптимизирующих преобразовании над циклами.

Триадная запись удобна для определения поведения элементов данных в каждом участке программы. В частности, анализируя триадное представление программы, можно установить в каждом операторе и (или) участке программы и во всей программе и целом множества элементов данных, которые определяются и которые используются. Однако для получения полной и достоверной начальной информации промежуточная триадная форма должна отражать не только внутренние переменные, но также вводимые и выводимые данные, фактические параметры, содержащиеся в операторах вызова процедур и процедур-функций, а также - формальные параметры процедур и процедур-функций. Для выполнения этого требования введем некоторые дополнительные операции. Для представления в промежуточной форме фактических параметров операторов вызова процедур введем операцию ФАКТИЧЕСКИЙ ПАРАМЕТР (ФАП), операндами которой являются имя вызываемой процедуры и идентификаторы передаваемых фактических параметров, а для представления . формальных параметров в операторах процедур—операцию ФОРМАЛЬНЫЙ ПАРАМЕТР (ФОП), аргументами которой служат ключевое слово PROCEDURE и идентификаторы формальных параметров.

clip_image038

Тогда например, фрагмент исходной программы

clip_image040

' в ОПЗ будет иметь вид

clip_image042

Используя описанные выше новые операции, получаем следующее триадное представление этого фрагмента:

Для разделения друг от друга операторов программ мы в промежуточной триадной форме после записи каждого очередного оператора используется разделитель «;». Например, mi _; _

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

clip_image044

Для подтверждения вышесказанного рассмотри следующий фрагмент исходной программы, составленный на языке Фортран-IV:

clip_image047

Для этого фрагмента усовершенствованная триадная форма имеет следующий вид:

Здесь для явного указания в промежуточной форме нарушений линейности выполнения программы в условные операторы, в частности в логический условный оператор, введена операция ВЫБОР ПО УСЛОВИЮ (ВПУ), операндами которой являются ключевое слово IF и последующее за ним логическое выражение. Несмотря на то что язык программирования Фортран не содержит знака конца оператора в промежуточной форме после каждого оператора предусмотрена отдельная строка для представления знака конца оператора «; » точно так же, как в языке ПЛ/1. Это значительно облегчает последующие этапы оптимизации. Введение знака «; » при преобразовании программы в ОПЗ необходимо для очистки стека операций по окончании преобразования каждого оператора.

Предлагаю ознакомиться с аналогичными статьями: