Я работаю над компилятором байт-кода для 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. Я могу обдумать это вручную, но у меня проблемы с продумыванием алгоритма, чтобы сделать это правильно. Есть указатели?