SlideShare a Scribd company logo
LLVM: Как приручить дракона?
Дмитрий Каш цын, HDSoftии
Как работает компилятор
1. Прочитать текст программы из файла
2. Записать исполняемый файл
Чуть детальнее
● Разбор лексем и синтаксический анализ
● Построение AST программы
● Преобразования (магия)
● Генерация объектного файла
● Линковка исполняемого файла
4
Но зачем?!*
* http://www.linux.org.ru/gallery/workplaces/10931314
5
Если серьезно
● Развитие computer science не стоит на месте
● Новые идеи — новые языки
● Новые языки — новые компиляторы
● Успех Rust и Go говорит сам за себя
6
Мой уютный компилятор™
● Парсинг исходников
● Представление программы?
● Оптимизация всего и вся
● Целевая архитектура, наборы инструкций
● Аллокация и распределение регистров
● Интероперабельность — системные вызовы,
FFI, работа с библиотеками
● Генерация исполняемого файла, линковка
● Отладочная информация
7
Структура команды x86 (OMG)
http://penberg.blogspot.ru/2010/04/short-introduction-to-x86-instruction.html
8
Как угодить всем?
● Языки разные. Очень.
● Разное отношение к данным
● Разные модели памяти
● Разные целевые архитектуры
● Разные наборы инструкций
9
Решение LLVM
● Запись программы в виде, не зависящем от
всего вышеперечисленного
● Промежуточное представление — IR код
● Обобщенная система команд
10
Решение LLVM
● Запись программы в виде, не зависящем от
всего вышеперечисленного
● Промежуточное представление — IR код
● Обобщенная система команд
Внезапно: LLVM — это не VM o_O
11
Разбор исходного текста
● LLVM считает, что AST уже есть
● Чтобы его получить, нужно провести
лексический и синтаксический анализ
● К счастью, это не надо делать вручную
● На помощь придут
– Flex/Bison
– ANTLR
– И другие
12
Так видит программу человек
int gcd(int a, int b) {
while (b != 0) {
if (a > b)
a = a − b;
else
b = b − a;
}
return a;
}
13
Так видит программу компилятор
condition
body
else-bodyif-body
while
variable
name: b
constant
value: 0
compare
op: ≠
branch
compare
op: >
assign
bin op
op: −
assign
bin op
op: −
statement
sequence
return
variable
name: a
variable
name: a
variable
name: a
variable
name: a
variable
name: a
variable
name: b
variable
name: b
variable
name: b
variable
name: b
condition
14
Лексический анализ
● Первичный разбор текста программы
● Удаление лишнего шума
● Преобразование потока входных символов в
последовательность токенов
15
Лексический анализатор flex
● Позволяет записать правила разбора в
текстовом, человеко-читаемом виде
● Регулярные выражения — это сила
● На выходе — токены
16
Входной файл для flex (огрызок)
whitespace [ rnt]*
number [0-9]+
identifier [a-zA-Z]+
{whitespace} { /* ignore whitespaces */ }
{number} { sscanf(yytext, "%d", &yylval->value);
return TOKEN_NUMBER; }
"+" { return PLUS; }
"-" { return MINUS; }
"(" { return LPAREN; }
")" { return RPAREN; }
";" { return SEMICOLON; }
"," { return COMMA; }
"=" { return EQ; }
"!=" { return NEQ; }
">" { return GTR; }
"if" { return IFSYM; }
"while" { return WHILESYM; }
17
Синтаксический анализатор bison
● На вход получает поток токенов от лексера и
файл описания грамматики
● На основании правил грамматики
производит разбор
● На выходе дает древовидное представление
программы с которым может работать
компилятор
18
Входной файл для bison (огрызок)
input:
| input line;
line:
'n'
| exp 'n' { complete("result is %gn", $1); };
exp:
TOKEN_NUMBER { $$ = $1; }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '/' exp { $$ = $1 / $3; }
| exp '*' exp { $$ = $1 * $3; }
| '(' exp ')' { $$ = $2; };
Позволяет разбирать арифметические выражения вида (2 + 3 * 4) * 5
19
IR код
● Intermediate Representation
● Запись графа управления в привычном текстовом виде…
20
IR код
● Intermediate Representation
● Запись графа управления в привычном текстовом виде…
но с плюшками:
– Asm-подобный синтаксис, но с параметризованными
функциями
– Строгая типизация
– Структуры данных, указатели
– Const, Volatile модификаторы
– Нотация SSA
21
Нотация SSA
● Static Single Assignment
● Переменных — нет о_О
● Все имена встречаются только единожды
● Функциональный стиль описания данных
● Императивный стиль описания операций
22
Что хорошего в SSA?
X ← 1
X ← 2
Y ← X
23
Что хорошего в SSA?
X ← 1
X ← 2
Y ← X
X1←1
X2←2
Y1←X2
24
Что хорошего в SSA?
X ← 1
X ← 2
Y ← X
X1←1 (RIP)
X2←2
Y1←X2
25
Что хорошего в SSA?
X ← 1
X ← 2
Y ← X
X1←1 (RIP)
X2←2 (RIP)
Y1←2
26
Граф потока управления*
● Control flow graph (CFG)
● Узлы — базовые блоки
● Ребра — инструкции
переходов
● Базовый блок —
линейный участок кода
(a)
(c)
(b)
(d)
* https://en.wikipedia.org/wiki/Control_flow_graph
27
Циклы и ветвления в SSA
28
Циклы и ветвления в SSA
29
Циклы и ветвления в SSA
30
Подсчет суммы массива
int sum_array(int* input, int length) {
int sum = 0;
for (int i = 0; i < length; ++i)
sum += input[i];
return sum;
}
31
Листинг IR кода
1 ; Function Attrs: nounwind readonly
2 define i32 @sum_array(int*, int)(i32* nocapture readonly %input, i32 %length) #0 {
3 %1 = icmp sgt i32 %length, 0 ; а есть вообще что суммировать?
4 br i1 %1, label %.lr.ph, label %._crit_edge
5 ._crit_edge:
6 %sum.0.lcssa = phi i32 [ 0, %0 ], [ %4, %.lr.ph ]
7 ret i32 %sum.0.lcssa ; возврат результата
8 .lr.ph:
9 %i.02 = phi i32 [ %5, %.lr.ph ], [ 0, %0 ]
10 %sum.01 = phi i32 [ %4, %.lr.ph ], [ 0, %0 ]
11 ; вычисление адреса текущего элемента в массиве и его загрузка в регистр
12 %2 = getelementptr inbounds i32, i32* %input, i32 %i.02
13 %3 = load i32, i32* %2, align 4
14 ; аккумулирование суммы и инкремент индекса
15 %4 = add nsw i32 %3, %sum.01 ; новое значение sum
16 %5 = add nuw nsw i32 %i.02, 1 ; новое значение i
17 ; условие выхода
18 %exitcond = icmp eq i32 %5, %length
19 ; проверка условия выхода и переход
20 br i1 %exitcond, label %._crit_edge, label %.lr.ph
21 }
32
Результат clang -O1 -m32
sum_array(int const*, int):
mov ecx, dword ptr [esp + 8]
xor eax, eax
test ecx, ecx
jle .LBB0_3
mov edx, dword ptr [esp + 4]
.LBB0_2: # %.lr.ph
add eax, dword ptr [edx]
add edx, 4
dec ecx
jne .LBB0_2
.LBB0_3: # %._crit_edge
ret
33
Результат clang -O1 (x64)
sum_array(int const*, int):
xor eax, eax
test esi, esi
jle .LBB0_2
.LBB0_1: # %.lr.ph
add eax, dword ptr [rdi]
add rdi, 4
dec esi
jne .LBB0_1
.LBB0_2: # %._crit_edge
ret
34
Оптимизации
● Наблюдаемое поведение
● Точки следования
● Эквивалентные преобразования
35
Основные идеи оптимизаций
● Не делать то, что никому не нужно
● Не делать дважды то, что можно сделать
один раз (а лучше не делать вообще)
● Если можно получить тот же результат, но
меньшими усилиями — это нужно сделать
● Сокращение издержек на всех уровнях
36
Виды оптимизаций
● Peephole оптимизации — буквально
«через замочную скважину». Локальные
оптимизации в пределах базового блока
● Внутрипроцедурные оптимизации
● Межпроцедурные оптимизации
● Оптимизации во время линковки
37
Loop Invariant Code Motion (LICM)
● Вынос инвариантных значений за пределы цикла
● Перенос значений из тела цикла в базовый блок возврата
int sum_array(int* input, int length) {
int sum = 0;
for (int i = 0; i < length; ++i) {
if (sum > length * 1024 * 1024)
printf("note: limit exceeded");
sum += input[i];
}
return sum;
}
38
Loop Invariant Code Motion (LICM)
● Вынос инвариантных значений за пределы цикла
● Перенос значений из тела цикла в базовый блок возврата
int sum_array(int* input, int length) {
int sum = 0;
for (int i = 0; i < length; ++i) {
if (sum > length * 1024 * 1024)
printf("note: limit exceeded");
sum += input[i];
}
return sum;
}
39
Loop Invariant Code Motion (LICM)
● Вынос инвариантных значений за пределы цикла
● Перенос значений из тела цикла в базовый блок возврата
int sum_array(int* input, int length) {
int sum = 0;
const int len = length * 1024 * 1024;
for (int i = 0; i < length; ++i) {
if (sum > len)
printf("note: limit exceeded");
sum += input[i];
}
return sum;
}
40
Common subexpression elimination (CSE)
● Удаление общих подвыражений
int sum_array(int* input, int length) {
int sum = 0;
int max = 0;
for (int i = 0; i < length; ++i) {
max = (input[i] > max) ? input[i] : max;
sum += input[i];
}
printf("max was %dn", max);
return sum;
}
41
Common subexpression elimination (CSE)
● Удаление общих подвыражений
int sum_array(int* input, int length) {
int sum = 0;
int max = 0;
for (int i = 0; i < length; ++i) {
max = (input[i] > max) ? input[i] : max;
sum += input[i];
}
printf("max was %dn", max);
return sum;
}
42
Common subexpression elimination (CSE)
● Удаление общих подвыражений
int sum_array(int* input, int length) {
int sum = 0;
int max = 0;
for (int i = 0; i < length; ++i) {
const int input_i = input[i];
max = (input_i > max) ? input_i : max;
sum += input_i;
}
printf("max was %dn", max);
return sum;
}
43
Что можно почитать
● blog.llvm.org
● llvm.org/docs
● halt.habrahabr.ru/topics/
● llst.org
Спасибо за внимание!

More Related Content

PDF
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
PDF
Максим Хижинский Lock-free maps
PDF
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
PDF
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
PDF
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
PDF
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
PDF
Haskell
PDF
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Максим Хижинский Lock-free maps
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Haskell
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“

What's hot (20)

PPTX
разработка серверов и серверных приложений лекция №3
PDF
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
PDF
TMPA-2013 Dmitry Zaitsev
PDF
Конкурентные ассоциативные контейнеры
PDF
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
PDF
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
PDF
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
PDF
Miasm defcon russia 23
PPTX
разработка серверов и серверных приложений лекция №2
PDF
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
PPTX
TMPA-2013 Tsytelov Trifanov Devexperts
PDF
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
PDF
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
PDF
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
PDF
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
PPTX
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
PPTX
Евгений Зуев, С++ в России: Стандарт языка и его реализация
PPTX
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
PDF
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
PDF
A System of Deductive Verification of Predicate Programs
разработка серверов и серверных приложений лекция №3
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
TMPA-2013 Dmitry Zaitsev
Конкурентные ассоциативные контейнеры
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
Miasm defcon russia 23
разработка серверов и серверных приложений лекция №2
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
TMPA-2013 Tsytelov Trifanov Devexperts
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
A System of Deductive Verification of Predicate Programs
Ad

Similar to Как приручить дракона: введение в LLVM (20)

PDF
Теория языков программирования некоторые слайды к лекциям
PDF
Построение компилятора на базе LLVM — Павел Сычев
PDF
ОПК № 2 – Алгоритмы и структуры данных, язык C
PPTX
Как написать JIT компилятор
PDF
доклад про Llvm
PPTX
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
PDF
C++ Базовый. Занятие 02.
ODP
C language. Introduction
PDF
Александр Сомов "C++: препроцессор, компилятор, компоновщик"
PDF
книга с++
PDF
C++ for real_programmers
PDF
C++ STL & Qt. Занятие 11.
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
PDF
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
PDF
C++ Базовый. Занятие 04.
PDF
Отображение языков высокого уровня на архитектуру ЭВМ на примере языка C и ос...
PPTX
На что нужно обратить внимание при обзоре кода разрабатываемой библиотеки
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
PPT
Языки программирования
PPT
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Теория языков программирования некоторые слайды к лекциям
Построение компилятора на базе LLVM — Павел Сычев
ОПК № 2 – Алгоритмы и структуры данных, язык C
Как написать JIT компилятор
доклад про Llvm
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
C++ Базовый. Занятие 02.
C language. Introduction
Александр Сомов "C++: препроцессор, компилятор, компоновщик"
книга с++
C++ for real_programmers
C++ STL & Qt. Занятие 11.
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
C++ Базовый. Занятие 04.
Отображение языков высокого уровня на архитектуру ЭВМ на примере языка C и ос...
На что нужно обратить внимание при обзоре кода разрабатываемой библиотеки
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
Языки программирования
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Ad

More from Tech Talks @NSU (20)

PDF
Tech Talks @NSU: Путь студента в IT-бизнес
PDF
Tech Talks @NSU: Стажировки в американских IT-компаниях. Как стать стажером, ...
PDF
Tech Talks @NSU: Как живется преподавателю Computer Science у «нас» и у «них»
PDF
Back to the Future: Функциональное программирование вчера и сегодня
PDF
Что такое Highload? Секреты высокой нагрузки
PDF
Автоматическое доказательство теорем
PDF
AOT-компиляция Java
PDF
Защита от атак по сторонним каналам
PDF
Тестировщик: ожидание vs. реальность
PDF
Гибкие методологии разработки ПО в реальном мире
PDF
Tech Talks @NSU: Что есть QA и как в него попасть
PDF
Tech Talks @NSU: Технологии кросс-платформенной разработки мобильных бизнес-п...
PDF
Tech Talks @NSU: DLang: возможности языка и его применение
PDF
Tech Talks @NSU: Рассказ о разных профессиях в IT-индустрии, или почему не вс...
PDF
Tech Talks @NSU: Что такое работа в техподдержке: тяжело ли живётся саппортеру
PDF
Tech Talks @NSU: Как олимпиадное программирование не испортило мою жизнь, а т...
PDF
Tech Talks @NSU: Организация тестирования в IT-компаниях Академгородка. Карье...
PDF
Tech Talks @NSU: Мир open source — мир возможностей
PDF
Tech Talks @NSU: Методологии разработки ПО. Что на самом деле скрывается за с...
PDF
Тестировщик: ожидание vs. реальность
Tech Talks @NSU: Путь студента в IT-бизнес
Tech Talks @NSU: Стажировки в американских IT-компаниях. Как стать стажером, ...
Tech Talks @NSU: Как живется преподавателю Computer Science у «нас» и у «них»
Back to the Future: Функциональное программирование вчера и сегодня
Что такое Highload? Секреты высокой нагрузки
Автоматическое доказательство теорем
AOT-компиляция Java
Защита от атак по сторонним каналам
Тестировщик: ожидание vs. реальность
Гибкие методологии разработки ПО в реальном мире
Tech Talks @NSU: Что есть QA и как в него попасть
Tech Talks @NSU: Технологии кросс-платформенной разработки мобильных бизнес-п...
Tech Talks @NSU: DLang: возможности языка и его применение
Tech Talks @NSU: Рассказ о разных профессиях в IT-индустрии, или почему не вс...
Tech Talks @NSU: Что такое работа в техподдержке: тяжело ли живётся саппортеру
Tech Talks @NSU: Как олимпиадное программирование не испортило мою жизнь, а т...
Tech Talks @NSU: Организация тестирования в IT-компаниях Академгородка. Карье...
Tech Talks @NSU: Мир open source — мир возможностей
Tech Talks @NSU: Методологии разработки ПО. Что на самом деле скрывается за с...
Тестировщик: ожидание vs. реальность

Как приручить дракона: введение в LLVM

  • 1. LLVM: Как приручить дракона? Дмитрий Каш цын, HDSoftии
  • 2. Как работает компилятор 1. Прочитать текст программы из файла 2. Записать исполняемый файл
  • 3. Чуть детальнее ● Разбор лексем и синтаксический анализ ● Построение AST программы ● Преобразования (магия) ● Генерация объектного файла ● Линковка исполняемого файла
  • 5. 5 Если серьезно ● Развитие computer science не стоит на месте ● Новые идеи — новые языки ● Новые языки — новые компиляторы ● Успех Rust и Go говорит сам за себя
  • 6. 6 Мой уютный компилятор™ ● Парсинг исходников ● Представление программы? ● Оптимизация всего и вся ● Целевая архитектура, наборы инструкций ● Аллокация и распределение регистров ● Интероперабельность — системные вызовы, FFI, работа с библиотеками ● Генерация исполняемого файла, линковка ● Отладочная информация
  • 7. 7 Структура команды x86 (OMG) http://penberg.blogspot.ru/2010/04/short-introduction-to-x86-instruction.html
  • 8. 8 Как угодить всем? ● Языки разные. Очень. ● Разное отношение к данным ● Разные модели памяти ● Разные целевые архитектуры ● Разные наборы инструкций
  • 9. 9 Решение LLVM ● Запись программы в виде, не зависящем от всего вышеперечисленного ● Промежуточное представление — IR код ● Обобщенная система команд
  • 10. 10 Решение LLVM ● Запись программы в виде, не зависящем от всего вышеперечисленного ● Промежуточное представление — IR код ● Обобщенная система команд Внезапно: LLVM — это не VM o_O
  • 11. 11 Разбор исходного текста ● LLVM считает, что AST уже есть ● Чтобы его получить, нужно провести лексический и синтаксический анализ ● К счастью, это не надо делать вручную ● На помощь придут – Flex/Bison – ANTLR – И другие
  • 12. 12 Так видит программу человек int gcd(int a, int b) { while (b != 0) { if (a > b) a = a − b; else b = b − a; } return a; }
  • 13. 13 Так видит программу компилятор condition body else-bodyif-body while variable name: b constant value: 0 compare op: ≠ branch compare op: > assign bin op op: − assign bin op op: − statement sequence return variable name: a variable name: a variable name: a variable name: a variable name: a variable name: b variable name: b variable name: b variable name: b condition
  • 14. 14 Лексический анализ ● Первичный разбор текста программы ● Удаление лишнего шума ● Преобразование потока входных символов в последовательность токенов
  • 15. 15 Лексический анализатор flex ● Позволяет записать правила разбора в текстовом, человеко-читаемом виде ● Регулярные выражения — это сила ● На выходе — токены
  • 16. 16 Входной файл для flex (огрызок) whitespace [ rnt]* number [0-9]+ identifier [a-zA-Z]+ {whitespace} { /* ignore whitespaces */ } {number} { sscanf(yytext, "%d", &yylval->value); return TOKEN_NUMBER; } "+" { return PLUS; } "-" { return MINUS; } "(" { return LPAREN; } ")" { return RPAREN; } ";" { return SEMICOLON; } "," { return COMMA; } "=" { return EQ; } "!=" { return NEQ; } ">" { return GTR; } "if" { return IFSYM; } "while" { return WHILESYM; }
  • 17. 17 Синтаксический анализатор bison ● На вход получает поток токенов от лексера и файл описания грамматики ● На основании правил грамматики производит разбор ● На выходе дает древовидное представление программы с которым может работать компилятор
  • 18. 18 Входной файл для bison (огрызок) input: | input line; line: 'n' | exp 'n' { complete("result is %gn", $1); }; exp: TOKEN_NUMBER { $$ = $1; } | exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } | exp '/' exp { $$ = $1 / $3; } | exp '*' exp { $$ = $1 * $3; } | '(' exp ')' { $$ = $2; }; Позволяет разбирать арифметические выражения вида (2 + 3 * 4) * 5
  • 19. 19 IR код ● Intermediate Representation ● Запись графа управления в привычном текстовом виде…
  • 20. 20 IR код ● Intermediate Representation ● Запись графа управления в привычном текстовом виде… но с плюшками: – Asm-подобный синтаксис, но с параметризованными функциями – Строгая типизация – Структуры данных, указатели – Const, Volatile модификаторы – Нотация SSA
  • 21. 21 Нотация SSA ● Static Single Assignment ● Переменных — нет о_О ● Все имена встречаются только единожды ● Функциональный стиль описания данных ● Императивный стиль описания операций
  • 22. 22 Что хорошего в SSA? X ← 1 X ← 2 Y ← X
  • 23. 23 Что хорошего в SSA? X ← 1 X ← 2 Y ← X X1←1 X2←2 Y1←X2
  • 24. 24 Что хорошего в SSA? X ← 1 X ← 2 Y ← X X1←1 (RIP) X2←2 Y1←X2
  • 25. 25 Что хорошего в SSA? X ← 1 X ← 2 Y ← X X1←1 (RIP) X2←2 (RIP) Y1←2
  • 26. 26 Граф потока управления* ● Control flow graph (CFG) ● Узлы — базовые блоки ● Ребра — инструкции переходов ● Базовый блок — линейный участок кода (a) (c) (b) (d) * https://en.wikipedia.org/wiki/Control_flow_graph
  • 30. 30 Подсчет суммы массива int sum_array(int* input, int length) { int sum = 0; for (int i = 0; i < length; ++i) sum += input[i]; return sum; }
  • 31. 31 Листинг IR кода 1 ; Function Attrs: nounwind readonly 2 define i32 @sum_array(int*, int)(i32* nocapture readonly %input, i32 %length) #0 { 3 %1 = icmp sgt i32 %length, 0 ; а есть вообще что суммировать? 4 br i1 %1, label %.lr.ph, label %._crit_edge 5 ._crit_edge: 6 %sum.0.lcssa = phi i32 [ 0, %0 ], [ %4, %.lr.ph ] 7 ret i32 %sum.0.lcssa ; возврат результата 8 .lr.ph: 9 %i.02 = phi i32 [ %5, %.lr.ph ], [ 0, %0 ] 10 %sum.01 = phi i32 [ %4, %.lr.ph ], [ 0, %0 ] 11 ; вычисление адреса текущего элемента в массиве и его загрузка в регистр 12 %2 = getelementptr inbounds i32, i32* %input, i32 %i.02 13 %3 = load i32, i32* %2, align 4 14 ; аккумулирование суммы и инкремент индекса 15 %4 = add nsw i32 %3, %sum.01 ; новое значение sum 16 %5 = add nuw nsw i32 %i.02, 1 ; новое значение i 17 ; условие выхода 18 %exitcond = icmp eq i32 %5, %length 19 ; проверка условия выхода и переход 20 br i1 %exitcond, label %._crit_edge, label %.lr.ph 21 }
  • 32. 32 Результат clang -O1 -m32 sum_array(int const*, int): mov ecx, dword ptr [esp + 8] xor eax, eax test ecx, ecx jle .LBB0_3 mov edx, dword ptr [esp + 4] .LBB0_2: # %.lr.ph add eax, dword ptr [edx] add edx, 4 dec ecx jne .LBB0_2 .LBB0_3: # %._crit_edge ret
  • 33. 33 Результат clang -O1 (x64) sum_array(int const*, int): xor eax, eax test esi, esi jle .LBB0_2 .LBB0_1: # %.lr.ph add eax, dword ptr [rdi] add rdi, 4 dec esi jne .LBB0_1 .LBB0_2: # %._crit_edge ret
  • 34. 34 Оптимизации ● Наблюдаемое поведение ● Точки следования ● Эквивалентные преобразования
  • 35. 35 Основные идеи оптимизаций ● Не делать то, что никому не нужно ● Не делать дважды то, что можно сделать один раз (а лучше не делать вообще) ● Если можно получить тот же результат, но меньшими усилиями — это нужно сделать ● Сокращение издержек на всех уровнях
  • 36. 36 Виды оптимизаций ● Peephole оптимизации — буквально «через замочную скважину». Локальные оптимизации в пределах базового блока ● Внутрипроцедурные оптимизации ● Межпроцедурные оптимизации ● Оптимизации во время линковки
  • 37. 37 Loop Invariant Code Motion (LICM) ● Вынос инвариантных значений за пределы цикла ● Перенос значений из тела цикла в базовый блок возврата int sum_array(int* input, int length) { int sum = 0; for (int i = 0; i < length; ++i) { if (sum > length * 1024 * 1024) printf("note: limit exceeded"); sum += input[i]; } return sum; }
  • 38. 38 Loop Invariant Code Motion (LICM) ● Вынос инвариантных значений за пределы цикла ● Перенос значений из тела цикла в базовый блок возврата int sum_array(int* input, int length) { int sum = 0; for (int i = 0; i < length; ++i) { if (sum > length * 1024 * 1024) printf("note: limit exceeded"); sum += input[i]; } return sum; }
  • 39. 39 Loop Invariant Code Motion (LICM) ● Вынос инвариантных значений за пределы цикла ● Перенос значений из тела цикла в базовый блок возврата int sum_array(int* input, int length) { int sum = 0; const int len = length * 1024 * 1024; for (int i = 0; i < length; ++i) { if (sum > len) printf("note: limit exceeded"); sum += input[i]; } return sum; }
  • 40. 40 Common subexpression elimination (CSE) ● Удаление общих подвыражений int sum_array(int* input, int length) { int sum = 0; int max = 0; for (int i = 0; i < length; ++i) { max = (input[i] > max) ? input[i] : max; sum += input[i]; } printf("max was %dn", max); return sum; }
  • 41. 41 Common subexpression elimination (CSE) ● Удаление общих подвыражений int sum_array(int* input, int length) { int sum = 0; int max = 0; for (int i = 0; i < length; ++i) { max = (input[i] > max) ? input[i] : max; sum += input[i]; } printf("max was %dn", max); return sum; }
  • 42. 42 Common subexpression elimination (CSE) ● Удаление общих подвыражений int sum_array(int* input, int length) { int sum = 0; int max = 0; for (int i = 0; i < length; ++i) { const int input_i = input[i]; max = (input_i > max) ? input_i : max; sum += input_i; } printf("max was %dn", max); return sum; }
  • 43. 43 Что можно почитать ● blog.llvm.org ● llvm.org/docs ● halt.habrahabr.ru/topics/ ● llst.org