comparison paper.tex @ 2:7cc0be313596

fix
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 01 Mar 2016 17:16:15 +0900
parents 1c933f3a5cb7
children d9b703be7359
comparison
equal deleted inserted replaced
1:1c933f3a5cb7 2:7cc0be313596
89 % 89 %
90 % For peerreview papers, this IEEEtran command inserts a page break and 90 % For peerreview papers, this IEEEtran command inserts a page break and
91 % creates the second title. It will be ignored for other modes. 91 % creates the second title. It will be ignored for other modes.
92 \IEEEpeerreviewmaketitle 92 \IEEEpeerreviewmaketitle
93 93
94 本章では LLVM と Clang を利用した新しいプログラミング言語のコンパイラの実装を行う方法を Continuaton based C という言語の実装例とともに説明する. 94
95 また, この実装では LLVM IR に変更を加えることはしない. LLVM IR に変更を加える事は可能であるが, そうした場合最適化を含む LLVM の全てのパスがその変更の影響を受け, 対応させなければならくなる. これは大変難しく現実的でない. 95
96 本章では LLVM と Clang を利用した新しいプログラミング言語のコンパイラの実装を行う方法を Continuaton based C(CbC)\ref{cbc}
97 という言語の実装例とともに説明する.
98 LLVMとClangは、C++ で記述されており、GCCよりも見通し良く書かれている。
99 LLVMは汎用のコンパイラフレームワークであり、プログラミング言語の構文解析、中間コード生成、機械語生成の各段階で様々なサポートがある。
100 LLVMで新しい言語を作る方法には様々な方法がある。一つは自作の構文解析器からLLVMの抽象構文木生成のAPI呼び出す方法である。
101 また、LLVM IRという中間コードを直接生成しても良い。
102 DSL(ドメイン特化言語)のような場合は、それですむことが多い。
103 しかし、LLVMの機能を越えたプログラミング言語を作成したい場合は、LLVMの内部に立ち入る必要がある。
104
105 CbCは組み込みシステムやOSなどのメタ計算、あるいは言語処理系そのものの実装に的にするように設計された言語である。
106 コードセグメントという単位と、それを接続する軽量継続(引数付き大域goto文)を持つ。このように関数呼び出しそのものを
107 独自に持つような言語を実装するにはLLVM自体をLLVMの大域的局所的な最適化に干渉しないように修正する必要がある。
108
109 ここではLLVMの内部構造について詳細に説明し、CbCでの修正方法について説明していく。
110
111 % また, この実装では LLVM IR に変更を加えることはしない. LLVM IR に変更を加える事は可能であるが, そうした場合最適化を含む LLVM の全てのパスがその変更の影響を受け, 対応させなければならくなる. これは大変難しく現実的でない.
96 112
97 % \section{Continuation based C} 113 % \section{Continuation based C}
98 % 今回例として用いる Continuation based C \cite{CbC2011}(以下 CbC) は code segment という処理単位を持つ. 114 % 今回例として用いる Continuation based C \cite{CbC2011}(以下 CbC) は code segment という処理単位を持つ.
99 % code segment の宣言は \_\_code という型を用いて行うとする. リスト \ref{code_simple} は最も基本的な CbC のコードの一例で, 図 \ref {fig:code_simple}はそれを図示したものである. 115 % code segment の宣言は \_\_code という型を用いて行うとする. リスト \ref{code_simple} は最も基本的な CbC のコードの一例で, 図 \ref {fig:code_simple}はそれを図示したものである.
100 % 116 %
119 % \label{fig:code_simple} 135 % \label{fig:code_simple}
120 % \end{figure} 136 % \end{figure}
121 % 137 %
122 138
123 \section{LLVM clang} 139 \section{LLVM clang}
124 LLVM とはコンパイラ, ツールチェーン技術等を開発するプロジェクトの名称である. 単に LLVM といった場合は LLVM Core を指し, これはコンパイラの基板となるライブラリの集合である. 以降は本論文でも, 単に LLVM といった場合は LLVM Core を指す. LLVM IR や LLVM BitCode と呼ばれる独自の言語を持ち, この言語で書かれたプログラムを実行することのできる仮想機械も持つ. また, LLVM IR を特定のターゲットの機械語に変換することが可能であり, その際に LLVM の持つ最適化機構を利用することができる. LLVM を利用する各コンパイラフロントエンドはターゲットとなるプログラミング言語を LLVM IR に変換することで LLVM の持つ最適化機構を利用する. 140 LLVM とはコンパイラ, ツールチェーン技術等を開発するプロジェクトの名称である. 単に LLVM といった場合は LLVM Core を指し, これはコンパイラの基板となるライブラリの集合である. 以降は本稿でも, 単に LLVM といった場合は LLVM Core を指す.
125 141
126 clang は バックエンドに LLVM を利用する C/C++/Objective-C コンパイラである. 具体的には与えられたコードを解析し, LLVM IR に変換する部分までを自身で行い, それをターゲットマシンの機械語に変換する処理と最適化に LLVM を用いる. 142 LLVMは、 LLVM IR という独自の中間言語を持つ。これはアーキテクチャ依存でない型付きのアセンブラとなっている。人が読める形式のものと
143 LLVM BitCode というビットストリームにエンコードされたものがある。
144 LLVMはLLVM IRを実行することのできる仮想機械も持ち、もちろん、.
145 LLVM IR を最適化しながら特定のターゲットの機械語に変換することもできる.
146
147 clang は バックエンドに LLVM を利用する C/C++/Objective-C コンパイラである. 具体的には与えられたソースコードを解析し,
148 抽象構文木(AST)を生成する。そして、そのASTを LLVM IR に変換し、LLVM Coreにより ターゲットマシンの機械語に変換する.
127 GCC と比較すると丁寧でわかりやすいエラーメッセージを出力する, コンパイル時間が短いといった特徴を持つ. 149 GCC と比較すると丁寧でわかりやすいエラーメッセージを出力する, コンパイル時間が短いといった特徴を持つ.
128 150
129 clang は library-based architecture というコンセプトの元に設計されており, 字句解析を行う liblex, 構文解析を行う libparse といったように処理機構ごとに複数のライブラリに分割されている. clang はこれらのライブラリを与えられた引数に応じて呼び出し, コンパイルを行う. さらに, 必要な場合はリンカを呼び出してリンクを行い, ソースコードを実行可能な状態まで変換することも可能である. 151 clang は library-based architecture というコンセプトの元に設計されており, 字句解析を行う liblex, 構文解析を行う libparse といったように処理機構ごとに複数のライブラリに分割されている.
130 152 clang はこれらのライブラリを与えられた引数に応じて呼び出し, コンパイルを行う.
131 ここで, そのライブラリの中でもコンパイルに関連するものについて説明する. 153 さらに, 必要な場合は外部のリンカを呼び出してリンクを行い, ソースコードを実行可能な状態まで変換することも可能である.
154
155 ここで, そのライブラリの中でもclangが使用するコンパイルに関連するものについて説明する.
132 156
133 \begin{description} 157 \begin{description}
134 \item[libast]\mbox{}\\ 158 \item[libast]\mbox{}\\
135 Abstract Syntax Tree (AST) や C の型等をクラスとして利用できるようにしたライブラリ. AST の説明は後述する. % AST は ``-Xclang -ast-dump'' オプションを付加することで表示できる. 159 Abstract Syntax Tree (AST) や C の型等をクラスとして利用できるようにしたライブラリ. AST の説明は後述する. % AST は ``-Xclang -ast-dump'' オプションを付加することで表示できる.
136 \item[liblex]\mbox{}\\ 160 \item[liblex]\mbox{}\\
155 \end{center} 179 \end{center}
156 \caption{clang の 処理過程} 180 \caption{clang の 処理過程}
157 \label{fig:clangProcess} 181 \label{fig:clangProcess}
158 \end{figure} 182 \end{figure}
159 183
160 184 \begin{lstlisting}[float=*,basicstyle=\tiny,frame=tb, label=AST, caption={sample.c の AST}]
161 \section{clangAST について}
162 LLVM と clang を用いたコンパイラの実装では基本的に clang の中間表現である clangAST を組み立てていくことになる. clangAST はソースコードの解析結果を保持したツリーである. AST は ``-Xclang -ast-dump'' というオプションを付加することで表示することもできる. 例えばリスト\ref{ASTSampleCode}コンパイル時にオプション ``-Xclang -ast-dump'' を付与した場合は出力結果としてリスト\ref{AST}が得られる. 出力された AST の各行が AST のノード なっており, 各ノードは Decl, Stmt, Expr といったクラスを継承したものになっている. それぞれの簡単な説明を以下に記す (各クラスの詳細な実装は clang documentation\cite{clang} を参考に).
163
164 \begin{description}
165 \item[Decl]\mbox{}\\
166 宣言や定義を表すクラスであり, 関数の宣言を表す FunctionDecl, 変数の宣言を表す VarDecl 等のサブクラスが存在する.
167 \item[Stmt]\mbox{}\\
168 一つの文に対応するクラスであり, if 文と対応する IfStmt, 宣言文と対応する DeclStmt, return 文と対応する ReturnStmt 等のサブクラスが存在する.
169 \item[Expr]\mbox{}\\
170 一つの式に対応するクラスであり, 関数呼び出しと対応する CallExpr, キャストと対応する CastExpr 等のサブクラスが存在する.
171 \end{description}
172
173 これらを踏まえて, ソースコード\ref{ASTSampleCode}と出力された AST( リスト\ref{AST} ) に注目する.
174
175 1行目の TranslationUnitDecl が根ノードに当たる. TranslationUnitDecl は翻訳単位を表すクラスであり, この AST が一つのファイルと対応していることがわかる. 実際にソースコードの内容が反映されているのは5行目以降のノードで, 5行目の FunctionDecl がソースコード\ref{ASTSampleCode}の1行目, add 関数の定義部分に当たる. ソースコード\ref{ASTSampleCode}の7行目の add 関数の呼び出しは, AST ではリスト\ref{AST}の21行目, CallExpr で表されている. この CallExpr の下のノードを見ていくと23行目の DeclRefExpr が関数のアドレスを持っており, これが add 関数のアドレスと一致することから, CallExpr は呼び出す関数への参照を持っていることがわかる. これらのノード以外についても return 文は ReturnStmt, 変数宣言は VarDecl というように, 各ノードがソースコードのいずれかの部分に対応していることが読み取れる.
176
177 \begin{lstlisting}[frame=lrbt, label=ASTSampleCode, caption={sample.c}]
178 int add(int a, int b){
179 return a + b;
180 }
181
182 int main(){
183 int res;
184 res = add(1,1);
185 return res;
186 }
187 \end{lstlisting}
188 \begin{lstlisting}[float=*,frame=lrbt, label=AST, caption={sample.c の AST}]
189 TranslationUnitDecl 0x102020cd0 <<invalid sloc>> 185 TranslationUnitDecl 0x102020cd0 <<invalid sloc>>
190 |-TypedefDecl 0x1020211b0 <<invalid sloc>> __int128_t '__int128' 186 |-TypedefDecl 0x1020211b0 <<invalid sloc>> __int128_t '__int128'
191 |-TypedefDecl 0x102021210 <<invalid sloc>> __uint128_t 'unsigned __int128' 187 |-TypedefDecl 0x102021210 <<invalid sloc>> __uint128_t 'unsigned __int128'
192 |-TypedefDecl 0x102021560 <<invalid sloc>> __builtin_va_list '__va_list_tag [1]' 188 |-TypedefDecl 0x102021560 <<invalid sloc>> __builtin_va_list '__va_list_tag [1]'
193 |-FunctionDecl 0x102021700 <sample.c:1:1, line:3:1> add 'int (int, int)' 189 |-FunctionDecl 0x102021700 <sample.c:1:1, line:3:1> add 'int (int, int)'
214 `-ReturnStmt 0x1020523a0 <line:8:3, col:10> 210 `-ReturnStmt 0x1020523a0 <line:8:3, col:10>
215 `-ImplicitCastExpr 0x102052388 <col:10> 'int' <LValueToRValue> 211 `-ImplicitCastExpr 0x102052388 <col:10> 'int' <LValueToRValue>
216 `-DeclRefExpr 0x102052360 <col:10> 'int' lvalue Var 0x1020219a0 'res' 'int' 212 `-DeclRefExpr 0x102052360 <col:10> 'int' lvalue Var 0x1020219a0 'res' 'int'
217 \end{lstlisting} 213 \end{lstlisting}
218 214
215
216 \section{clangAST について}
217 LLVM と clang を用いたコンパイラの実装では基本的に clang の中間表現である clangAST を組み立てていくことになる. clangAST はソースコードの解析結果を保持したツリーである.
218 AST は \\
219 \begin{lstlisting}[basicstyle=\tiny,frame=lrbt, caption={ASTを表示するオプション}]
220 -Xclang -ast-dump
221 \end{lstlisting}
222 というオプションを付加することで表示することもできる.
223 例えば、簡単なCのソースコード(\ref{ASTSampleCode})は、
224 リスト\ref{AST}のようになる。
225
226 \begin{lstlisting}[basicstyle=\tiny,frame=lrbt, label=ASTSampleCode, caption={sample.c}]
227 int add(int a, int b){
228 return a + b;
229 }
230
231 int main(){
232 int res;
233 res = add(1,1);
234 return res;
235 }
236 \end{lstlisting}
237
238 出力された AST の各行が AST のノード なっており, 各ノードは Decl, Stmt, Expr といったC++のクラスを継承したものになっている.
239 それぞれの簡単な説明を以下に記す (各クラスの詳細な実装は clang documentation\cite{clang} を参考に).
240
241 \begin{description}
242 \item[Decl]\mbox{}\\
243 宣言や定義を表すクラスであり, 関数の宣言を表す FunctionDecl, 変数の宣言を表す VarDecl 等のサブクラスが存在する.
244 \item[Stmt]\mbox{}\\
245 一つの文に対応するクラスであり, if 文と対応する IfStmt, 宣言文と対応する DeclStmt, return 文と対応する ReturnStmt 等のサブクラスが存在する.
246 \item[Expr]\mbox{}\\
247 一つの式に対応するクラスであり, 関数呼び出しと対応する CallExpr, キャストと対応する CastExpr 等のサブクラスが存在する.
248 \end{description}
249
250
251
252 1行目の TranslationUnitDecl が根ノードに当たる. TranslationUnitDecl は翻訳単位を表すクラスであり, この AST が一つのファイルと対応していることがわかる. 実際にソースコードの内容が反映されているのは5行目以降のノードで, 5行目の FunctionDecl がソースコード\ref{ASTSampleCode}の1行目, add 関数の定義部分に当たる.
253 対応するソースコードの位置が明らかな場合は\verb+sample.c1:1+などと指定されており、そうでない場合は\verb+<<invalid sloc>>+となっている。
254 型名や変数名などがASTに格納されていることもわかる。
255 ソースコード\ref{ASTSampleCode}の7行目の add 関数の呼び出しは, AST ではリスト\ref{AST}の21行目, CallExpr で表されている.
256 この CallExpr の下のノードを見ていくと23行目の DeclRefExpr が関数のアドレス0x102021700を持っており,
257 これが add 関数のアドレスと一致することから, CallExpr は呼び出す関数への参照を持っていることがわかる.
258 これらのノード以外についても return 文は ReturnStmt, 変数宣言は VarDecl というように,
259 各ノードがソースコードのいずれかの部分に対応していることが読み取れる.
260
261
219 \section{LLVMでの型の扱い} 262 \section{LLVMでの型の扱い}
220 clang で新しい型を扱えるようにするためには, キーワードを登録する, 識別子を登録する, QualType の扱う Type の登録をするといった作業が必要である. これらを順に説明する. 263
221 264 clangに新しい機能を付け加えるには新しい型が必要となることがある。
222 clang では, 予約語は全て \$(CLANG)\footnote{clang のソースコードを展開したディレクトリのパス}/include/ clang/Basic/TokenKinds.def に定義されており, ここで定義した予約語の頭に kw\_ を付けたものがその予約語の ID となる. ここに, 次のように変更を加えて \_\_code を追加した. これで \_\_code に対応する token の id が kw\_\_\_code になる. ここで使われている KEYWORD マクロは予約語の定義に用いられるもので, 第一引数が登録したい予約語, 第二引数がその予約語が利用される範囲を表す. KEYALL は全ての C, C++ でサポートされることを示し, この他には C++ の予約語であることを示す KEYCXX や C++11 以降で利用されることを示す KEYCXX11 等がある. code segment は C のバージョンに関わらずサポートされるべきであるので KEYALL を選択した. 265 clang で新しい型を扱えるようにするためには, まず型の表す予約後(KEYWORD)を登録する,
223 266 そして、それに対応する識別子を登録する,
224 \begin{lstlisting}[float=*,frame=lrbt,label=token,caption={キーワードの登録}] 267 それを QualType (Qaulified type)というC++のオブジェクトの扱う Type として登録をするという手順になる。
268 ここで新しく作られた型はIRレベルでは基本的な型に展開されてしまうので、LLVMの最適化と衝突することはない。
269
270 clang では, 予約語は全て \$(CLANG)\footnote{clang のソースコードを展開したディレクトリのパス}/include/ clang/Basic/TokenKinds.def に定義されている.
271 ここで定義した予約語の頭に kw\_ を付けたものがその予約語の ID となる.
272
273 ここでは CbC のコードセグメントを表す型である\_\_code を追加してみよう。
274 \_\_code という型は実際には\verb+void *+だが、これを関数の戻り値の型と指定することにより、その関数がコードセグメントであることを表す.
275
276 まず、TokenKinds.def のKEYWORDにに\_\_code を追加する.
277 これで \_\_code に対応する token の id が kw\_\_\_code になる.
278 ここで使われている KEYWORD はCのマクロであり、予約語の定義に用いられる.
279 KEYWORDの第一引数が登録したい予約語, 第二引数のKEYALLはその予約語が利用される範囲を表す.
280 KEYALL は全ての C, C++ でサポートされることを示し, この他には C++ の予約語であることを示す KEYCXX や C++11 以降で利用されることを示す KEYCXX11 等がある.
281 \verb+noCbC+はCbCでの変更部分を示す条件マクロになっている.
282
283 \begin{lstlisting}[frame=lrbt,basicstyle=\tiny,label=token,caption={キーワードの登録}]
225 : 284 :
226 KEYWORD(__func__ , KEYALL) 285 KEYWORD(__func__ , KEYALL)
227 KEYWORD(__objc_yes , KEYALL) 286 KEYWORD(__objc_yes , KEYALL)
228 KEYWORD(__objc_no , KEYALL) 287 KEYWORD(__objc_no , KEYALL)
229 288
232 : 291 :
233 #endif 292 #endif
234 : 293 :
235 \end{lstlisting} 294 \end{lstlisting}
236 295
237 予約語を定義したことで, clang の字句解析器が各予約語を認識できるようになった. しかし, まだ予約語を認識できるようになっただけで \_\_code という型自体は用意されていない. 296 予約語を定義したことで, clang の字句解析器が各予約語を認識できるようになった. 次は clang 内部で使用する識別子を作る.
238 297
239 clang では型の識別子の管理に TypeSpecType という enum を用いる. この enum の定義は \$(CLANG)/include/clang/Basic/Specifiers.h で行われており, これを以下のように編集した. 298 clang では型の識別子の管理に TypeSpecType という enum を用いる. この enum の定義は \$(CLANG)/include /clang/Basic/Specifiers.h で行われており, これを以下のように編集した.
240 299
241 \begin{lstlisting}[float=*,frame=lrbt,label=TST,caption={TypeSpecTypeの登録}] 300 \begin{lstlisting}[frame=lrbt,,basicstyle=\tiny,label=TST,caption={TypeSpecTypeの登録}]
242 enum TypeSpecifierType { 301 enum TypeSpecifierType {
243 TST_unspecified, 302 TST_unspecified,
244 TST_void, 303 TST_void,
245 : 304 :
246 #ifndef noCbC 305 #ifndef noCbC
248 #endif 307 #endif
249 : 308 :
250 \end{lstlisting} 309 \end{lstlisting}
251 これに加えてさらに QualType が用いる Type を作らなければならない. 310 これに加えてさらに QualType が用いる Type を作らなければならない.
252 311
253 QualType は変数や関数等の型情報を持つクラスで, const, volatile 等の修飾子の有無を示すフラグと, int, char, * (ポインタ) 等の型情報を持つ Type オブジェクトへのポインタを持つ. QualType の持つ Type オブジェクトは getTypePtr 関数を呼び出すことで取得でき, Type クラスは isIntegerType, isVoidType, isPointerType と言った関数を持つので, これを利用して型を調べることができる. また, ポインタ型である場合には getPointeeType という関数を呼び出すことでそのポインタが指す型の Type を持つ QualType を得ることができ, それを通してポインタの指す型を知ることが可能である. 配列や参照等に対しても同様に, それぞれ要素, 参照元の Type へのポインタを持つ QualType を得る関数が存在する. 修飾子の有無は const なら isConstQualified, volatile なら isVolatileQualified といった関数を用いて確認できる. 312 QualType は変数や関数等の型情報を持つクラスで, const, volatile 等の修飾子の有無を示すフラグと, int, char, * (ポインタ) 等の型情報を持つ Type オブジェクトへのポインタを持つ.
313 QualType の持つ Type オブジェクトは getTypePtr 関数を呼び出すことで取得でき, Type クラスは isIntegerType, isVoidType, isPointerType と言った関数を持つので, これを利用して型を調べることができる.
314 また, ポインタ型である場合には getPointeeType という関数を呼び出すことでそのポインタが指す型の Type を持つ QualType を得ることができ,
315 それを通してポインタの指す型を知ることが可能である.
316 配列や参照等に対しても同様に, それぞれ要素, 参照元の Type へのポインタを持つ QualType を得る関数が存在する.
317 修飾子の有無は const なら isConstQualified, volatile なら isVolatileQualified といった関数を用いて確認できる.
254 318
255 ここで, 以下に一つの例として ``const int *'' 型に対応する QualType を表した図を示す. 319 ここで, 以下に一つの例として ``const int *'' 型に対応する QualType を表した図を示す.
256 320
257 \begin{figure}[htpb] 321 \begin{figure}[htpb]
258 \begin{center} 322 \begin{center}
265 図\ref{fig:qual}の QualType A が const int * 型の変数, もしくは関数の持つ QualType である. これの持つ getTypePtr 関数を呼び出すことで, PointerType を得ることができる. この PointerType がどの型に対するポインタかを知るには前述したとおり getPointeeType を呼び出せば良い. そうして呼び出されたのが QualType B である. この例の QualType は const int * 型に対応するものであるので, ここで取得できた QualType B のgetTypePtr 関数を呼び出すと, 当然 IntegerType が得られる. また, この時 int には const がかかっているので, QualType B の isConstQualified 関数を呼ぶと true が返る. 329 図\ref{fig:qual}の QualType A が const int * 型の変数, もしくは関数の持つ QualType である. これの持つ getTypePtr 関数を呼び出すことで, PointerType を得ることができる. この PointerType がどの型に対するポインタかを知るには前述したとおり getPointeeType を呼び出せば良い. そうして呼び出されたのが QualType B である. この例の QualType は const int * 型に対応するものであるので, ここで取得できた QualType B のgetTypePtr 関数を呼び出すと, 当然 IntegerType が得られる. また, この時 int には const がかかっているので, QualType B の isConstQualified 関数を呼ぶと true が返る.
266 330
267 331
268 このように, clang では複雑な型を持つ関数, 変数でもその型を表すために持つ QualType は一つであり, それが指す Type を辿ることで完全な型を知ることができる. 332 このように, clang では複雑な型を持つ関数, 変数でもその型を表すために持つ QualType は一つであり, それが指す Type を辿ることで完全な型を知ることができる.
269 333
270 この Type の定義は \$(CLANG)/include/clang/AST/BuiltinTypes.def で行われているので, これを編集する(リスト\ref{clangType}). ここで使用されているマクロには符号付き整数であることを示す SIGNED\_TYPE や符号無し整数であることを示す UNSIGNED\_TYPE 等があり, それらは BUILTIN\_TYPE マクロを拡張するものである. \_\_code 型は符号無し,有りといった性質を保つ必要はないため, 今回は BUILTIN\_TYPE を使うべきである. 334 この Type の定義は \$(CLANG)/include/ clang/AST/BuiltinTypes.def で行われているので, これを編集する(リスト\ref{clangType}).
271 335 ここで使用されているマクロには符号付き整数であることを示す SIGNED\_TYPE や符号無し整数であることを示す UNSIGNED\_TYPE 等があり, それらは BUILTIN\_TYPE マクロを拡張するものである.
272 \begin{lstlisting}[float=*,frame=lrbt,label=clangType,caption={Typeの登録}] 336 \_\_code 型は符号無し,有りといった性質を保つ必要はないため, 今回は BUILTIN\_TYPE を使うべきである.
337
338 \begin{lstlisting}[frame=lrbt,basicstyle=\tiny,label=clangType,caption={Typeの登録}]
273 : 339 :
274 // 'bool' in C++, '_Bool' in C99 340 // 'bool' in C++, '_Bool' in C99
275 UNSIGNED_TYPE(Bool, BoolTy) 341 UNSIGNED_TYPE(Bool, BoolTy)
276 342
277 // 'char' for targets where it's unsigned 343 // 'char' for targets where it's unsigned
284 BUILTIN_TYPE(__Code, __CodeTy) 350 BUILTIN_TYPE(__Code, __CodeTy)
285 #endif 351 #endif
286 : 352 :
287 \end{lstlisting} 353 \end{lstlisting}
288 354
289 ここまでの変更で clang が \_\_code 型を扱えるようになり, \_\_code 型の関数, 即ち code segment を解析する準備が整った. 355 ここまでの変更で clang が \_\_code 型を扱えるようになった.
290 次は \_\_code 型を解析し clangAST に変換できるようにしなければならない. clang では型の構文解析は Parser クラスの ParseDeclarationSpecifiers 関数で行われる. この関数のもつ巨大な switch 文に kw\_\_\_code が来た時の処理を加えてやれば良い. 具体的には switch 文内に以下のように記述を加えた. また, この関数の定義は \$(CLANG)/lib/Parse/ParseDecl.cpp で行われている. 356 % り, \_\_code 型の関数, 即ち code segment を解析する準備が整った.
357
358
359 次は clang が \_\_code 型を解析し clangAST に変換できるようにしなければならない.
360 clang では型の構文解析は Parser クラスの ParseDeclarationSpecifiers 関数で行われる.
361 この関数のもつ巨大な switch 文に kw\_\_\_code が来た時の処理を加えてやれば良い.
362 具体的には switch 文内に以下のように記述を加えた. また, この関数の定義は \$(CLANG)/lib/Parse/ParseDecl.cpp で行われている.
291 363
292 \begin{lstlisting}[float=*,frame=lrbt,label=parse__Code,caption={\_\_code の parse}] 364 \begin{lstlisting}[float=*,frame=lrbt,label=parse__Code,caption={\_\_code の parse}]
293 case tok::kw___code: { 365 case tok::kw___code: {
294 LangOptions* LOP; 366 LangOptions* LOP;
295 LOP = const_cast<LangOptions*>(&getLangOpts()); 367 LOP = const_cast<LangOptions*>(&getLangOpts());
491 563
492 MCOperand はオペランドに対応し, MCInst はこのクラスを用いる. 564 MCOperand はオペランドに対応し, MCInst はこのクラスを用いる.
493 565
494 MC Layer で用いられる各クラスも ``-mllvm -asm-show-inst'' オプションを用いることで他の中間表現のように確認することが出来る. MCInst はアセンブリの各命令に対応しているので, アセンブリファイルにコメントとして出力される. リスト \ref{MCInst} は\ref{IRtestC} をコンパイルして得られるアセンブリコードの一部である. 各命令の隣にコメントで記されているのが MCInst, 下に記されているのが MCOperand である. 566 MC Layer で用いられる各クラスも ``-mllvm -asm-show-inst'' オプションを用いることで他の中間表現のように確認することが出来る. MCInst はアセンブリの各命令に対応しているので, アセンブリファイルにコメントとして出力される. リスト \ref{MCInst} は\ref{IRtestC} をコンパイルして得られるアセンブリコードの一部である. 各命令の隣にコメントで記されているのが MCInst, 下に記されているのが MCOperand である.
495 567
496 \begin{lstlisting}[frame=lrbt, label=MCInst, caption={アセンブリコードと MCInst}] 568 % \begin{lstlisting}[frame=lrbt, label=MCInst, caption={アセンブリコードと MCInst}]
497 _add: ## @add 569 % _add: ## @add
498 .cfi_startproc 570 % .cfi_startproc
499 ## BB#0: ## %entry 571 % ## BB#0: ## %entry
500 pushq %rbp ## <MCInst #2300 PUSH64r 572 % pushq %rbp ## <MCInst #2300 PUSH64r
501 ## <MCOperand Reg:36>> 573 % ## <MCOperand Reg:36>>
502 Ltmp0: 574 % Ltmp0:
503 .cfi_def_cfa_offset 16 575 % .cfi_def_cfa_offset 16
504 Ltmp1: 576 % Ltmp1:
505 .cfi_offset %rbp, -16 577 % .cfi_offset %rbp, -16
506 movq %rsp, %rbp ## <MCInst #1684 MOV64rr 578 % movq %rsp, %rbp ## <MCInst #1684 MOV64rr
507 ## <MCOperand Reg:36> 579 % ## <MCOperand Reg:36>
508 ## <MCOperand Reg:44>> 580 % ## <MCOperand Reg:44>>
509 Ltmp2: 581 % Ltmp2:
510 .cfi_def_cfa_register %rbp 582 % .cfi_def_cfa_register %rbp
511 addl %esi, %edi ## <MCInst #97 ADD32rr 583 % addl %esi, %edi ## <MCInst #97 ADD32rr
512 ## <MCOperand Reg:23> 584 % ## <MCOperand Reg:23>
513 ## <MCOperand Reg:23> 585 % ## <MCOperand Reg:23>
514 ## <MCOperand Reg:29>> 586 % ## <MCOperand Reg:29>>
515 movl %edi, %eax ## <MCInst #1665 MOV32rr 587 % movl %edi, %eax ## <MCInst #1665 MOV32rr
516 ## <MCOperand Reg:19> 588 % ## <MCOperand Reg:19>
517 ## <MCOperand Reg:23>> 589 % ## <MCOperand Reg:23>>
518 popq %rbp ## <MCInst #2178 POP64r 590 % popq %rbp ## <MCInst #2178 POP64r
519 ## <MCOperand Reg:36>> 591 % ## <MCOperand Reg:36>>
520 retq ## <MCInst #2460 RETQ> 592 % retq ## <MCInst #2460 RETQ>
521 \end{lstlisting} 593 % \end{lstlisting}
522
523 594
524 \section{オプションの追加} 595 \section{オプションの追加}
525 リスト\ref{parse__Code} では新たに作成した HasCodeSegment というオプションを変更する処理を行っている(4行目). このオプションの値を変更しているのはコード内に code segment が存在することを LLVM に伝え, 最適化を利用するためである. このオプションは LangOptions というクラスによって管理されている. LangOptions はコンパイル時のオプションのうち, プログラミング言語に関わるオプションを管理するクラスであり, それらは \$(CLANG)/include/clang/Basic/ LangOptions.def で定義される. これを以下のリスト \ref{langOpt} のように変更して HasCodeSegment というオプションを追加した. LANGOPT マクロの引数は第一引数から順にオプション名, 必要ビット数, デフォルトの値, オプションの説明 となっている. 596 リスト\ref{parse__Code} では新たに作成した HasCodeSegment というオプションを変更する処理を行っている(4行目). このオプションの値を変更しているのはコード内に code segment が存在することを LLVM に伝え, 最適化を利用するためである. このオプションは LangOptions というクラスによって管理されている. LangOptions はコンパイル時のオプションのうち, プログラミング言語に関わるオプションを管理するクラスであり, それらは \$(CLANG)/include/clang/Basic/ LangOptions.def で定義される. これを以下のリスト \ref{langOpt} のように変更して HasCodeSegment というオプションを追加した. LANGOPT マクロの引数は第一引数から順にオプション名, 必要ビット数, デフォルトの値, オプションの説明 となっている.
526 597
527 \begin{lstlisting}[float=*,frame=lrbt,label=langOpt,caption={LangOptions の追加}] 598 \begin{lstlisting}[float=*,frame=lrbt,label=langOpt,caption={LangOptions の追加}]