第13回
コンパイラ理論
1. 型推論
2. 最適化とコード出力
コンパイラの構成と最適化
中田 育男 (著)
ISBN: 9784254121773
画像は https://www.amazon.co.jp/dp/4254121776 より引用
1
コンパイラの流れ
型情報付き
AST
中間コード (命
令列)
出力コード
中間コード生成
最適化
レジスタ割り付け
プログラム
トークン列
構文木
抽象構文木
字句解析
構文解析
抽象構文木生成
型推論
型検査
2
抽象構文木の生成
コンパイラ内部では、構文木から抽象構文木へ変換することで、型付けからの処理を構
文 (や言語体系) に依存せず行う
let rec fib n =
if n <= 2 then 1
else fib (n - 1) + fib (n - 2)
LetRec("fib", [n],
If(
Le(Var("n"), Const(2)),
Const(1),
Add(
Call("fib", [Sub(Var("n"),Const(1))]),
Call("fib", [Sub(Var("n"),Const(2))]))))
3
13-1型推論
4
型付けと型推論 (再掲)
関数や変数に値を束縛する際、その型を定める必要がある。これを型付け (Typing) と
いう
言語によっては型の略記を許すこともあり、コンパイラが関数や変数の型を推論 (Type
inference) しなければならないことがある
let add x y =
x + y
let x = 10
add : int → int
x : int
5
型環境
コンパイラは、プログラムの解釈とともに、型環境を拡張していく。後続のプログラムは、
型環境から変数の型を判断していく
いわば型環境は、既に束縛された変数の型を記憶する集合とみなせる
let a = 10 in let b = 20 in a + b
∅ a : int
a : int
b : int
6
推論規則
型推論を行うためには推論規則とよばれるルールを定めて、その規則にしたがって型付
けをおこなっていく
推論規則による導出木を組み立てていくことで、型推論を行うことができる
Γ ⊢ if E1
then E2
else E3
: T
Γ ⊢ E1
: bool Γ ⊢ E2
: T Γ ⊢ E3
: T
true : bool false : bool
導出木を下から
組みあげていく
型環境 Γ で E3
は型 T
に評価できる、の意
true, false は
そもそも bool 型
7
型推論 - let 文
let 式 (値への変数の束縛) の場合は、次のような構造を取る
E1
の型の評価が行われ、その結果を v の型として型環境に追加する。E2
の評価では
v の型が記載された型環境が用いられる
let v = E1
in E2
v : a Γ ⊢ let I = E1
in E2
: T2
Γ ⊢ E1
: T1
Γ, x:T1
⊢ E2
: T2
8
型推論 - let rec 文
let rec 文では E1
中に I の出現がある可能性がある
先に I を型 α としてみなす型環境を追加する。E1
の型の評価では、I:α の型環境で
評価が行われ、その結果を α と同一化 (unify) する。E2
の評価では、型が記載された
型環境が用いられる
let rec I = E1
in E2
I : α
9
[課題] 型推論および演算
第11回で示した次の文法について、評価するプログラムを作成せよ
V → true | false
V → 整数値 (-1000 から 1000 まで)
E → V | (E) |
E + E | E - E | E * E | E / E |
E & E | E | E | E = E | E <> E
Cond → if E then E else E
10
13-2最適化とコード出力
11
コード出力について
● 中間コード生成
● 最適化
○ 定数の畳み込み
○ 共通部分式の除去
○ 不要命令の削除
○ インライン化
● コード出力
○ レジスタ割り付け
12
中間コード生成
実際に CPU が実行できるように近づけるコード変換を中間コード生成とよぶ
let rec fib n =
if n <= 2 then 1
else fib (n - 1) +
fib (n - 2)
let rec fib n =
let x = n <= 2 in
if x then
1
else
let a = n - 1 in
let b = fib a in
let c = n - 2 in
let d = fib c in
let e = b + d in
e
Function fib(n) {
x = n <= 2;
Jump to E1 if !x;
Return 1;
E1:
a = n - 1;
b = Call fib(a);
c = n - 2;
d = Call fib(c);
e = b + d;
Return e;
}
変換のイメージ:
13
定数の畳み込み
計算式の途中で定数がある場合に、実行時に演算を行うのではなく、コンパイラが演算
した結果を出力コードに埋め込む方式
a ← 10
b ← 20
c ← a + b
return c
14
a ← 10
b ← 20
c ← 30
return c
共通部分式の除去
計算式の一部に共通する部分式が存在する場合、それらを先に計算し、くくりだしを行う
最適化
x ← (a + b) * c
y ← (a + b) * d
w ← a + b
x ← w * c
y ← w * d
15
不要な命令の削除
命令の結果が使われない場合、その命令に副作用がなければ削除してしまうことがで
きる
a ← 10
x ← array[a]
c ← a + b
return c
不要な命令
16
インライン化
関数が軽量で、呼び出し箇所が少なく、繰り返し呼ばれる場合には、関数の実体を呼び
出し元のコードに埋め込むことができる
max(a,b) {
return
a < b ? b : a;
}
...
e = c < d ? d : c;
...
...
e = max(c, d);
...
17
レジスタ割り付け
プログラムの実行中の途中計算結果は、有限のレジスタ数に記録する必要がある。した
がって演算結果をどのレジスタで管理するか割り当てなければいけない
$3 ← $1 + $2
$3 ← $1 + $3
$3 ← $3 - $1
$1 ← $3 - $2
...
c ← a + b
d ← a + c
e ← d - a
f ← e - b
...
18
生存解析
プログラムについて、各ステートメントをノードとみなしたグラフを生成する
● あるノードが利用する変数の集合
● あるノードが生成する変数の集合
このときデータフロー方程式を計算することで
あるノード n における生存している変数の集合
が考えられる
c ← a + b
d ← a + c
e ← d - a
f ← e - b
19
レジスタ割り付けにおける彩色問題
生存解析の結果、同時に生存しなければならない変数同士をむすぶグラフを作成
隣接ノード同士が別の色で彩色されるよう、作成したグラフ上において、彩色問題の近
似アルゴリズムを走らせる (厳密解を求めるなら NP)
a b
c
d e
20
a b
c
d e
第13回 まとめ
1. 型推論
● 型付け
● 推論規則
2. 最適化とコード出力
● 中間コード出力
● 定数の畳み込み (定数伝播), コピー伝播
● 共通部分式除去
● 不要命令除去
● 生存解析
● レジスタ割付
21

[Basic 13] 型推論 / 最適化とコード出力