Hooplをコンパイラーに導入しようとしていますが、いくつかの問題に直面しました。Hooplのグラフを作成すると、導入されたラベルの順にノードが表示されます。
例えば:
(define (test) (if (eq? (random) 1 ) 2 (if (eq? (random) 2 ) 3 0) ) )
に「コンパイル」
L25: call-direct random -> _tmp7_6
branch L27
L26: return RETVAL
L27: iconst 1 _tmp8_7
branch L28
L28: call-direct eq? _tmp7_6, _tmp8_7 -> _tmp4_8
branch L29
L29: cond-branch _tmp4_8 L30 L31
L30: iconst 2 RETVAL
branch L26
L31: call-direct random -> _tmp12_10
branch L32
L32: iconst 2 _tmp13_11
branch L33
L33: call-direct eq? _tmp12_10, _tmp13_11 -> _tmp9_12
branch L34
L34: cond-branch _tmp9_12 L36 L37
L35: assign RETVAL _tmp6_15
branch L26
L36: iconst 3 _tmp6_15
branch L35
L37: iconst 0 _tmp6_15
branch L35
ASTからの再帰的なグラフ構築の順序のため、命令の順序(showGraphの順序)は奇妙です。コードを生成するには、より自然な方法でブロックを並べ替える必要があります。たとえば、関数の最後にRETVALを返し、次のようにブロックをマージします。
branch Lx:
Lx: ...
1つのブロックに、というように続きます。私は次のようなものが必要なようです:
block1 = get block
Ln = get_last jump
block2 = find block Ln
if (some conditions)
remove block2
replace blick1 (merge block1 block2)
これをHooplで実行する方法が完全に混乱しています。もちろん、すべてのノードをダンプしてから、Hooplフレームワークの外部で変換を実行することもできますが、これは悪い考えだと思います。
誰かが私に接着剤をくれませんか?有用な例は見つかりませんでした。Lambdachineプロジェクトでも同様のことが実行されていますが、複雑すぎるようです。
別の質問もあります。すべてのCall命令を非ローカルにするポイントはありますか?Callの実装がローカル変数を変更せず、常に制御をブロックの次の命令に移すことを考えると、これのポイントは何ですか?通話指示が次のように定義されている場合
data Insn e x where
Call :: [Expr] -> Expr -> Label :: Insn O C -- last instruction of the block
そのため、グラフはさらに奇妙に見えます。だから私は使用します
-- what the difference with any other primitive, like "add a b -> c"
Call :: [Expr] -> Expr -> Label :: Insn O O
私はこれが間違っているのでしょうか?