Россия |
Оптимизация
Def-Use Chains
Следующей удобной формой представления программ для оптимизации является представление с использованием def-use chains .
Помимо алфавита операторов введем в рассмотрение алфавиты входов I и выходов O и определим для каждого оператора множество его входов
и выходов
. При этом будем требовать, чтобы множества входов и выходов для разных операторов не пересекались.
Рассмотрим теперь отображение DU , которое каждому выходу сопоставляет некоторое подмножество множества входов. Тогда для каждого оператора определяются множества и
, которые есть соответственно множества его выходов и множество тех выходов других операторов, образы которых при отображении DU содержат хотя бы один вход оператора
Неформально говоря, данное представление позволяет отследить потоки данных в программе без учета того, как именно эти данные преобразуются. Множества входов и выходов соответствуют интуитивному представлению об аргументах и результатах операторов, а отображение DU просто описывает, как используются выработанные операторами результаты.
Пример
Рассмотрим представление программы, приведенной в разделе "Представление программы", с использованием def-use chains.
Здесь входы операторов обозначены с помощью кружков, расположенных слева он операторов, выходы - с помощью кружков, расположенных справа. Пунктирные стрелки ведут из выходов одних операторов к входам других и обозначают образы при отображении DU.
Построение данного представления опирается на решение одной из задач из области анализа потоков данных, а именно - задачи о достижимых определениях. Подробно данная задача рассмотрена в "Анализ потоков данных" .
Далее мы рассмотрим примеры оптимизирующих преобразований и те представления, которые необходимо использовать для их проведения.
Удаление пустого оператора
Удаление пустого оператора - это одно их наиболее простых и распространенных оптимизирующих преобразований, которое реализуется практически во всех, даже не оптимизирующих, компиляторах. Для его формализации требуется представление программы в виде графа потока управления с пустым оператором.
Данное преобразование заключается в том, что вершина графа, помеченная пустым оператором, удаляется вместе с входящими и исходящими дугами, а в оставшийся граф добавляются дуги, соединяющие предшественников удаленного оператора с его потомком (если он есть). Напомним, что в выбранном нами представлении у вершины графа, помеченной пустым оператором, может быть не более одного потомка.
Несмотря на кажущуюся простоту данного преобразования, им покрывается большое количество частных случаев. В качестве примеров его применения справа на иллюстрации приведены удаление перехода на следующую инструкцию и удаление перехода на переход.
Удаление мертвого кода
Данное преобразование легко реализуется, если программа представлена с помощью def-use chains. Преобразование заключается в удалении такого оператора, у которого не используются его выходы.
Пример применения такого преобразования приведен на иллюстрации.
Данное преобразование повторно по отношению к самому себе, поскольку удаление одного оператора приводит к тому, что операторы, вырабатывающие для него данные, также могут оказаться неиспользуемыми.