Генерация кода из трехадресного кода в байт-код JVM

Я работаю над компилятором байт-кода для Renjin (R для JVM) и экспериментирую с переводом нашего представления промежуточного трехадресного кода (TAC) в байт-код. Все учебники по компиляторам, с которыми я консультировался, обсуждают распределение регистров во время генерации кода, но я не смог найти никаких ресурсов для генерации кода на виртуальных машинах на основе стека, таких как JVM.

Простые инструкции TAC легко перевести в байт-код, но я немного теряюсь, когда речь идет о временных. Есть ли у кого-нибудь ссылки на ресурсы, которые описывают это?

Вот полный пример:

Оригинальный код R выглядит так:

x + sqrt(x * y)

TAC IR:

 0:  _t2 := primitive<*>(x, y)
 1:  _t3 := primitive<sqrt>(_t2)
 2:  return primitive<+>(x, _t3)

(на секунду игнорируем тот факт, что мы не всегда можем разрешить вызовы функций примитивам во время компиляции)

Результирующий байт-код JVM будет выглядеть (примерно) примерно так:

aload_x 
dup
aload_y
invokestatic r/primitives/Ops.multiply(Lr/lang/Vector;Lr/lang/Vector;)
invokestatic r/primitives/Ops.sqrt(Lr/lang/Vector;)
invokestatic r/primitives/Ops.plus(Lr/lang/Vector;Lr/lang/Vector;)
areturn

По сути, в начале программы мне уже нужно думать, что мне понадобится локальная переменная x в начале стека к тому времени, когда я доберусь до инструкции TAC 2. Я могу обдумать это вручную, но я У меня проблемы с продумыванием алгоритма, чтобы сделать это правильно. Есть указатели?

1 ответ

Решение

Преобразование 3-адресного представления в стек проще, чем в стеке, в 3-адресное.

Ваша последовательность должна быть следующей:

  1. Форма основных блоков
  2. Выполнить SSA-преобразование
  3. Построить деревья выражений в основных блоках
  4. Выполните планирование регистров (и одновременное удаление), чтобы выделить локальные переменные для регистров, не исключенных предыдущим шагом
  5. Выдать код JVM - регистры переходят в переменные, деревья выражений тривиально расширяются в операции стека
Другие вопросы по тегам