2006/11/9 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎

Slides:



Advertisements
Similar presentations
1 B10 CPU を作る 1 日目 解説 TA 高田正法
Advertisements

コンパイラ演習 第 6 回 2005/11/17 大山 恵弘 佐藤 秀明. 今回の内容 実マシンコード生成 – アセンブリ生成 (emit.ml) – スタブ、ライブラリとのリンク 末尾呼び出し最適化 – 関数呼び出しからの効率的なリターン (emit.ml) –[ 参考 ]CPS 変換 種々の簡単な拡張.
コンパイラ演習 第 6 回 (2011/11/17) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴 潮田 資秀 小酒井 隆広 山下 諒蔵 佐藤 春旗 大山 恵弘 佐藤 秀明 住井 英二郎.
コンパイラ演習 第 12 回 (2012/01/05) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴 潮田 資秀 小酒井 隆広 山下 諒蔵 佐藤 春旗 大山 恵弘 佐藤 秀明 住井 英二郎.
2006/10/26 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
コンパイラ 2011年11月14日
ML 演習 第 1 回 佐藤 春旗, 山下 諒蔵, 前田 俊行 May 30, 2006.
ML 演習 第 8 回 2007/07/17 飯塚 大輔, 後藤 哲志, 前田 俊行
2006/10/5 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/11/30 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
実行時のメモリ構造(1) Jasminの基礎とフレーム内動作
コンパイラ演習番外編 (その1): min-rt 改 コンテスト
2006/10/12 山下 諒蔵 佐藤 春旗 前田俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2012年度 計算機システム演習 第4回 白幡 晃一.
コンパイラ演習 第 9 回 (2011/12/08) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴
2006年度 計算機システム演習 第4回 2005年5月19日.
コンパイラ演習 第12回 2006/1/26 大山 恵弘 佐藤 秀明.
2006/12/7 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2007/1/18 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/10/19 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井英二郎
2006/11/02 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/11/16 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
コンパイラ演習 第 4 回 (2011/10/27) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴
の まとめ 2007/04/02 (Mon) / d;id:hzkr
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
2007/1/11 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
Tokuda Lab. NISHIMURA Taichi
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
型付きアセンブリ言語を用いた安全なカーネル拡張
コンパイラの解析 (4) 例外処理.
プログラミング言語入門 手続き型言語としてのJava
第10回関数 Ⅱ (ローカル変数とスコープ).
最適化の方法 中田育男著 コンパイラの構成と最適化 朝倉書店, 1999年 第11章.
Cプログラミング演習 第7回 メモリ内でのデータの配置.
プログラミング言語入門.
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
依存型で型付けされた 副作用のある関数のための 型保存コンパイラ
コンパイラ演習 第11回 2006/1/19 大山 恵弘 佐藤 秀明.
コンパイラ資料 実行時環境.
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
オブジェクト指向プログラミングと開発環境
演習0 func0, func1, func2を作成せよ. main()関数の中で,func0()を呼び出しを実行せよ.
JAVAバイトコードにおける データ依存解析手法の提案と実装
2007/6/12(通信コース)2007/6/13(情報コース) 住井
プログラムが実行されるまで 2002年4月14日 海谷 治彦.
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
コンピュータアーキテクチャ 第 5 回.
~sumii/class/proenb2010/ml2/
高度プログラミング演習 (11).
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
2006/6/27(通信コース)2006/7/5(情報コース) 住井
コンピュータアーキテクチャ 第 5 回.
~sumii/class/proenb2009/ml6/
Eijiro Sumii and Naoki Kobayashi University of Tokyo
言語プロセッサ 第12日目 平成20年1月9日.
X64 函数呼び出し規約 長谷川啓
コンパイラ 2012年10月11日
コンパイラ 第12回 実行時環境 ― 変数と関数 ― 38号館4階N-411 内線5459
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
関数と再帰 教科書13章 電子1(木曜クラス) 2005/06/22(Thu.).
プログラミング演習I 2003年6月11日(第9回) 木村巌.
情報システム基盤学基礎1 コンピュータアーキテクチャ編
第10回 関数と再帰.
オブジェクト指向言語論 第三回 知能情報学部 新田直也.
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
情報処理Ⅱ 小テスト 2005年2月1日(火).
計算技術研究会 第5回 C言語勉強会 関数(function)を使う
6.5 最終コード生成 (1)コードの形式 ①絶対2進コード(AB : absolute binary) 命令後のオペランドが絶対番地指定。
Presentation transcript:

2006/11/9 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎 コンパイラ演習 第 6 回 2006/11/9 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎

今回の内容 実マシンコード生成 アセンブリ生成 (emit.ml) スタブ、ライブラリとのリンク 末尾呼び出し最適化 [参考] CPS 変換 種々の簡単な拡張 MinCaml にない機能

実マシンコード生成

アセンブリ生成 save/restore をストア/ロードとして明示化 スタックの状態を追跡 (stackmap, stackset) if 文の合流後は両方のスタックの積集合をとる 関数呼び出し規約の明示化 引数を正しいレジスタにセット (shuffle関数) リターンアドレスの save/restore スタックポインタの管理 条件分岐の明示化 分岐用・合流用のラベルを導入 他は単純

外部ファイル スタブ (stub.c) ヒープとスタックを確保 その後 MinCaml のエントリポイントを call ライブラリ (libmincaml.s) 外部関数を定義 入出力 配列生成 数値計算 自作 CPU 向けの外部ファイルも必要かも アーキテクチャ次第

ビルドの流れ MinCamlソース MinCamlコンパイラ SPARCアセンブリ 自作CPUアセンブリ stub.c (自作スタブ) 自作アセンブラ 自作リンカ libmincaml.s (自作ライブラリ) SPARCバイナリ 自作CPUバイナリ

末尾呼び出し最適化

末尾呼び出し let rec fact x r = if x <= 1 then r else fact (x – 1) (r * x) 関数の最後の処理が call

単純にコンパイルすると… let rec fact x r = if x <= 1 then r else fact (x – 1) (r * x) save(Rret) add Rsp, 4, Rsp call fact nop sub Rsp, 4, Rsp restore(Rret) retl 返り番地だけから なるフレームを構成 返り番地を pop して 直ちにリターン

その結果 return address return address return address return address 無駄なフレームが 積みあがる! return address return address return address return address return address return address main関数のフレーム

何がいけなかったのか? どうすればよいのか? 問題の元凶: 末尾呼び出し直後の地点に 律義にリターン 時間的に無駄 問題の元凶: 末尾呼び出し直後の地点に 律義にリターン 時間的に無駄 何もしない地点へわざわざリターン 空間的にも無駄 リターンするために、返り番地を余分に退避 することがないなら、呼び出し元に 直接返ればよい! コンパイラが末尾呼び出しを認識

末尾呼び出し最適化 の例 let f x = … (g 8) - 3 let g y = h (y+1) let h z = z * 2 大元の呼び出し元に直接リターン!

末尾呼び出し最適化 末尾呼び出し時の 無駄なジャンプ・退避を除去 cf. 末尾再帰 関数の最後の処理が自分自身の再帰呼び出し 末尾呼び出し時の 無駄なジャンプ・退避を除去 cf. 末尾再帰 関数の最後の処理が自分自身の再帰呼び出し 末尾呼び出し最適化により、ループに変換

「if の直後に return」する場合 合流する必要がない cmp c0, x, y bg c0, L1 ...(then節)... b L2 L1: ...(else節)... L2: blr cmp c0, x, y bg c0, L1 ...(then節)... blr L1: ...(else節)... blr

「call の直後に return」する場合 callをただの goto にできる save(Rret) add Rsp, n, Rsp bl Lf sub Rsp, n, Rsp restore(Rret) blr b Lf

実装 変換中の式が末尾かどうかを管理 Tail: 末尾 末尾呼び出し最適化を実行、または 結果を返り値用のレジスタにセットしてリターン NonTail(r): 末尾でない 結果をレジスタ r にセット

[参考] CPS 変換 すべての call や if を tail にしてしまう! Nontail な関数適用/条件分岐の「継続」を生成 「継続」 ≒ 「その後にすること」 クロージャで表現する すべての関数定義/関数適用に 仮引数/実引数として継続を追加 関数の戻り値は継続に渡す α変換および A 正規化の完了した K 正規形に対して行うと簡単

CPS 変換のイメージ let rec f x = g x + 5 let rec g y = y + y ようにする

CPS 変換のイメージ let rec f x k = let c z = let r = z + 5 in k r in g x c let rec g y k = let r = y + y in k r g は実行が終わったら、引数にもらった 関数(クロージャ)を呼び出すことにより 「復帰」する

CPS 変換の利点/欠点 利点: 以降の処理が容易 関数呼び出し時の save/restore が不要 「リターンアドレス」の概念が不要 スタックも不要 欠点: クロージャが頻繁に生成/適用される 効率的なヒープ管理の必要性 inter-procedural なレジスタ割り当て エスケープ解析 generational garbage collection

種々の簡単な拡張

レコード、Variant レコード: フィールドが アルファベット順に並んだ tuple とみなす { foo = 3; bar = 7 } = { bar = 7; foo = 3 } ⇒ (7, 3) Variant: コンストラクタを整数で表し、 それを第1要素とする tuple にする type  list = Nil | Cons of  *  list として Nil ⇒ (0) Cons(x, y) ⇒ (1, x, y)

λ抽象、部分適用 λ抽象: let rec に置換 fun x → M ⇒ let rec f x = M in f (f は fresh な変数名) 部分適用: let rec と完全適用に置換 たとえば let rec f x y = x - y なら f 3 ⇒ let rec g y = f 3 y in g (g は fresh な変数名) 関数の型情報が必要

共通課題 (1/3) 以下のプログラムはどのようなアセンブリにコンパイルされるか、末尾呼び出し最適化をしない場合とする場合、それぞれについて説明せよ。 ヒント: 末尾呼び出し最適化をする場合、 手続き型言語でループを用いて書いた gcd と 同じアセンブリになる (はず) let rec gcd m n = if m <= 0 then n else if m <= n then gcd m (n – m) else gcd n (m – n) in print_int (gcd 21600 337500)

共通課題 (2/3) 以下のプログラムを手動で CPS 変換せよ K 正規化はしてもしなくてもよい let rec ack x y = if x <= 0 then y - -1 else if y <= 0 then ack (x - 1) 1 else ack (x - 1) (ack x (y - 1)) in print_int (ack 3 10)

共通課題 (3/3) 「種々の簡単な拡張」 (の一部) を用いる MLプログラムを書け。 それを既存のMLコンパイラが どうコンパイルするか調べ、解説せよ 同程度以上に複雑な他のプリミティブについて 調べてもよい

課題の提出先と締め切り 提出先: compiler-enshu@yl.is.s.u-tokyo.ac.jp 締め切り: 2 週間後 (11/23) の午後 1 時 Subject: Report 6 <学籍番号> <アカウント> 本文にも氏名と学籍番号を明記のこと

今後の予定 (変更の可能性あり) Polymorphism Variant/record & pattern matching Object-oriented extension Exception handling Garbage collection Alias analysis Escape analysis