РАЗРАБОТКА ПО

Окончание. Начало см. в PC Week/RE № 22/ 2002 г. с. 18.

Многоуровневая оптимизация кода

Существует два уровня оптимизации в Ucc и Ucpp: высокий и низкий.

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

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

Отдельного упоминания заслуживает наличие стековой оптимизации, необходимой при реализации компиляторов для стековых машин (таких, как машины Forth, Java). В Ucc и Ucpp реализована стековая оптимизация для виртуальной машины Java (JVM) для семейства процессоров Cjip компании ImSys AB. Особенностью данной целевой платформы является возможность введения новых инструкций. Стековая оптимизация в Ucc и Ucpp включает поддержку специфических инструкций, отражающих особенности виртуальных машин JVM и Forth.

Стековая машина отличается от регистровой тем, что основные (или все) ее инструкции исполняются над операндами, загруженными на вершину стека, а не на регистры. Задача оптимизации - повысить эффективность полученного кода путем выбора оптимального набора инструкций, идущих в таком порядке, благодаря которому минимизировано количество операций со стеком: пересылки данных между стеком и регистрами или памятью, перестановки элементов стека, использование прямого доступа к нескольким верхним элементам стека, выемка его глубоких элементов. Со стеком связана еще одна операция: его применяют для временного хранения данных, чтобы освободить дополнительные регистры. Реализация стековой оптимизации в Ucc и Ucpp потребовала разработки как высокоуровневых алгоритмов (которые вошли в фазу MiddleEnd), так и низкоуровневых (выполняемых на фазе BackEnd).

Кодогенератор, настраиваемый на целевую платформу

Каждая фаза компиляторов Ucc и Ucpp является машино-независимой, включая кодогенератор. Последний состоит из двух принципиально важных фаз: фазы переписи деревьев внутреннего представления и фазы распределения переменных. Имеющееся каноническое внутреннее представление исходной программы преобразуется фазой переписи деревьев в целевое представление с помощью кодогенерационной таблицы. Чтобы достичь высокой эффективности, получение машинного кода производится с помощью промежуточных переменных, а не реальных регистров. Следующая фаза компилятора распределяет переменные по регистрам оптимальным способом и устраняет избыточность, полученную на предыдущей фазе. Кодогенерационная таблица имеет гибкую структуру, отражает все необходимые специфические средства целевого процессора и управляет процессом кодогенерации. Она написана на специальном языке и является единственной машино-зависимой частью компилятора.

Универсальный компилятор плюс+

Универсальные компиляторы Ucc и Ucpp - это не только программные продукты, но и технология. На их основе новые компиляторы могут быть разработаны за минимальное время. “АстроСофт” предлагает свои услуги по созданию таких инструментальных средств, как оптимизирующие компиляторы языков C/C++ или специальных языков, конвертеры, ассемблеры, линкеры, отладчики, профайлеры, библиотеки и другие средства программирования для любых целевых платформ.

Ucc и Ucpp как генераторы компиляторов

Кодогенерационная таблица составляет лишь малую часть всего исходного кода компиляторов C/C++, поэтому разработать описание нового процессора сравнительно просто. Более того, для отдельных процессоров кодогенерационная таблица является общей для обоих компиляторов. Таким образом, создание компиляторов C и C++ для конкретного процессора весьма эффективно и по времени, и по затратам. С этой позиции Ucc и Ucpp могут рассматриваться как генераторы компиляторов.

Автор - ведущий программист-аналитик научно-исследовательской лаборатории AstroSoft Development. С ней можно связаться по адресу: VeronikaM@astrosoft.ru.