Лекция 11 Генерация кода Исходная программа Начальная стадия Промеж. код Оптимизатор Промеж. кода код Таблица символов Генератор кода Целевая программа Функции кодогенерации • Выбор инструкций: какие инструкции использовать • Планирование инструкций: в каком порядке размещать эти инструкции. • Размещение в регистрах: размещение переменных программы в регистрах процессора. • Генерация отладочной информации Подзадачи генерации кода • • • • • • Вход генератора кода Целевые программы Управление памятью Выбор инструкций Распределение регистров Выбор порядка выполнения Целевая машина • Регистровая машина – Данные для подвыражений хранятся в регистрах • Стековая машина – Подвыражения вычисляются на вершине стека Стоимость адресации • • • • op source destination MOV s d ADD s d SUM s d Режим Представление Адрес Добавочная стоимость Абсолютный M M 1 Регистровый R R 0 Индексированный c(R) c + contents(R) 1 Косвенный регистровый *(R) contents(R) 0 Косвенный индексированный *c(R) Contents(c + contents(R)) 1 Стоимость инструкций Стоимость инструкции = 1 + стоимость адресации источника + стоимость адресации получателя Пример: • MOV R0, R1 – стоимость 1 • MOV R5, M – стоимость 2 • ADD #1, R1 – стоимость 2 (#1 – константа) • SUB 4(R0), *12(R1) – стоимость 3 (т.к. 4 т 12 – константы) Пример – a:=b+c 1. MOV b, R0 ADD c, R0 стоимость 6 MOV R0, a 2. MOV b, a ADD c, a стоимость 6 3. R0,R1,R2 – адреса a,b,c MOV *R1, *R0 ADD *R2, *R0 стоимость 2 4. R1,R2 – значения b,c. b дальше не нужен ADD R2, R1 MOV R1, а стоимость 3 Управление памятью в run-time • Запись активации – блок памяти, содержащий информацию о связи имен с памятью для конкретной процедуры и локальные имена уровня процедуры (поля для параметров, результатов, информация о состоянии машины, локальных данных, временных переменных) • Статическое распределение – На этапе компиляции определяется расположение записи активации • Стековое распределение – Новая запись активации вносится в стек для каждой активации процедуры Распределение и назначение регистров Инструкции с только регистрами – короче и быстрее • Распределение по роли (отдельно регистры значений, арифметических выражений, стека) • Глобальное распределение регистров (для часто используемых переменных назначаются регистры между блоками, для переменных внутри цикла) • Счетчик использование переменных • Раскраска графа как метод распределения регистров(кол-во цветов – доступные регистры) Выбор инструкций при генерации кода Задача: •сопоставление конструкциям исходной программы последовательностей машинных инструкций (проекции конструкций) •выбор размещений для переменных и промежуточных результатов •выбор наилучших режимов адресации Способ: •формализация представления исходной программы с помощью деревянных грамматик •описание машинной программы в терминах покрытий деревьев Деревянные языки Для решения задачи построения генератора кода применяется теория деревянных языков и грамматик. Именно, входная программа разбивается на фрагменты (выражения), каждый из которых трактуется как предложение языка специального вида. Вывод этого предложения в грамматике, определяющей такой язык, затем интерпретируется как последовательность машинных инструкций. Деревянные языки • Деревянные языки позволяют описать множества деревьев, обладающих определенными свойствами. Скобочная запись дерева, которая может быть получена выписыванием пометок вершин при простом обходе дерева слева-направо и сверху-вниз. При этом поддеревья одной вершины отделяются от нее скобками, а между собой – запятыми. Системы восходящего переписывания деревьев Деревянные грамматики лежат в основе систем восходящего переписывания деревьев (Bottom-Up Rewriting Systems) Теория деревянных грамматик интерпретируются следующим образом: 1. Нетерминалы обозначают режимы адресации или классы размещения значений (регистр, непосредственный операнд и т.д.); 2. Цепные правила обозначают преобразования типов или пересылки; 3. Язык, определяемый грамматикой – это формат внутреннего представления программы перед выбором команд; 4. Вывод дерева в данной грамматике – последовательность команд.