comparison Paper/nobu-prosym.tex @ 20:9e904a731cf4

modify
author Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp>
date Sun, 20 Nov 2011 17:55:14 +0900
parents e89540b527cf
children f6a58652d10c
comparison
equal deleted inserted replaced
19:e89540b527cf 20:9e904a731cf4
173 %コードセグメントは関数よりも小さな単位で記述される為,最適化がされやすくなる. 173 %コードセグメントは関数よりも小さな単位で記述される為,最適化がされやすくなる.
174 %コードセグメントの記述の仕方は C の関数と同じで,引数を持たせて継続を行うことができる. 174 %コードセグメントの記述の仕方は C の関数と同じで,引数を持たせて継続を行うことができる.
175 \section{GCCの3つの内部表現} 175 \section{GCCの3つの内部表現}
176 GCC-4.6 への実装の前に,GCC で扱われる3つの内部表現について触れておく. 176 GCC-4.6 への実装の前に,GCC で扱われる3つの内部表現について触れておく.
177 177
178 \subsection{3つの内部表現}
179 GCC は内部で Generic Tree, GIMPLE, RTL という3つの内部表現を扱う. 178 GCC は内部で Generic Tree, GIMPLE, RTL という3つの内部表現を扱う.
180 それぞれが 179 それぞれが
181 読み込んだソースコードは Generic Tree, GIMPLE, RTL の順に変換されていき, 180 読み込んだソースコードは Generic Tree, GIMPLE, RTL の順に変換されていき,
182 最後にアセンブラ言語へと出力される. 181 最後にアセンブラ言語へと出力される.
183 図\ref{fig:ir}は GCC がソースコードを読み込みアセンブラ言語出力までの流れを表した図である. 182 図\ref{fig:ir}は GCC がソースコードを読み込みアセンブラ言語出力までの流れを表した図である.
189 \caption{GCC によるコンパイルの一連の流れ} 188 \caption{GCC によるコンパイルの一連の流れ}
190 \label{fig:ir} 189 \label{fig:ir}
191 \end{figure} 190 \end{figure}
192 191
193 192
194 \subsubsection{Generic Tree} 193 \subsection{Generic Tree}
195 ソースコードより読み込んだ関数の情報を木構造で表したものが Generic Tree となる. 194 ソースコードより読み込んだ関数の情報を木構造で表したものが Generic Tree となる.
196 関数の返り値,引数,変数の型,条件式とプログラムの処理全てが木構造で表される. 195 関数の返り値,引数,変数の型,条件式とプログラムの処理全てが木構造で表される.
196
197 CbC の実装では parse の部分からこの Generic Tree 生成の部分に手が加わっている. 197 CbC の実装では parse の部分からこの Generic Tree 生成の部分に手が加わっている.
198 198
199 199
200 \subsubsection{GIMPLE} 200 \subsection{GIMPLE}
201 Generic Tree で表現されたデータは GIMPLE というデータ構造に変換される. 201 Generic Tree で表現されたデータは GIMPLE というデータ構造に変換される.
202 GIMPLE も Generic Tree と同じ構文木だが、より制約がかかった状態で作成された構文木となる. 202 GIMPLE も Generic Tree と同じ構文木だが、より制約がかかった状態で作成された構文木となる.
203 制約は「1つの枝に4つ以上の子を持たせない」等といったもので, 203 制約は「1つの枝に4つ以上の子を持たせない」等といったもので,
204 GIMPLE へと変換されたデータは Generic Tree より簡単な命令で表されることになり最適化がかけやすくなる. 204 GIMPLE へと変換されたデータは Generic Tree より簡単な命令で表されることになり最適化がかけやすくなる.
205 CbC の実装では特に修正は加えていない. 205 CbC の実装では特に修正は加えていない.
206 206
207 207
208 \subsubsection{Register Transfer Language (RTL)} 208 \subsection{Register Transfer Language (RTL)}
209 構文木 GIMPLE は解析が行われた後 RTL へと変換される. 209 構文木 GIMPLE は解析が行われた後 RTL へと変換される.
210 RTL はレジスタの割り当てといった低レベルの表現で,アセンブラとほぼ同じ表現を行うことができる. 210 RTL はレジスタの割り当てといった低レベルの表現で,アセンブラとほぼ同じ表現を行うことができる.
211 プログラム内部では RTL も木構造で表される. 211 プログラム内部では RTL も木構造で表される.
212 212
213 CbC における継続は,この RTL への変換で行われる最適化の1つ Tail Call Elimination が重要となってくる. 213 CbC における継続は,この RTL への変換で行われる最適化の1つ Tail Call Elimination が重要となってくる.
216 \section{GCC-4.6 への実装} 216 \section{GCC-4.6 への実装}
217 前節までで CbC の基本仕様と GCC でのアセンブラ出力までの流れを確認した. 217 前節までで CbC の基本仕様と GCC でのアセンブラ出力までの流れを確認した.
218 ここからは GCC-4.6 への実装について述べていく. 218 ここからは GCC-4.6 への実装について述べていく.
219 219
220 220
221 %\subsection{``\_\_code'' のパース} 221 \subsection{``\_\_code'' のパース}
222 C の予約後は \verb+gcc/c-family/c-common.c+ の \verb+c_common_reswords+ 構造体で定義されている.
223 ここに,図\ref{fig:code-parse}のように \verb+code+ の登録を行う.
224
225 \begin{figure}[htpb]
226 \begin{center}
227 \scalebox{0.35}{\includegraphics{figure/code-parse.eps}}
228 \end{center}
229 \caption{\_\_code のパース}
230 \label{fig:code-parse}
231 \end{figure}
232
233
234 これで \verb+__code+ は \verb+RID_CbC_CODE+ として判定されるようになる.
235 次に, id を用意する.
236 Genric Tree が生成されるデータは一度 \verb+c_declspecs+ 構造体に保存される.
237 そこに登録するコードセグメント判定用 id ``\verb+cts_CbC_code+'' を用意する.
238 これは gcc/c-tree.h で定義される(図\ref{fig:code-id}).
239
240 \begin{figure}[htpb]
241 \begin{center}
242 \scalebox{0.35}{\includegraphics{figure/code-id.eps}}
243 \end{center}
244 \caption{cts\_CbC\_code の定義}
245 \label{fig:code-id}
246 \end{figure}
247
248 後は\verb+c_declspecs+ 構造体にこの id を登録する.
249 id の登録は \verb+declspecs_add_type+ 関数の中で行われる(図\ref{fig:regi-id}).
250
251 \begin{figure}[htpb]
252 \begin{center}
253 \scalebox{0.35}{\includegraphics{figure/regi-id.eps}}
254 \end{center}
255 \caption{id の登録(declspecs\_add\_type 関数)}
256 \label{fig:regi-id}
257 \end{figure}
258
259 図\ref{fig:regi-id} のプログラムは void 型の id 登録を元に作られている.
260 違うところは \verb+cts_CbC_code+ を登録するところだけである.
261
262 最後に, \verb+finish_declspecs+ 関数にて id 毎に tree タイプの決定をする.
263 コードセグメントは void 型として扱ってもらうために \verb+void_type_node+ をタイプと
264 して登録している(図\ref{fig:regi-node}).
265
266 \begin{figure}[htpb]
267 \begin{center}
268 \scalebox{0.35}{\includegraphics{figure/regi-node.eps}}
269 \end{center}
270 \caption{declspecs\_add\_type 関数}
271 \label{fig:regi-node}
272 \end{figure}
273
274
222 275
223 \subsection{Tail Call Elimination} 276 \subsection{Tail Call Elimination}
224 CbC の継続の実装には GCC の最適化の1つ, Tail Call Elimination (末尾除去) を強制することで実装する. 277 CbC の継続の実装には GCC の最適化の1つ, Tail Call Elimination (末尾除去) を強制することで実装する.
225 これにより, コードセグメント間の移動を, call ではなく jmp 命令で実現する. 278 これにより, コードセグメント間の移動を, call ではなく jmp 命令で実現する.
226 %Tail Call Elimination とは関数の最後の処理で別の関数呼び出しを行った際に, 279 %Tail Call Elimination とは関数の最後の処理で別の関数呼び出しを行った際に,
227 %call ではなく jmp を用いることができるという最適化である. 280 %call ではなく jmp を用いることができるという最適化である.
228 図\ref{fig:continue}は Tail Call Elimination が行われた際のプログラムの処理を表している. 281 図\ref{fig:continue}は Tail Call Elimination が行われた際のプログラムの処理を表している.
229 282
230 \begin{figure}[htpb] 283 \begin{figure}[htpb]
231 \begin{center} 284 \begin{center}
232 \scalebox{0.35}{\includegraphics{figure/continuation.eps}} 285 \scalebox{0.30}{\includegraphics{figure/continuation.eps}}
233 \end{center} 286 \end{center}
234 \caption{Tail Call Elimination} 287 \caption{Tail Call Elimination}
235 \label{fig:continue} 288 \label{fig:continue}
236 \end{figure} 289 \end{figure}
237 funcB は jmp 命令で funcC を呼び出す. 290 funcB は jmp 命令で funcC を呼び出す.
262 \end{enumerate} 315 \end{enumerate}
263 316
264 1 については自明だろう.コードセグメントは戻値を持たない為 void 型の扱いになる. 317 1 については自明だろう.コードセグメントは戻値を持たない為 void 型の扱いになる.
265 2, 3 と 4 については以下で詳しく説明を行う. 318 2, 3 と 4 については以下で詳しく説明を行う.
266 319
267 \subsubsection{継続の直後に return の配置} 320 \subsubsection{goto の直後に return の配置}
268 この処理は Generic Tree の生成時に組み込んである為, ユーザは return を記述する必要はない. 321 図\ref{fig:factoril}の factorial0 関数を図\ref{code:return}の様に, goto の直後に return を
269 例をあげると, 図\ref{fig:factorial}の factorial0 は, 322 置く必要がある.だがそれをプログラムで記述することは実用的でない.
270 プログラム内部では図\ref{code:return}の様に処理されることになる. 323 CbC では Generic Tree の生成時に継続の直後に return を自動で組み込むことで解決している.
324 %, ユーザは return を記述する必要はない.
325 %例をあげると, 図\ref{fig:factorial}の factorial0 は,
326 % プログラム内部では図\ref{code:return}の様に処理されることになる.
327
271 \begin{figure}[h] 328 \begin{figure}[h]
272 \begin{minipage}[b]{.45\textwidth} 329 \begin{minipage}[b]{.45\textwidth}
273 \begin{lstlisting}[caption=継続の直後に return を置く,label=code:return] 330 \begin{lstlisting}[caption=goto の直後に return を置く,label=code:return]
274 __code factorial0(int prod, int x) 331 __code factorial0(int prod, int x)
275 { 332 {
276 if ( x >= 1) { 333 if ( x >= 1) {
277 goto factorial0(prod*x, x-1); 334 goto factorial0(prod*x, x-1);
278 return; 335 return;
307 %Tail Call Elimination にかからないコードセグメントがある. 364 %Tail Call Elimination にかからないコードセグメントがある.
308 %この点を改善する必要がある. 365 %この点を改善する必要がある.
309 366
310 %\subsection{引数の一時変数への避難} 367 %\subsection{引数の一時変数への避難}
311 %\subsection{スタック書き換えの問題} 368 %\subsection{スタック書き換えの問題}
312 \subsection{引数の並びの上書きコピー} 369 \subsubsection{引数の並びの上書きコピー}
313 CbC の継続では, 引数渡しでスタックを入れ替える為値が書き換えられる可能性がでてくる. 370 CbC の継続では, 引数渡しでスタックを入れ替える為値が書き換えられる可能性がでてくる.
314 例えばlistlising\ref{code:cs_prog}のような継続である. 371 例えばlistlising\ref{code:cs_prog}のような継続である.
315 \begin{figure}[h] 372 \begin{figure}[h]
316 \begin{minipage}[b]{.45\textwidth} 373 \begin{minipage}[b]{.45\textwidth}
317 \begin{lstlisting}[caption=スタックの上書きが起こる継続の例,label=code:cs_prog] 374 \begin{lstlisting}[caption=スタックの上書きが起こる継続の例,label=code:cs_prog]
364 tree call は継続を行うコードセグメントを指す. 421 tree call は継続を行うコードセグメントを指す.
365 コードセグメントに渡された引数の情報を抜き出す部分が \verb+FOR_EACH_CALL_EXPR_ARG+ である. 422 コードセグメントに渡された引数の情報を抜き出す部分が \verb+FOR_EACH_CALL_EXPR_ARG+ である.
366 \verb+tmp_decl+ という一時変数を作り,最後に \verb+CALL_EXPR_ARG+ を使って引数の情報が入っていた 423 \verb+tmp_decl+ という一時変数を作り,最後に \verb+CALL_EXPR_ARG+ を使って引数の情報が入っていた
367 ところへ一時変数を入れている. 424 ところへ一時変数を入れている.
368 425
369
370 \subsection{環境付き継続} 426 \subsection{環境付き継続}
371 CbC には通常の C の関数からコードセグメントに継続する際, 427 CbC には通常の C の関数からコードセグメントに継続する際,
372 その関数から値を戻す処理への継続を得ることができる. 428 その関数から値を戻す処理への継続を得ることができる.
373 これを環境付き継続という. 429 これを環境付き継続という.
374 これらは, 以下の二種類の CbC で定義した特殊変数である. 430 これらは, 以下の二種類の CbC で定義した特殊変数である.
375 \verb+__environment+ は, 環境を表す情報である. 431 \verb+__environment+ は, 環境を表す情報である.
376 \verb__return+ は, これを環境付き継続の行き先であり, 関数の戻値と \verb+__environment+ の二つの引数を持つ 432 \verb+__return+ は, これを環境付き継続の行き先であり, 関数の戻値と \verb+__environment+ の二つの引数を持つ
377 コードセグメントである. 例えば, 以下のように使うと, \verb+main()+ は 1 を返す. 433 コードセグメントである. 例えば, 以下のように使うと, \verb+main()+ は 1 を返す.
378 434
379 \begin{verbatim} 435 \begin{verbatim}
380 __code c1(__code ret(int,void *),void *env) { 436 __code c1(__code ret(int,void *),void *env) {
381 goto ret(1,env); 437 goto ret(1,env);
391 447
392 \begin{figure}[h] 448 \begin{figure}[h]
393 \begin{minipage}[b]{.45\textwidth} 449 \begin{minipage}[b]{.45\textwidth}
394 \begin{lstlisting}[caption=環境付き継続を行うコード,label=code:_ret_val] 450 \begin{lstlisting}[caption=環境付き継続を行うコード,label=code:_ret_val]
395 __label__ _cbc_exit0; 451 __label__ _cbc_exit0;
396 static int retval; // should be thread local 452 static int retval;
397 void _cbc_internal_return(int retval_, void *_envp){ 453 void _cbc_internal_return(int retval_,
454 void *_envp){
398 retval = retval_; 455 retval = retval_;
399 goto _cbc_exit0; 456 goto _cbc_exit0;
400 } 457 }
401 if (0) { 458 if (0) {
402 _cbc_exit0: 459 _cbc_exit0:
428 485
429 \subsubsection{fastcall} 486 \subsubsection{fastcall}
430 C において fastcall を用いる場合は関数にキーワード ``\verb+__attribute__ ((fastcall))+'' をつけて行う. 487 C において fastcall を用いる場合は関数にキーワード ``\verb+__attribute__ ((fastcall))+'' をつけて行う.
431 だが, コードセグメントを全てこのキーワードをつけて宣言することは実用的ではない. 488 だが, コードセグメントを全てこのキーワードをつけて宣言することは実用的ではない.
432 そこで, コードセグメントで宣言された場合, fastcall が自動で付くように実装を行う. 489 そこで, コードセグメントで宣言された場合, fastcall が自動で付くように実装を行う.
433 図\ref{fig:fastcall}はコードセグメントに fastcall 属性を付与しているコードである. 490 図\ref{fig:fastcall}はコードセグメントの生成を行なっているコードである.
434 491
435 %\lstinputlisting[language=c]{source/fastcall.c} 492 %\lstinputlisting[language=c]{source/fastcall.c}
436 493
437 \begin{figure}[htpb] 494 \begin{figure}[htpb]
438 \begin{center} 495 \begin{center}
465 \end{lstlisting} 522 \end{lstlisting}
466 \end{minipage} 523 \end{minipage}
467 \hfill 524 \hfill
468 \end{figure} 525 \end{figure}
469 526
470 typedefrec によりコードセグメントは自分自身に戻る構成ができる. 527 typedefrec によりコードセグメントは自分自身に戻る構成ができるようになる.
471 より柔軟なプログラミングが行えるように typdefrec の実装を行う予定である. 528 より柔軟なプログラミングが行えるように typdefrec の実装を行う予定である.
472
473 529
474 \section{評価} 530 \section{評価}
475 今回実装を行った GCC-4.6 ベースのコンパイラを GCC-4.4 ベース, 531 今回実装を行った GCC-4.6 ベースのコンパイラを GCC-4.4 ベース,
476 Micro-C コンパイラとそれぞれ比較を行った. 532 Micro-C コンパイラとそれぞれ比較を行った.
477 比較を行うのはクイックソートのプログラムである. 533 比較を行うのはクイックソートのプログラムである.
478 クイックソートは再帰的にプログラムされる為 CbC に向いている 534 %クイックソートは再帰的にプログラムされる為 CbC に向いている
479 プログラムだと言える. 535 %プログラムだと言える.
536 クイックソートは再帰的なプログラムな為スタック操作が行われる.
480 比較を行うのは以下のアーキテクチャと OS になる. 537 比較を行うのは以下のアーキテクチャと OS になる.
481 538
482 %\begin{description} 539 %\begin{description}
483 \begin{itemize} 540 \begin{itemize}
484 \item x86/Linux 541 \item x86/Linux
519 \end{tabular} 576 \end{tabular}
520 \caption{アーキテクチャ毎のGCCとmicro-cの速度比較(単位: 秒)(速度最適化)} 577 \caption{アーキテクチャ毎のGCCとmicro-cの速度比較(単位: 秒)(速度最適化)}
521 \label{tab:speed-mc-vs-gcc-opt} 578 \label{tab:speed-mc-vs-gcc-opt}
522 \end{table} 579 \end{table}
523 580
581
582 \section{まとめと今後の課題}
583 今回 CbC コンパイラを GCC-4.6 へとアップデートを行った.
584
585
586
587
588
524 \nocite{kono:2002a, kono:2008a, yogi:2008a, gcc_internals} 589 \nocite{kono:2002a, kono:2008a, yogi:2008a, gcc_internals}
525 \bibliographystyle{junsrt} 590 \bibliographystyle{junsrt}
526 \bibliography{cbc.bib} 591 \bibliography{cbc.bib}
527 592
528 \end{document} 593 \end{document}