run-time code generation and modal-ml の紹介@pldir#2
DESCRIPTION
PLDIr#2 (2009-09-30) での紹介。元ネタはPLDI'98。TRANSCRIPT
“Run-time Code Generation and
Modal-ML” (Philip Wickline,Peter Lee, Frank Pfenning)
PLDIr #2 (PLDI’98) 2009-09-30
酒井政裕
Citation Count: 14
概要とポイント
� 実行時コード生成フレームワークの提案
� 言語はMLをS4様相型(+α)で拡張
� CAM(Categorical Abstract Machine)の拡張へ
とコンパイル
� 多段のコード生成を許す言語を、それを許さない実行モデル向けにコンパイルするテクニック
目次
� 実行時コード生成
� ML□
� プログラム例
� 抽象マシンへのコンパイル
� まとめ
実行時コード生成
� 計算を複数のステージにうまく分割できれば、前の計算結果を後の計算の高速化に活用して、パフォーマンスを劇的に向上できる
� ステージの情報がわかれば、コンパイラは実行時コード生成を行うようなコードを生成して、これを実現できる。� 利点
� レジスタ割り当てなどのソースコード上の変換では扱いにくい最適化が可能(?)
� 実行時までわからない値を活用:ループ展開、配列の範囲チェックの除去など
例: 多項式の値の計算
type poly = int list;
val poly1 = [2,4,0,2333]
(* val evalPoly : int * poly -> int *)
evalPoly (x, nil) = 0
evalPoly (x, a::p) = a + (x * evalPoly (x, p));
ステージ情報の与え方
� 人手で与えることが多い� Lisp のマクロの backquote と unquote 記法など
� 直観的
� 変数の意図しない捕獲、マクロの無限の展開など、間違えやすい。
� 例外: 部分評価
� 入力が最初のステージで入手可能かという情報を与えることによって、半自動的に。
� また、束縛時解析も用いられる。
提案するアプローチと言語
� 原理に基づいたシステマティックなアプローチ� 型とか使ってフォーマルに
� 提案する言語: ML□
� 重量級で、振る舞いが予測困難な解析アルゴリズムではなく、直接ステージの情報をコンパイラに指示。
� ステージングのエラーは型エラーになる。また、型を使ってステージ化の仕方を概念化できる。
� 他の解析手法とは補完的。ユーザによる記述を解析で補ってもオッケー。
� 多段のステージを自然に表現できる。
目次
� 実行時コード生成
� ML□
� プログラム例
� 抽象マシンへのコンパイル
� まとめ
ML□
� 単純型付きラムダ計算に型構築子□を追加
� 型□τは「型τのプログラムを生成するコード生成器」の型
� 生成器は code M という式で作られる
� 例: code (λx. x) : □(α→α)
� 後述する演算子 lift を除けば、S4様相論理にカ
リーハワード対応
構文
� Type Variables α, β, γ
� Types τ, σ ::= α | τ→σ | □τ
� Terms M,N ::= x | λx.M | M N | u | code M |lift M |let cogen u = M in N end
� Contexts Γ ::= ・ | Γ, x:τ | Γ, u : τ
� x は value variable
� u は code variable
例
� code (λx. x)
: □(α→α)
� λx. let cogen u = x in u end
: (□α) →α
� λf. λg. let cogen f’ = f in
let cogen g’ = g in
code (λx. f’ (g’ x)) end
: □(β→γ)→□(α→β)→□(α→γ)
実際にはlet cogenの時点では
コード生成されず、束縛した変数が使われるときにコード生成される
後の方が最適化の余地が大きいので
let cogen で □αの式からαの式が得られる
codeは一種のquote
型付け規則 (の一部)
� 文脈が、value variable のコンテキストΓ、code variable の文脈⊿に分かれている。
� (実際のコード生成を let cogenから遅延することの帰結か?)
⊿; ・ ⊢ M : τ
─────────⊿; Γ ⊢ code M : τ
⊿; Γ ⊢ M : □τ (⊿, u : τ); Γ ⊢ N : σ───────────────────⊿; Γ ⊢ let cogen u = M in N end : σ
x : τ in Γ
───────⊿; Γ ⊢ x : τ
Mは自由なvalue
variable を持てない!
lift
� 元にした Davies and Pfenningの Mini-MLe□に
は無かった演算だけど、便利なので追加
� 式ではなく評価結果の値のquote
� コード生成に使うときは一切の最適化をしない
� 様相論理に対応しない
⊿; Γ ⊢ M : τ
─────────⊿; Γ ⊢ lift M : □τ
α→□αは pathetic
なフレームに対応するが??
目次
� 実行時コード生成
� ML□
� プログラム例
� 抽象マシンへのコンパイル
� まとめ
プログラム例: 多項式の値の計算
(* val compPoly : poly -> [int -> int] *)
fun compPoly (nil) = code (fn x => 0)
| compPoly (a::p) =
let cogen f = compPoly p
cogen a’ = lift a
in code (fn x => a’ + (x * f x)) end ;
val codeGenerator = compPoly poly1 ;
val mkPolyFun = eval codeGenerator;
[τ] は□τのこと
� パケットフィルター用の言語のコンパイルの例
� 外部から与えられたパケットフィルターをカーネル空間で動かしたいけど、安全でないコードを動かすわけにはいかないので、専用言語で与えてインタープリターで解釈している。
� 動的コード生成できれば性能向上できる。
� コード生成器をメモ化で共有する工夫
� 今回は省略
目次
� 実行時コード生成
� ML□
� プログラム例
� 抽象マシンへのコンパイル
� まとめ
コンパイルターゲット
� 単純なスタックマシンの CAM を拡張したCCAM をターゲットに
� CAM = Categorical Abstract Machine
� 余談: Camlは Categorical Abstract Machine
Language の略だったんだよ
� CAMの詳細について紹介するのは面倒なので、
概要のみ
emit(i)
� CCAMはCAMに、以下のような命令を追加� 命令の出力先を確保する arena命令
� 命令iの出力を表す emit(i) 命令
� 実際のマシンでは emit(i) は例えば以下のような命令列� iの値の下位16bitを即値からロードする命令
� iの値の上位16bitを〃
� それらを合わせて書き出す命令
� emit(add) は実際には引数が0かどうかを調べて、特殊化したりするかも
基本的なコンパイル方針
� M が i1;i2;?;inにコンパイルされるとき、code M を emit(i1);emit(i2);?;emit(in) に
コンパイル
� ただし、コード変数の出現は、コード生成器の呼び出しにコンパイル。
入れ子の emit(i) ?
� ML□ では code (? code M ?) のような式を書ける
� code M のコンパイル結果に emit(i) が含まれるとき、それを emit(emit(i)) にする?
� 実際のマシンでは即値の空間は有限なので、命令を一つemitするには少なくとも2命令必要
� n 段のネスト emit(emit(?emit(i)?)) は、実際には 2n
の長さの命令になり、code blow-up !
� ⇒入れ子のemit命令は許さない
入れ子の codeの取り扱い
� 基本的なアイディア� code (? code M ?) という入れ子があったら、let cogen u = lift (code M)in code (?u?) end に変換。
� もちろん、Mが自由なコード変数を含んでいたら、うまくいかない。� code (let cogen u’ = N in code (u’ + M) end)
� これを変換すると u’が束縛されていない状態に?
� let cogen u = lift (code (u’ + M))in code (let cogen u’ = N in u end) end
ではどうするのか
� MLレベルではどうにもならないけど、使われるときにCAMレベルで環境を操作して、元もとあった場所の環境を参照!
� そ、そんな??
コンパイル方法の詳細
� 6.2 Details of the Compilation Scheme は
技巧的で面白いのだけど、面倒くさいので、今回は省略。
実装 / 評価
� プロトタイプのコンパイラを実装� ソース: 代数的データ型、リファレンス、配列など、ML
のコアをほとんど含むよう拡張した ML□
� ターゲット: 条件分岐、再帰、様々な基本型で拡張したCCAM
� CCAMのシミュレーターを実装
� CCAMでの簡約ステップ数で評価
評価
コード生成器の作成
コード生成の実行
生成されたコードの実行
まとめ
� ML□は実行時のコード生成のコントロールに必
要なステージの情報を正確に表現できる
� ステージを明示的にコントロールできる言語は、プログラムの性能を向上する実用的な手法
� Mini-MLe□の型付きのフレームワークは、 ML□
とその処理系の形式化の基礎を提供してくれた
� この枠組みは、他の言語やコンパイル手法にも拡張できて、ステージ計算一般の推論に使えるはず