コンパイラ演習 第11回 2006/1/19 大山 恵弘 佐藤 秀明.

Slides:



Advertisements
Similar presentations
G ゼミ 2010/5/14 渡辺健人. パフォーマンスの測定 CUDA Visual Profiler CUDA の SDK に標準でついているパフォーマン ス測定用のツール 使い方: exe ファイルのパスと作業ディレクトリ指定して実 行するだけ 注意点 : GPU のコード実行後にプログラム終了前に,
Advertisements

コンパイラ演習 第 6 回 2005/11/17 大山 恵弘 佐藤 秀明. 今回の内容 実マシンコード生成 – アセンブリ生成 (emit.ml) – スタブ、ライブラリとのリンク 末尾呼び出し最適化 – 関数呼び出しからの効率的なリターン (emit.ml) –[ 参考 ]CPS 変換 種々の簡単な拡張.
コンパイラ演習 第 6 回 (2011/11/17) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴 潮田 資秀 小酒井 隆広 山下 諒蔵 佐藤 春旗 大山 恵弘 佐藤 秀明 住井 英二郎.
プログラミング実習 1 ・ 2 ク ラス 第 2 週目 担当教員 : 渡邊 直樹. 課題 2 ● 2 × 2型行列の固有値, 固有ベクトルを求め る EigMatrix.java というプログラムを作成せ よ。 ● 行列の各要素はコマンド・プロンプトから入力 ● 計算した結果もコマンド・プロンプトに表示.
プログラミング言語論 第10回(演習) 情報工学科 木村昌臣   篠埜 功.
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第3回 配列(1) 情報・知能工学系 山本一公
2006/10/26 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第5回 関数(1) 情報・知能工学系 山本一公
(Rubyistのための) 超音速:ML入門
2006/11/9 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
JavaScript プログラミング入門 2006/11/10 神津.
関数(1) 第11回 [6月29日、H.16(‘04)] 今日のメニュー 1 前回の課題 2 前回の宿題 3 いろいろな関数の演習 4 課題
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第4回 配列(2) 情報・知能工学系 山本一公
プログラミング基礎I(再) 山元進.
ML 演習 第 1 回 佐藤 春旗, 山下 諒蔵, 前田 俊行 May 30, 2006.
ML 演習 第 8 回 2007/07/17 飯塚 大輔, 後藤 哲志, 前田 俊行
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
2006/11/30 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
コンパイラ演習番外編 (その1): min-rt 改 コンテスト
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
プログラミング演習Ⅱ 第12回 文字列とポインタ(1)
プログラミング基礎I(再) 山元進.
2006/10/12 山下 諒蔵 佐藤 春旗 前田俊行 大山 恵弘 佐藤 秀明 住井 英二郎
OCommand : 型安全な シェルプログラミングのための 領域特化言語の提案
プログラミング演習II 2004年10月19日(第1回) 理学部数学科・木村巌.
コンパイラ演習 第12回 2006/1/26 大山 恵弘 佐藤 秀明.
2006/12/7 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2007/1/18 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
プログラミング実習 1・2 クラス 第 1 週目 担当教員:  渡邊 直樹.
2006/10/19 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井英二郎
2006/11/02 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
条件式 (Conditional Expressions)
2006/11/16 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
配列の扱い、探索 有効範囲と記憶域期間 第12回 [7月10日、H.15(‘03)] 今日のメニュー 1 前回の課題の復習
コンパイラ演習 第 4 回 (2011/10/27) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴
2007/1/11 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
シミュレーション演習 G. 総合演習 (Mathematica演習) システム創成情報工学科
岩村雅一 知能情報工学演習I 第8回(後半第2回) 岩村雅一
ML 演習 第 4 回 末永 幸平, 遠藤 侑介, 大山 恵弘 2005/06/21.
情報工学科 3年生対象 専門科目 システムプログラミング 第5回、第6回 ヒアドキュメント レポート課題 情報工学科 篠埜 功.
暗黙的に型付けされる構造体の Java言語への導入
動的依存グラフの3-gramを用いた 実行トレースの比較手法
プログラミング演習(2組) 第8回
最適化の方法 中田育男著 コンパイラの構成と最適化 朝倉書店, 1999年 第11章.
第7回 プログラミングⅡ 第7回
A Provably Sound TAL for Back-end Optimization について
国立情報学研究所 ソフトウェア研究系 助教授/
順序付き線形型に基づく 木構造処理プログラムから ストリーム処理プログラムへの変換
依存型で型付けされた 副作用のある関数のための 型保存コンパイラ
バイトコードを単位とするJavaスライスシステムの試作
フロントエンドとバックエンドのインターフェース
 型推論3(MLの多相型).
データ構造とアルゴリズム (第5回) 静岡大学工学部 安藤和敏
知能情報工学演習I 第11回( C言語第5回) 課題の回答
プログラミング基礎a 第4回 C言語によるプログラミング入門 条件判断と反復
PROGRAMMING IN HASKELL
2008/7/16(情報コース)2008/7/22(通信コース) 住井
~sumii/class/proenb2009/ml6/
PROGRAMMING IN HASKELL
~sumii/class/proenb2010/ml5/
言語プロセッサ 第12日目 平成20年1月9日.
SMP/マルチコアに対応した 型付きアセンブリ言語
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
PROGRAMMING IN HASKELL
プログラミング演習II 2003年11月19日(第6回) 木村巌.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
情報処理Ⅱ 小テスト 2005年2月1日(火).
C言語講座第5回 2017 構造体.
情報処理Ⅱ 第3回 2004年10月19日(火).
Presentation transcript:

コンパイラ演習 第11回 2006/1/19 大山 恵弘 佐藤 秀明

今回の内容 バリアント/レコード パターンマッチ 表現方法 型付け switch文への変換 簡単な最適化 マッチング漏れ 以降のフェーズでの処理 発展 exhaustiveness informationの利用 パターン式の拡張

バリアント/レコード

バリアントのメモリレイアウト 先頭にタグを追加したタプルのように配置 タグ名は整数にエンコード 要素数は可変 異なるtypeのタグは同じ整数を使用してもよい 要素数は可変 type t = A of string * int | B | C of string | ... (0, “str1”, 13) または (1) または (2, “str2”) または... A → 0 B → 1 C → 2 ...

レコードのメモリレイアウト ラベル名でソートしたタプルのように配置 type s = {foo: string; bar: int; baz: float} type s = {bar: int; baz: float; foo: string} (3, 4.22, "hoge") ソート

中間コード上での表現 新たにプリミティブを追加 既存のプリミティブに吸収してもよい 実装方法は各自の判断に任せます バリアント: 生成/タグ名取得/要素取得 レコード: 生成/要素取得 既存のプリミティブに吸収してもよい 損をすることもある かえって実装が大変 最適化の精度が落ちる 実装方法は各自の判断に任せます

型付け タグ名/ラベル名と型情報との関連を管理 外部関数としてまとめておくとよい タグ名/ラベル名から型は一意に決定 複数のtypeで同じ名が使用される場合はエラー type t = A of string * int | B | C of string | ... TagEnv(A) = (t, [string; int]) TagEnv(B) = (t, []) TagEnv(C) = (t, [string]) type s = {bar: int; baz: float; foo: string} LabelEnv(bar) = LabelEnv(baz) = LabelEnv(foo) = (s, [bar→int; baz→float; foo→string])

パターンマッチ

パターン式の導入 基本的な定義 拡張は後述 p ::= (パターン式) | _ (ワイルドパターン) | c (定数パターン) | x | (p1, ..., pn) | c p | {l1=p1; ...; ln=pn} (パターン式) (ワイルドパターン) (定数パターン) (変数パターン) (タプルパターン) (バリアントパターン) (レコードパターン)

パターン式の型付け(1/2) 同じ名前の変数はパターン式の中に 2回以上出現できない Γ |- p : τ, (B) 同じ名前の変数はパターン式の中に 2回以上出現できない 型システムで保証すると楽 Γ |- p : τ, (B) Γ: 前提となる型環境 p: 型付けするパターン式 τ: pの型 B: pの中で束縛される変数の型環境

パターン式の型付け(2/2) (変数パターン) Γ |- x : τ, (x : τ) パターン式で束縛 された変数の型環境 (タプルパターン) Γ |- p1 : τ1, (B1) ... Γ |- pn : τn, (Bn) for all i≠j, varname(Bi)∩varname(Bj) = 0 Γ |- (p1, ... , pn) : τ1×…× τn, (B1, ... , Bn) タプルの各要素で束縛された変数の 名前が重複していないことを確認

match文の導入 基本的な定義 拡張は後述 e ::= (式) ... match e with (パターンマッチ) p1 -> e1 | ... | pn -> en (式) (パターンマッチ)

match文の型付け パターン式が束縛した変数の型環境を利用 Γ |- e : τ Γ |- p1 : τ, (B1) Γ, B1 |- e1 : τ' ... Γ |- pn : τ, (Bn) Γ, Bn |- en : τ' Γ |- match e with p1 ->e1 | ... | pn ->en : τ'

switch文への変換 match文を低レベルなプリミティブに分解 一見うまくいきそうだが… 定数とのマッチング→switch 変数束縛→let 一見うまくいきそうだが… e ::= ... switch e with c1 -> e1 | ... | cn -> en | _ -> e' (式) (switch)

ナイーブに変換すると errorならばe2に実行が 移ることをどう表現するか? 処理の巻き戻し match e with (1, 2, v, 4) -> e1 | (_, _, _, _) -> e2 let (x1, x2, x3,x4) = e in switch x1 with 1 -> (switch x2 with 2 -> let v = x3 in (switch x4 with 4 -> e1 | _ -> error) | _ -> e2

いろいろな案 マッチングの成否をoption型で表現して返す マッチングの失敗を例外として処理 errorの後にすることを継続として渡す match e1 with Success(result) -> result | Failure -> e2 バリアントの生成/展開を毎回行うコスト マッチングの失敗を例外として処理 try e1 with MatchFailure -> e2 例外処理によるオーバヘッド増加 errorの後にすることを継続として渡す クロージャ作成/関数呼び出しが重い errorの後にすることをインライン展開 errorが複数存在するときはコード量爆発 最適化のフェーズでやるべきことかも

解決策: 専用プリミティブの追加 fail_match handle_match e1 e2 手続き型的な挙動を表現 マッチングに失敗 handle_match e1 e2 e1の評価中fail_match に到達したらe2の評価 にジャンプ 手続き型的な挙動を表現 大域的脱出みたいなもの ただのジャンプだから軽い let (x1, x2, x3,x4) = e in handle_match (switch x1 with 1 -> (switch x2 with 2 -> let v = x3 in (switch x4 with 4 -> e1 | _ -> fail_match) e2

バリアント/レコードの処理 タプル同様に展開して各要素をマッチング バリアントの場合はタグも展開してマッチング タグは整数定数と同じように扱える match e with {a=1; b=2} -> e1 | {a=2; b=3} -> e2 match e with A(1, 2) -> e1 | B -> e2 let (a, b) = fields(e) in switch a with 1 -> (switch b with 2 -> e1 | _ -> fail_match) | 2 -> ... | _ -> fail_match let t = tag(e) in switch t with A -> let (x1, x2) = fields(e) in (switch x1 with ...) | B -> e2 | _ -> fail_match

簡単なマッチング最適化(1/2) 先頭パターンから定数が連続するとき 連続する定数の種類ごとにまとめてマッチング 定数が連続する部分の候補に結局マッチ しなかったらそれ以降の候補にジャンプ let (x1, x2) = e in handle_match (switch x1 with 1 -> (switch x2 with 8 -> e1 | 10 -> e3 | _ -> fail_match) | 2 -> e2 let v = x1 in e4 match e with ( 1 , 8 ) -> e1 | ( 2 , _ ) -> e2 | ( 1 , 10 ) -> e3 | ( v , _) -> e4

簡単なマッチング最適化(2/2) 先頭パターンから同じ名前の変数が 連続するとき まとめて変数束縛 先頭パターンから同じ名前の変数が 連続するとき まとめて変数束縛 連続するのがワイルドパターンなら束縛すら不要 let (x1, x2) = e in handle_match (let v = x1 in switch x2 with 8 -> e1 | 10 -> e2 | _ -> fail_match) switch x1 with 1 -> e3 | _ -> fail_match match e with ( v , 8 ) -> e1 | ( v , 10 ) -> e2 | ( 1 , _) -> e3

マッチング漏れ handle_matchで捕捉されないfail_match =マッチするパターンがない場合 対処法の例 コンパイル時に警告だけ表示 実行時の異常終了を実現するしくみが必要 例外処理の枠組みで対処してもよい マッチング漏れがあればコンパイルを通さない

以降のfail_matchの扱い 生きている変数 スタック/レジスタ割り当ての状態 アセンブリ生成 FV(fail_match)=(以降の処理で生きている変数) スタック/レジスタ割り当ての状態 fail_matchに到達したら破棄してよい 次の処理を追跡する前に状態を巻き戻す アセンブリ生成 その後に実行するコードへジャンプ

switchのアセンブリ生成 caseの数による 2〜3個程度ならif-then-elseの 連鎖でよい mul x, 4, y ld [table+y], z b z nop ... table: .word label_e0 .word label_e1 .word label_e2 label_e0: (e0の処理) label_e1: (e1の処理) label_e2: (e2の処理) caseの数による 2〜3個程度ならif-then-elseの 連鎖でよい それ以上ならジャンプテーブルを 作成 switch x with 0 -> e0 | 1 -> e1 | 2 -> e2 | ...

発展: exhaustiveness information 型情報やマッチングの文脈から いろいろなことが分かる マッチングが必ず成功するパターン マッチングが必ず失敗するパターン 絶対に使用されないパターン 評価結果を変えない判定順序入れ替え 行: 各マッチング候補間の判定順序 列: パターン中の各要素間の判定順序 コンパイル時に活用可能 コード最適化 冗長/不完全なmatch式について警告を出す

コード最適化の例(1/3) 最適化しないと let (x, y) = tag(x0), tag(y0) in handle_match (switch x with [] -> 1 | _ -> fail_match) (handle_match (switch y with [] -> 2 (::) -> (::) -> 3 | _ -> fail_match)) 最適化しないと match x0, y0 with [], _ -> 1 | _, [] -> 2 | _::_, _::_ -> 3 リストは[]、(::)をタグにもつ バリアントとみなす

コード最適化の例(2/3) match文の第2・第3 パターンを入れ替え 絶対に使われない パターンを削除 let (x, y) = tag(x0), tag(y0) in handle_match (switch x with [] -> 1 | (::) -> (switch y with (::) -> 3 | _ -> fail_match) [] -> 2 let (x, y) = tag(x0), tag(y0) in handle_match (switch x with [] -> 1 | (::) -> (switch y with (::) -> 3 | _ -> fail_match)) (switch y with [] -> 2)

コード最適化の例(3/3) 冗長なマッチング 判定を削除 サイズの小さい式を インライン展開 不要なhandle_match を除去 let (x, y) = tag(x0), tag(y0) in handle_match (switch x with [] -> 1 | _ -> (switch y with (::) -> 3 | _ -> fail_match)) 2 let (x, y) = tag(x0), tag(y0) in handle_match (switch x with [] -> 1 | _ -> (switch y with (::) -> 3 | _ -> 2)) 2 let (x, y) = tag(x0), tag(y0) in switch x with [] -> 1 | _ -> (switch y with (::) -> 3 | _ -> 2) 最適化の適用例:  最大反復回数を定め、変化がなくなるまで各フェーズを反復

発展: パターン式の拡張 p1 | ... | pn p when e p1 as p2 型システムで保証するとよい p when e eが不成立ならfail_match p1 as p2 let p = e 、let rec f p1 ... pn = e など

共通課題 次のmatch文をswitch文に変換せよ。 「最良」と思われる変換結果を提出せよ 「処理の巻き戻し」をどう表現するかは自由 「最良」の定義は各自で設定すること 「処理の巻き戻し」をどう表現するかは自由 match e with (_, A(4)) -> e1 | (_, A(5)) -> e2 | (1, B) -> e3 | (3, B) -> e4 | (1, A(2)) -> e5 | (1, A(x)) -> e6 | (y, _) -> e7 ただし第2要素の持ちうるタグはAとBのみ

コンパイラ係用選択課題 パターンマッチを自作コンパイラに実装せよ。 以下のパターンを扱えるようにすること マッチング漏れに「対処」すること ワイルドパターン 定数パターン 変数パターン バリアントパターン マッチング漏れに「対処」すること その他の実装方針は自由に決めてよい

課題の提出先と締め切り 提出先: compiler-enshu@yl.is.s.u-tokyo.ac.jp 共通課題の締め切り: 2週間後(2/2)の午後1時 コンパイラ係用課題の締め切り: 2006年3月31日 Subject: report 11 <学籍番号> <アカウント > 本文にも氏名と学籍番号を明記のこと

課題の提出についての注意 プログラムだけでなく、説明・考察・感想な ども書くこと 基本的にはメールの本文に解答を記述 多くのソースを送る必要がある課題では、 ソースをtarファイルなどに固めてメールに 添付のこと

参考文献 Caml Lightでのパターンマッチ実装法 OCamlが採用したパターンマッチ最適化の手法 “The ZINC experiment: an economical implementation of the ML language” http://pauillac.inria.fr/~xleroy/publi/ZINC.ps.gz OCamlが採用したパターンマッチ最適化の手法 “Optimizing Pattern-Matching” http://pauillac.inria.fr/~maranget/papers/opt-pat.ps.gz パターンマッチ最適化のheuristics “When Do Match-compilation Heuristics Matter?” http://www.cs.virginia.edu/~techrep/CS-2000-13.pdf