Я пишу компилятор для подмножества Паскаля. Компилятор создает машинные инструкции для готовой машины. Я хочу написать оптимизатор подглядывания для этого машинного языка, но у меня возникли проблемы с заменой некоторых более сложных шаблонов.
Спецификация оптимизатора Peephole
Я исследовал несколько разных подходов к написанию оптимизатора подглядывания, и я решил использовать обратный подход:
- Encoder выполняет вызов функции
emit()
каждый раз, когда должна быть сгенерирована машинная инструкция. -
emit(Instruction currentInstr)
проверяет таблицу оптимизации глазок:- Если текущая команда соответствует хвосту шаблона:
- Проверить ранее выпущенные инструкции для соответствия
- Если все команды совпадают с шаблоном, примените оптимизацию, изменив конец конца хранилища кодов
- Если оптимизация не найдена, введите команду как обычно
- Если текущая команда соответствует хвосту шаблона:
Текущий подход к разработке
Этот метод достаточно прост, это реализация, с которой у меня возникают проблемы. В моем компиляторе машинные инструкции хранятся в классе Instruction
. Я написал класс InstructionMatch
, где хранятся регулярные выражения, предназначенные для соответствия каждому компоненту машинной команды. Его метод equals(Instruction instr)
возвращает true
, если шаблоны соответствуют некоторой машинной команде instr
.
Однако я не могу полностью применить правила, которые у меня есть. Во-первых, я чувствую, что, учитывая мой нынешний подход, у меня будет беспорядок ненужных объектов. Учитывая, что полный список номеров оптимизации глазок может насчитывать около 400 шаблонов, это быстро выходит из-под контроля. Кроме того, я не могу получить более сложные замены, работающие с этим подходом (см. "Мой вопрос" ).
Альтернативные подходы
Одна бумага, которую я прочитал, складывает предыдущие инструкции в одну длинную строку, используя регулярные выражения для соответствия и замены и преобразования строки обратно в машинные инструкции. Это казалось мне плохим подходом, пожалуйста, поправьте меня, если я ошибаюсь.
Примеры шаблонов, синтаксис шаблонов
x: JUMP x+1; x+1: JUMP y --> x: JUMP y
LOADL x; LOADL y; add --> LOADL x+y
LOADA d[r]; STOREI (n) --> STORE (n) d[r]
Обратите внимание, что каждый из этих шаблонов примеров является просто понятным для человека представлением следующего шаблона машинной команды:
op_code register n d
(n обычно указывает количество слов и d смещение адреса). Синтаксис x: <instr>
указывает, что инструкция хранится по адресу x
в хранилище кода.
Итак, инструкция LOADL 17
эквивалентна полной машинной команде 5 0 0 17
, когда код операции LOADL
равен 5 (n
и r
не используются в этой инструкции)
Мой вопрос
Итак, учитывая этот фон, мой вопрос таков: как эффективно сопоставлять и заменять шаблоны, когда мне нужно включать части предыдущих инструкций в качестве переменных в моей замене? Например, я могу просто заменить все экземпляры LOADL 1; add
инструкцией машинного приращения - для этого мне не нужна какая-либо часть предыдущих инструкций. Но я не понимаю, как эффективно использовать значения "x" и "y" моего второго примера в шаблоне замещения.
edit. Я должен упомянуть, что каждое поле класса Instruction
представляет собой просто целое число (как обычно для машинных команд). Любое использование "x" или "y" в таблице шаблонов - это переменная, стоящая за любым целым значением.