9e3c04c4c7d9288aac050eea94105d18.ppt
- Количество слайдов: 33
Анализ потока управления и потока данных в программе Новиков Сергей
Содержание a. Структура компилятора b. Пример программы на С c. Линейная последовательность операций d. Анализ потока управления e. Анализ потока данных f. Примеры оптимизаций g. Литература к лекции Agenda
Структура компилятора Compiler structure Компилятор - переводит исходный код программы (написанные на языке высокого уровня) в эквивалентный код на языке целевой платформы ядро компилятора. c. cpp. f 77. . . 1 . c. cpp. F. . . 2 1. 1. Препроцессор 2. 2. Front-End 3. 3. Оптимизации 4. 4. Кодогенератор 5. 5. Ассемблер 6. 6. Линкер High-Level Low-Level IR 4 IR High-Level Low-Level IR IR asm 5 . o. obj 6 . out. exe
Пример (исходый код программы на С) 1. int func( int a, int b) 2. { 3. int res = 0; 4. int c = 10; 5. int d = 20; 6. int i, j, k = 0; 7. for ( i = 0; i < 100; i++ ) 8. { 9. for ( j = 0; j < 100; j++ ) 10. { 11. if ( i + j < a + b ) 12. { 13. res += a + b + i;
Линейная последовательность операций 1. MOVE. s 32 -> res // line: 3, 0 2. MOVE. s 32 -> c // line: 4, 0 3. MOVE. s 32 -> d // line: 5, 0 4. MOVE. s 32 -> k // line: 6, 0 5. MOVE. s 32 -> i // line: 8, 0 6. GOTO
Граф потока управления
Граф потока управления
Граф потока управления с промежуточным представлением
Действия на графе потока управления a. Обход (нумерация) Обход в глубину (depth first) b. 1. для каждого преемника { c. 2. устанавливаем номер ++ d. 3. обходим рекурсивно преемника } e. Обход в ширину (reverse post order) f. 1. для каждого преемника { g. 2. обходим рекурсивно преемника } h. 3. устанавливаем номер -a. b. Маркирование c. Клонирование d. Построение дерева доминаторов/постдоминаторов e. Построение дерева циклов
Обязательное предшествование (доминирование)
Свойство доминирования/постдоминирования a. Узел d доминирует/постдоминирует узел n если любой путь от стартового/стопового узла к n проходит через d b. Алгоритмы построения дерева доминаторов/постдоминаторов a. b. Простейший алгоритм O(N*N) Lengauer-Tarjan алгоритм O((N+E)log(N+E))
Дерево доминаторов
Дерево постдоминаторов
Глубинное остовное дерево (depth-first spanning tree)
Глубинное остовное дерево (пример)
Выделение сильно связных подграфов
Разметка циклов
Дерево циклов
Несводимые циклы a. Несводимый цикл – цикл с более, чем одним входом b. Цикл можно свести путем дублирования кода
Компоненты с одним входом и одним выходом
Дерево структуры программы (program structure tree)
Классический анализ потока данных
Время жизни переменных
Итерационный алгоритм определения времени жизни переменных
Форма статического единственного присваивания Фрагмент программы z = 3; if(P) { y = 5; } else { y = z + 2; } x = y; SSA - форма z=3 if(P) y 1=5 y 2=z+2 y 3=phi(y 1, y 2) x=y 3
Форма статического единственного присваивания в виде Def-Use графа
Построение SSA/Def-Use графа a. Построение phi-функций Для каждой переменной определяем узлы cfg, в которых она инициализируется b. Запускаем алгоритм поиска итерационного фронта доминирования (сложность O(|N|*|DF|)*B/size(word)) a. N – количество узлов в графе потока управления b. DF – итерационный фронт доминирования для одного узла (в среднем 1 -2 на задачах) c. B – количество переменных d. size(word) – размер слова в битовом векторе c. По результатам работы алгоритма строим phi-функции b. Линковка записей и чтений
Фронт доминирования a. CFG+DOM Dominance Frontier START d b STOP дуги дерева доминаторов J-дуги
Метод нумераций значений a. Хорошо зарекомендовавшая себя техника потокового анализа. b. Анализ присваивает одинаковые номера операциям, вырабатывающие одинаковые значения. Номера называются классами эквивалентности. c. Алгоритмическая сложность O(N * D * Argmax) a. b. N количество операций D глубина дерева циклов c. Argmax максимальное число аргументов у операции
Метод нумераций значений (пример) a. Классы эквивалентности: 1, 2, 3, 4 1 foo = bar = 0; j = i = 0; 3 if ( i % 2) 2 A = j + 100; B = i + 100; A = i; B = j; 4 “ 0” foo += a[i] + (3*A + 2*B); bar += a[j] + (7*B – 2*A); i++; j++; return (foo – bar);
Исходый код программы 1. int func( int a, int b) 2. { 3. int res = 0; 4. int c = 10; 5. int d = 20; 6. int i, j, k = 0; 7. for ( i = 0; i < 100; i++ ) 8. { 9. for ( j = 0; j < 100; j++ ) 10. { 11. if ( i + j < a + b ) 12. { 13. res += a + b + i;
Примеры оптимизаций a. 16 (с + d) подстановка констант b. 11, 13 (a+b) сбор общих подвыражений c. 13, 18 (b+i) удаление частично избыточных вычислений d. 20 (k++) удаление избыточных вычислений e. 11 (a+b) вынос инвариантных вычислений из цикла
Литература к лекции


