annotate final_main/chapter4.tex @ 6:5b368e14bb64

update
author mir3636
date Tue, 14 Feb 2017 18:48:26 +0900
parents 6d00f6c9bb8a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
30a433a94a9a first commit
mir3636
parents:
diff changeset
1 \chapter{LLVM/clang による CbC の実装}
30a433a94a9a first commit
mir3636
parents:
diff changeset
2 \section{LLVM clang}
30a433a94a9a first commit
mir3636
parents:
diff changeset
3 LLVM とは、モジュラー構成および再利用可能なコンパイラとツールチェーン技術等を開発するプロジェクトの名称である。
30a433a94a9a first commit
mir3636
parents:
diff changeset
4 LLVM IR や LLVM BitCode と呼ばれる独自の中間言語を持ち、それを機械語に変換することができる。
30a433a94a9a first commit
mir3636
parents:
diff changeset
5 また、この言語で書かれたプログラムを実行するための仮想機械としても動作する。
30a433a94a9a first commit
mir3636
parents:
diff changeset
6
30a433a94a9a first commit
mir3636
parents:
diff changeset
7 clang は LLVM をバックエンドとして利用する C/C++/Ob jective-C のコンパイラである。
30a433a94a9a first commit
mir3636
parents:
diff changeset
8
4
mir3636
parents: 2
diff changeset
9 \section{clang の基本構造}
mir3636
parents: 2
diff changeset
10 \label{sec:clang}
mir3636
parents: 2
diff changeset
11 clang は library-based architecture というコンセプトの元に設計されており、字句解析を行う liblex、構文解析を行う libparse といったように処理機構ごとに複数のライブラリに分割されている。
mir3636
parents: 2
diff changeset
12 clang はこれらのライブラリを与えられた引数に応じて呼び出し、コンパイルを行う。
mir3636
parents: 2
diff changeset
13 さらに、必要な場合はリンカを呼び出してリンクを行い、ソースコードを実行可能な状態まで変換することも可能である。
mir3636
parents: 2
diff changeset
14
mir3636
parents: 2
diff changeset
15 ここで、そのライブラリの中でもコンパイルに関連するものについて説明する。
mir3636
parents: 2
diff changeset
16
mir3636
parents: 2
diff changeset
17 \begin{description}
mir3636
parents: 2
diff changeset
18 \item[libast]\mbox{}\\
6
mir3636
parents: 4
diff changeset
19 Abstract Syntax Tree (AST) や C の型等をクラスとして利用できるようにしたライブラリ。%、AST の説明は後述する。% AST は ``-Xclang -ast-dump'' オプションを付加することで表示できる.
4
mir3636
parents: 2
diff changeset
20 \item[liblex]\mbox{}\\
mir3636
parents: 2
diff changeset
21 字句解析ライブラリ、マクロの展開等の前処理系も担当する。
mir3636
parents: 2
diff changeset
22 \item[libparse]\mbox{}\\
mir3636
parents: 2
diff changeset
23 構文解析ライブラリ、解析結果を元に後述する libsema を使用して AST を生成する。
mir3636
parents: 2
diff changeset
24 \item[libsema]\mbox{}\\
mir3636
parents: 2
diff changeset
25 意味解析ライブラリ。parser (libparse) に AST を生成する機能を提供する。
mir3636
parents: 2
diff changeset
26 \item[libcodegen]\mbox{}\\
mir3636
parents: 2
diff changeset
27 コード生成ライブラリ。生成された AST を LLVM IR に変換する。
mir3636
parents: 2
diff changeset
28 \item[clang]\mbox{}\\
mir3636
parents: 2
diff changeset
29 ドライバ、各ライブラリを用いて求められた処理を行う。
mir3636
parents: 2
diff changeset
30 \end{description}
mir3636
parents: 2
diff changeset
31
6
mir3636
parents: 4
diff changeset
32 これを踏まえて clang が C のコードを LLVM IR に変換する処理について説明する。
mir3636
parents: 4
diff changeset
33 clang が C のコードを LLVM IR に変換する処理の過程を簡潔に図示したものである。
mir3636
parents: 4
diff changeset
34 以下の図 \ref{fig:clangProcess} は clang が C のコードを LLVM IR に変換する処理の過程を簡潔に図示したものである。
mir3636
parents: 4
diff changeset
35 clang は C のソースコードを受け取るとまずその解析を libparser による parser を用いて行い、libsema を用いて 解析結果から AST を構築する。
mir3636
parents: 4
diff changeset
36 そしてその AST を libcodegen を用いて LLVM IR に変換する。
mir3636
parents: 4
diff changeset
37
mir3636
parents: 4
diff changeset
38 %AST はソースコードの解析結果を保持したツリーである。
mir3636
parents: 4
diff changeset
39 %AST は “-Xclang -ast-dump” というオプションを付加することで表示することもできる。
mir3636
parents: 4
diff changeset
40
mir3636
parents: 4
diff changeset
41 \begin{figure}[htpb]
mir3636
parents: 4
diff changeset
42 \begin{center}
mir3636
parents: 4
diff changeset
43 \scalebox{0.35}{\includegraphics{fig/clangProcess.pdf}}
mir3636
parents: 4
diff changeset
44 \end{center}
mir3636
parents: 4
diff changeset
45 \caption{clang の 処理過程}
mir3636
parents: 4
diff changeset
46 \label{fig:clangProcess}
mir3636
parents: 4
diff changeset
47 \end{figure}
mir3636
parents: 4
diff changeset
48
0
30a433a94a9a first commit
mir3636
parents:
diff changeset
49 \section{LLVM の基本構造}
30a433a94a9a first commit
mir3636
parents:
diff changeset
50 LLVM は LLVM IR をターゲットのアセンブリ言語に直接的に変換を行うわけではない。
30a433a94a9a first commit
mir3636
parents:
diff changeset
51 LLVM では、最適化や中間表現の変換を何段階か行う。
30a433a94a9a first commit
mir3636
parents:
diff changeset
52 この変換を行う処理は全て pass が行う。
30a433a94a9a first commit
mir3636
parents:
diff changeset
53 多くの pass は最適化のために存在し、そのなかから任意のものを利用することができる。
30a433a94a9a first commit
mir3636
parents:
diff changeset
54 pass には以下のようなものがある。
30a433a94a9a first commit
mir3636
parents:
diff changeset
55
30a433a94a9a first commit
mir3636
parents:
diff changeset
56 \begin{description}
30a433a94a9a first commit
mir3636
parents:
diff changeset
57 \item[SelectionDAG Instruction Selection (SelectionDAGISel)]\mbox{}\\
30a433a94a9a first commit
mir3636
parents:
diff changeset
58 LLVM IR を SelectionDAG (DAG は Directed Acycric Graph の意) に変換し、最適化を行う。その後 Machine Code を生成する。
30a433a94a9a first commit
mir3636
parents:
diff changeset
59 \item[SSA-based Machine Code Optimizations]\mbox{}\\
30a433a94a9a first commit
mir3636
parents:
diff changeset
60 SSA-based Machine Code に対する最適化を行う。各最適化はそれぞれ独立した pass になっている。
30a433a94a9a first commit
mir3636
parents:
diff changeset
61 \item[Register Allocation]\mbox{}\\
2
mir3636
parents: 1
diff changeset
62 仮装レジスタから物理レジスタへの割り当てを行う。ここで PHI 命令が削除され、SSA-based でなくなる。
0
30a433a94a9a first commit
mir3636
parents:
diff changeset
63 \item[Prolog/Epilog Code Insertion]\mbox{}\\
30a433a94a9a first commit
mir3636
parents:
diff changeset
64 Prolog/Epilog Code の挿入を行う、どちらも関数呼び出しに関わるものであり、Prolog は関数を呼び出す際に呼び出す関数
30a433a94a9a first commit
mir3636
parents:
diff changeset
65 のためのスタックフレームを準備する処理、Epilog は呼び出し元の関数に戻る際に行う処理である。
30a433a94a9a first commit
mir3636
parents:
diff changeset
66 \item[Late Machine Code Optimizations]\mbox{}\\
30a433a94a9a first commit
mir3636
parents:
diff changeset
67 Machine Code に対してさらに最適化を行う。
30a433a94a9a first commit
mir3636
parents:
diff changeset
68 \item[Code Emission]\mbox{}\\
30a433a94a9a first commit
mir3636
parents:
diff changeset
69 Machine Code を MC Layer での表現に変換する。その後さらにターゲットのアセンブリ言語へ変換し、その出力を行う。
30a433a94a9a first commit
mir3636
parents:
diff changeset
70 \end{description}
30a433a94a9a first commit
mir3636
parents:
diff changeset
71
30a433a94a9a first commit
mir3636
parents:
diff changeset
72 これらの処理の流れを図示したものが以下の図\ref{fig:llvmProcess}である。
30a433a94a9a first commit
mir3636
parents:
diff changeset
73 前述した通りこれらの処理は全て pass によって行われる。
30a433a94a9a first commit
mir3636
parents:
diff changeset
74 pass にはいくつかの種類があり、関数単位で処理を行うもの、ファイル単位で処理を行うもの、ループ単位で処理を行うもの等がある。
30a433a94a9a first commit
mir3636
parents:
diff changeset
75
30a433a94a9a first commit
mir3636
parents:
diff changeset
76 \begin{figure}[htpb]
30a433a94a9a first commit
mir3636
parents:
diff changeset
77 \begin{center}
30a433a94a9a first commit
mir3636
parents:
diff changeset
78 \scalebox{0.35}{\includegraphics{fig/llvmProcess.pdf}}
30a433a94a9a first commit
mir3636
parents:
diff changeset
79 \end{center}
30a433a94a9a first commit
mir3636
parents:
diff changeset
80 \caption{LLVM の 処理過程}
30a433a94a9a first commit
mir3636
parents:
diff changeset
81 \label{fig:llvmProcess}
30a433a94a9a first commit
mir3636
parents:
diff changeset
82 \end{figure}
30a433a94a9a first commit
mir3636
parents:
diff changeset
83
30a433a94a9a first commit
mir3636
parents:
diff changeset
84 \section{LLVM/clang のデバッグ}
30a433a94a9a first commit
mir3636
parents:
diff changeset
85 LLVM/clang で CbC をコンパイルした際 Code Gear 内 の局所変数でポインタを参照すると tail call されないという不具合があることがわかった。
30a433a94a9a first commit
mir3636
parents:
diff changeset
86
30a433a94a9a first commit
mir3636
parents:
diff changeset
87 局所変数でポインタを参照していると clang は生成する LLVM IR にオブジェクトの寿命を示す lifetime.start と lifetime.end を書き出す。
30a433a94a9a first commit
mir3636
parents:
diff changeset
88
1
mir3636
parents: 0
diff changeset
89 ここでリスト\ref{ir_b}のようにオブジェクトの lifetime の終わりを示す lifetime.end が tail call の後に書き出されてしまうことにより、tail call の際に局所変数が解放されておらず lifetime が残っているので tail call が無視されてしまう。
0
30a433a94a9a first commit
mir3636
parents:
diff changeset
90
30a433a94a9a first commit
mir3636
parents:
diff changeset
91 しかし CbC では継続を行った後、継続前の Code Segment に戻ることはないので局所変数の解放は継続前に行っても良い。
30a433a94a9a first commit
mir3636
parents:
diff changeset
92 そこで lifetime.end を tail call の直前で生成を行うことで tail call を出すようにした。
30a433a94a9a first commit
mir3636
parents:
diff changeset
93
1
mir3636
parents: 0
diff changeset
94 修正後に生成された LLVM IR コード(リスト\ref{ir_a})では tail call の直前に生成された。
0
30a433a94a9a first commit
mir3636
parents:
diff changeset
95
1
mir3636
parents: 0
diff changeset
96 \begin{lstlisting}[frame=lrbt,label=ir_a,caption={\footnotesize LLVM IR コード 修正前}]
mir3636
parents: 0
diff changeset
97 if.then: ; preds = %entry
mir3636
parents: 0
diff changeset
98 %code_stack = getelementptr inbounds %struct.Context, %struct.Context* %context, i64 0, i32 8
mir3636
parents: 0
diff changeset
99 %4 = load %struct.stack*, %struct.stack** %code_stack, align 8, !tbaa !7
mir3636
parents: 0
diff changeset
100 %next = getelementptr inbounds %struct.Context, %struct.Context* %context, i64 0, i32 0
mir3636
parents: 0
diff changeset
101 %call1 = call i32 (%struct.stack*, i32*, ...) bitcast (i32 (...)* @stack_pop to i32 (%struct.stack*, i32*, ...)*)(%struct.stack* %4, i32* %next) #3
mir3636
parents: 0
diff changeset
102 %5 = load i32, i32* %next, align 8, !tbaa !11
mir3636
parents: 0
diff changeset
103 tail call fastcc void @meta(%struct.Context* nonnull %context, i32 %5) #3
mir3636
parents: 0
diff changeset
104 br label %cleanup
mir3636
parents: 0
diff changeset
105
mir3636
parents: 0
diff changeset
106 if.end: ; preds = %entry
mir3636
parents: 0
diff changeset
107 %6 = load %struct.stack*, %struct.stack** %node_stack, align 8, !tbaa !24
mir3636
parents: 0
diff changeset
108 %call4 = call i32 (%struct.stack*, %struct.Node**, ...) bitcast (i32 (...)* @stack_push to i32 (%struct.stack*, %struct.Node**, ...)*)(%struct.stack* %6, %struct.Node** nonnull %parent) #3
mir3636
parents: 0
diff changeset
109 tail call fastcc void @meta(%struct.Context* nonnull %context, i32 18) #3
mir3636
parents: 0
diff changeset
110 br label %cleanup
mir3636
parents: 0
diff changeset
111
mir3636
parents: 0
diff changeset
112 cleanup: ; preds = %if.end, %if.then
mir3636
parents: 0
diff changeset
113 call void @llvm.lifetime.end(i64 8, i8* %0) #3
mir3636
parents: 0
diff changeset
114 ret void
mir3636
parents: 0
diff changeset
115 \end{lstlisting}
mir3636
parents: 0
diff changeset
116
mir3636
parents: 0
diff changeset
117 \begin{lstlisting}[frame=lrbt,label=ir_b,caption={\footnotesize LLVM IR コード 修正後}]
mir3636
parents: 0
diff changeset
118 if.then: ; preds = %entry
mir3636
parents: 0
diff changeset
119 %code_stack = getelementptr inbounds %struct.Context, %struct.Context* %context, i64 0, i32 8
mir3636
parents: 0
diff changeset
120 %4 = load %struct.stack*, %struct.stack** %code_stack, align 8, !tbaa !7
mir3636
parents: 0
diff changeset
121 %next = getelementptr inbounds %struct.Context, %struct.Context* %context, i64 0, i32 0
mir3636
parents: 0
diff changeset
122 %call1 = call i32 (%struct.stack*, i32*, ...) bitcast (i32 (...)* @stack_pop to i32 (%struct.stack*, i32*, ...)*) (%struct.stack* %4, i32* %next) #3
mir3636
parents: 0
diff changeset
123 %5 = load i32, i32* %next, align 8, !tbaa !11
mir3636
parents: 0
diff changeset
124 call void @llvm.lifetime.end(i64 8, i8* %0) #3
mir3636
parents: 0
diff changeset
125 tail call fastcc void @meta(%struct.Context* nonnull %context, i32 %5) #3
mir3636
parents: 0
diff changeset
126 br label %cleanup
mir3636
parents: 0
diff changeset
127
mir3636
parents: 0
diff changeset
128 if.end: ; preds = %entry
mir3636
parents: 0
diff changeset
129 %6 = load %struct.stack*, %struct.stack** %node_stack, align 8, !tbaa !24
mir3636
parents: 0
diff changeset
130 %call4 = call i32 (%struct.stack*, %struct.Node**, ...) bitcast (i32 (...)* @stack_push to i32 (%struct.stack*, % struct.Node**, ...)*)(%struct.stack* %6, %struct.Node** nonnull %parent) #3
mir3636
parents: 0
diff changeset
131 call void @llvm.lifetime.end(i64 8, i8* %0) #3
mir3636
parents: 0
diff changeset
132 tail call fastcc void @meta(%struct.Context* nonnull %context, i32 18) #3
mir3636
parents: 0
diff changeset
133 br label %cleanup
mir3636
parents: 0
diff changeset
134
mir3636
parents: 0
diff changeset
135 cleanup: ; preds = %if.end, %if.then
mir3636
parents: 0
diff changeset
136 ret void
mir3636
parents: 0
diff changeset
137 \end{lstlisting}
mir3636
parents: 0
diff changeset
138
mir3636
parents: 0
diff changeset
139