понедельник, 19 марта 2012 г.

Немного о том, что происходит во время компилирования программы в GCC.


Обычно рассказывается, что преобразование происходит по следующей схеме:
  1. препроцессирование (команда gcc -E)
  2. ассемблирование (команда gcc -S)
  3. создание объектного файла (команда gcc -o)
  4. связывание (ld)
Но между препроцессированием и ассемблированием есть ещё несколько довольно сложных стадий. О них по порядку:

  1. Парсинг интерфейсом (front-end) текущего языка. После этого получается AST файла, но в зависимости от реализации интерфейса языка, оно может быть как в обощённом (GENERIC) представлении, так и во внутреннем, понятным только самому интерфейсу.
  2. Гимплификация (gimplification). Это процесс преобразования функции из промежуточного представления в язык GIMPLE. Это трёх-адресный ассемблер, куда преобразуются выражения из GENERIC.
  3. Оптимизация. На данном этапе выполняются различные виды оптимизаций. Они выполняются в несколько проходов. Сначала устанавливаются и упорядочиваются сами проходы (passes), после чего они последовательно запускаются. Это могут быть оптимизации OpenMP, удаление мёртвых ветвей кода, оптимизация работы переменных и т.п. Это называется Tree optimization passes.
  4. Транслирование в RTL. RTL - Register Transfer Language. Это специальный низкоуровневый промежуточный язык. Для него тоже производятся некоторые оптимизации.
  5. Ассемблирование. И, наконец, из RTL компилятор получает ассемблерный код.
Вот так, за очень много проходов и преобразований происходит компилирование программы. И это лишь действия между двумя крупными этапами.