Генератор кода

[Оглавление] [Текст модуля] [Предыдущая]

Самая сложная часть компилятора Why - это, без сомнения, генератор кода, хотя так было далеко не всегда. Первые версии компилятора создавали простейший прямолинейный код, который отличался неэффективностью. Генератор кода последней версии использует два метода улучшения машинного кода: кеширование верхних элементов арифметического стека в регистрах процессора и хранение констант на этапе компиляции. Тем не менее, последний вариант генератора кода по своей структуре практически ничем не отличается от начального.

Базовыми для генератора кода являются методы Emit и EmitLine. Все остальные методы так или иначе используют их для вывода текста в выходной файл. Метод Emit просто выводит строку из нескольких символов, EmitLine - добавляет символ конца строки.

В простейшем случае генератор кода работает следующим образом. Когда компилятор, делая разбор последовательности (Sequence), встречает константу, он заносит ее в арифметический стек (PushIntegerConstant или PushStringConstant). Встретив локальную переменную, он заносит в стек ее адрес (PushLocalVariable), знак операции - выполняет ее (PerformOperation), имя процедуры - вызывает ее (Call). Кроме этих базовых операций существует еще небольшой набор макросов, которые представляют собой последовательности действий при выполнении структурных операторов - "if", "to/downto-loop", "repeat-until/while" и "begin-while/until-loop": EmitIfCode, EmitToCode, EmitDowntoCode, EmitLoopCode, EmitWhileCode и EmitUntilCode. Особая группа - операторы для работы со стеком Drop, Dup, Rot и Swap, код для которых генерируется методами EmitDropCode, EmitDupCode, EmitRotCode и EmitSwapCode соответственно. Эти методы имеют большое значение в улучшенном варианте генератора кода, так как код, который они выводят, зависит от того, как в данном контексте кешируются верхние элементы стека. Все остальные методы не представляют особого интереса - это вывод меток, директив, символов PUBLIC, EXTRN и т.п.

У объекта TCodeGenerator есть наследник THeaderGenerator, создающий .INC-файлы с описанием внешних ("EXTRN") процедур. Эти файлы используются для упрощения всех операций, связанных с импортом модулей. Например, при импорте модуля Graph просто генерируется директива включения .INC-файла (INCLUDE Graph.INC), созданного при компиляции модуля Graph.

В улучшенном варианте объекта TCodeGenerator используется два способа повышения эффективности создаваемого кода.

Первый способ - хранение (кеширование) верхних элементов арифметического стека в регистрах процессора. Для организации кеширования TCodeGenerator использует специальную структуру - массив занятых регистров CacheRegisters, построенный по принципу стека, и целый набор private- и public-методов для работы с этой структурой. Когда в кеше нет регистров, обращение к элементам стека происходит так же, как и при обычной генерации кода - путем загрузки данных из памяти в регистры процессора. Если кеш заполнен, обращения к памяти не происходит, т.к. соответствующие значения уже загружены в регистры. Перед вызовом любых процедур делается опустошение кеша - FlushCache, чтобы процедуры могли обращаться к элементам стека как обычно, через память.

Второй способ оптимизации - хранение констант на этапе компиляции. Для этого требуется дополнительная структура - массив элементов типа TCacheRegisterValue. Когда компилятор встречает целочисленную константу, он вместо генерации кода для занесения ее в регистр запоминает ее. Если затем в исходном тексте встречается какая-нибудь операция, компилятор прежде всего смотрит, известны ли значения верхних элементов стека. Если они известны, то операция выполняется на этапе компиляции, и никакой код не генерируется. Таким образом, генератор кода для последовательности "2 3 +" выдаст то же самое, что и для "5". Кроме того, автоматически появляется возможность улучшить код для всех структурных операторов, которые выполняют проверку условия. Например, в операторе "if" если значение верхнего элемента стека известно, то можно сгенерировать безусловный переход на блок, соответствующий его значению, True (1) или False (0).


[Наверх] [Об авторе...] [Оглавление]

Copyright © Алексей Яковлев, АВМ-008, факультет АТС, РГУПС.
Моя домашняя страничка: http://www.yallie.narod.ru.