3

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 

私はこれが間違っているのでしょうか?

4

2 に答える 2

2

私はトリックを行うためのいくつかの方法を見つけて試しました:

  1. foldBlockNodesF3 関数または他の foldBlockNodes... 関数の使用
  2. preorder_dfs* 関数の使用 (Lambdachine プロジェクトと同様)
  3. 最初から大きなブロックでグラフを作成する

FactBase はラベルにリンクされているため、最後のオプションは役に立ちません。そのため、変数の活性を変更するすべての命令には、次の分析で使用するためのラベルが必要です。

したがって、私の最終的な解決策は、foldBlockNodesF3関数を使用してグラフを線形化し、同時にレジスタを割り当てて手動で余分なラベルを削除することです

于 2011-08-23T06:55:21.490 に答える
2

HOOPLを使用して「ブロックマージ」を実装することが可能です。あなたの質問は一般的すぎるので、私はあなたに計画を立てます:

  1. この最適化に必要な分析タイプを決定します (順方向または逆方向)。
  2. 解析格子を設計する
  3. 伝達関数の設計
  4. 書き換え機能の設計
  5. パスを作成する
  6. パスを同じ方向の他のパスとマージして、それらがインターリーブするようにします
  7. 燃料を使ってパスを実行する
  8. 最適化されたグラフを必要な形式に変換します

どの段階で問題がありますか? ステップ 1 と 2 は、論文を読めばかなり簡単です。

また、基本ブロックの一般的な概念、つまり命令がブロックにマージされる理由、制御フロー グラフが個々の命令ではなくブロックで構成される理由、個々の命令ではなくブロックで分析が実行される理由も理解する必要があります。

書き換え関数は、ファクトを使用してブロック内の最後のノードを書き換える必要があります。したがって、ファクト ラティスには、「到達可能性に関する情報」だけでなく、宛先ブロック自体も含める必要があります。

于 2011-08-21T18:59:44.670 に答える