itmo_conspects

Лекция 6. Анализ и оптимизации компилятора

Оптимизации

Оптимизации компилятора - это преобразования программы, которые делают её быстрее, компактнее или экономичнее, не изменяя поведение. Оптимизации компилятора бывают:

  1. Локальные - действуют внутри одного базового блока, например, свертка констант, удаление мертвого кода
  2. Глобальные - анализируют всю функцию или граф потока управления (CFG), например, устранение общих подвыражений, перемещение инвариантов циклов
  3. Межфункциональные (interprocedural) - охватывают несколько функций, например, inlining (встраивание), link-time optimization (оптимизация на этапе компоновки)

Приведем несколько простых оптимизаций:

Анализ кода

Для большинства оптимизаций используется анализ граф управления потоком (Control Flow Graph, CFG) программы. Для него применяются обходы графа:


Блок V доминирует над блоком W, если любой путь от входа в функцию до W проходит через V. Блок V называют доминатором. Начальный блок доминирует над всеми

Дерево доминаторов строится при помощи DFS и служит для оптимизаций, анализа циклов и построения SSA-формы


Цикл в графе потока управления определяется через наличие обратного ребра (back-edge) - перехода из блока B в блок A, где A доминирует над B.

Основные понятия:

Алгоритм анализа циклов обычно выполняется так:

  1. Строится граф управления потока функции
  2. Для каждого ребра B -> A проверяется, доминирует ли A над B. Если да, то это обратное ребро
  3. Из найденных обратных рёбер выделяются множества блоков, формирующих циклы
  4. Для каждого цикла определяются header, latch, preheader и выходы
  5. Строится иерархия вложенности циклов (дерево цикла), что помогает выполнять оптимизации, такие как loop unrolling, fusion, invariant motion и другие