私はRenjin(R for the JVM)のバイトコードコンパイラで作業しており、中間3アドレスコード(TAC)表現をバイトコードに変換することを試しています。私が参考にしたコンパイラのすべての教科書は、コード生成中にレジスタの割り当てについて議論していますが、JVMのようなスタックベースの仮想マシン上でコード生成のためのリソースを見つけることができませんでした。3つのアドレスコードからJVMバイトコードへのコード生成
単純なTAC命令はバイトコードに変換するのは簡単ですが、一時的なものが含まれていると少し失われます。誰がこれを説明するリソースへのポインタを持っていますか?
x + sqrt(x * y)
TAC IR:
オリジナルRコードは次のようになります。ここでは
は完全な例である が0: _t2 := primitive<*>(x, y)
1: _t3 := primitive<sqrt>(_t2)
2: return primitive<+>(x, _t3)
(第2のために事実を無視taht私たちがすることはできませんコンパイル時に常に関数呼び出しをプリミティブに解決する)
結果のJVMバイトコードwouこのようなLDの外観(おおよそ)何か:
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を必要とするつもりだと考えてする必要があります私は手動でこれを考えることができますが、これを正しく行うためのアルゴリズムを考えるのは難しいです。すべてのポインタ?
ワウ!ありがとう、これは私が探していたものです。質問:基本ブロックごとに、または手順全体にわたってSSA変換を実行する必要がありますか?チュートリアル、教科書、その他のリソースへの指針はありますか? – akbertram
SSA変換は、プロシージャ全体で行われます。http://en.wikipedia.org/wiki/Single_static_assignment変数を割り当てる複数の割り当て場所を持つ基本ブロックごとに、支配的な境界線を見つけるだけで済みます。そこにphiノードを挿入してから、冗長なphisを取り除いてください(nb:循環依存関係を持つものもあります)。 –
@akbertram、 'LLVM'はここでインスピレーションの源泉になることができます。それ以降は中間表現を安全にモデル化できます。そこからいくつかの重要な意思決定:あるレジスタを別のレジスタに割り当てることを許さず、レジスタに定数を割り当てることを許さない場合は、常にその代わりに代わりにそのレジスタを置き換えます。 –