Does Code Generation Promote or Prevent Optimizations?

Asma Charfi, Chokri Mraidha, Sebastien Gerard, Francois Terrier, and Pierre Boulet. 2010. Does Code Generation Promote or Prevent Optimizations?. In <em>Proceedings of the 2010 13th IEEE International Symposium on Object/Component/Service-Oriented Real-Time Distributed Computing</em> (ISORC '10). IEEE Computer Society, Washington, DC, USA, 75-79. DOI=10.1109/ISORC.2010.25 http://dx.doi.org/10.1109/ISORC.2010.25

RTES системы позволяют сократить время разработки и увеличить качество программного обеспечения. Подход MBD позволяет разрабатывать RTES на более высоком уровне абстракции. В этом подходе можно выделить три основные стадии: - создание моделей, - генерация кода, - компиляция сгенерированного кода. Для создания моделей принято использовать UML. В течение нескольких лет разработчикам приходилось править сгенерированный код, чтобы он компилировался, но с появлением UML2 эта проблема исчезла. Разработчики MDB обычно полагаются на оптимизации компилятора. Авторы данной работы пытаются разобраться: достаточно ли оптимизаций делает компилятор?

Самым популярным компилятором языка С++ является GCC. В этом компиляторе реализовано множество различных оптимизаций, которые могут быть включены с помощью флагов -O1, -O2, и т. п. Среди этих оптимизаций есть удаление «мертвого» когда, т. е. кода, который при выполнении программы недостижим. Чтобы воспользоваться этой оптимизацией, нужно включить флаг -Os, который оптимизирует размер скомпилированной программы. Давайте с помощью UML диаграммы зададим автомат, одно из состояний которого недостижимо. Затем воспользуемся программой Papyrus и сгенерируем код на C++ (в данной работе использованы вложенные операторы switch-case для генерации автомата). Однако размер скомпилированных файлов показывает, что компилятор не избавился от «мертвого» кода. GCC оптимизирует код, но чтобы понимать, какой код является «мертвым» необходимо находиться на более высоком уровне абстракции.

Если оптимизация уже сгенерированного кода не достаточно эффективна, то нужно попробовать провести оптимизацию во время его генерации. Создание оптимизаций в генераторах кода усложняет поддержку и сертификацию этих генераторов. Кроме того, многие генераторы позволяют «дебажить» код, устанавливая точки останова прямо на элементах модели. Оптимизации сделают невозможным такой «дебаггинг». Еще одной проблемой данного метода оптимизации является зависимость процесса оптимизации от языка программирования, на котором генерируется код, и зависимость от шаблонов, по которым он генерируется. Т. е. для каждого языка и способа генерации нужно реализовывать свой оптимизатор. Генераторы кода строят граф потока исполнения программы, чтобы избавиться от «мертвого» кода. Компилятор GCC делает то же самое. Получается, что эта работа выполняется дважды.

Многие современные компиляторы моделей пропускают этап генерации кода. Этот подход дает возможность избавиться от двух высоких уровней абстракции: UML-диаграммы и кода на языке программирования высокого уровня. Однако на сегодня не существует аналогичных по количеству оптимизаций компиляторов языков программирования, способных компилировать модели. Кроме того, программисты неохотно переходят на MDB, также как они неохотно переходили с языка ассемблера на языки высокого уровня. В данной работе описаны пробные шаги по избавлению от первой проблемы. Чтобы не создавать свой компилятор с нуля, возьмем за основу GCC. Напишем фронт-энд, который будет переводить модель в промежуточное представление или псевдокод; мидл-энд, который будет переводить программу из одного промежуточного состояния в другое; а в качестве бэк-энда используем GCC. Таким образом, язык высокого уровня заменится на другое промежуточное представление, например, одно из промежуточных представлений GCC. До сих пор высокоуровневая оптимизация не достигнута, так как используется только оптимизатор GCC. Высокоуровневые оптимизации можно провести с помощью преобразователей моделей, которые умеют избавляться от изолированных состояний, невозможных переходов в конечных автоматах и т. д. Таким образом, сначала трансформируется модель с целью высокоуровневой оптимизации, а затем трансформированная модель подается на вход GCC, который оптимизирует на низком уровне.