Mercurial > hg > Papers > 2011 > nobu-prosym
comparison Paper/nobu-prosym.tex @ 29:d80535a49459
modify tex
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 21 Nov 2011 06:28:32 +0900 |
parents | 9ca3eb4921d6 |
children | db9735be2bf1 |
comparison
equal
deleted
inserted
replaced
28:9ca3eb4921d6 | 29:d80535a49459 |
---|---|
113 GCC への実装により,GCC の最適化やデバッガの機能を使うことができより実用的な CbC プログラミングが行えるようになった. | 113 GCC への実装により,GCC の最適化やデバッガの機能を使うことができより実用的な CbC プログラミングが行えるようになった. |
114 %以来,GCC のアップデートに合わせて GCC ベースの CbC コンパイラのアップデートを行って来ている. | 114 %以来,GCC のアップデートに合わせて GCC ベースの CbC コンパイラのアップデートを行って来ている. |
115 %今回,CbC コンパイラを GCC-4.6 へとアップデートを行った. | 115 %今回,CbC コンパイラを GCC-4.6 へとアップデートを行った. |
116 %本論文では, CbC,GCC の簡単な説明と,GCC-4.6 への実装を述べる. | 116 %本論文では, CbC,GCC の簡単な説明と,GCC-4.6 への実装を述べる. |
117 だが, GCC をベースとした CbC のコンパイラ (以下 CbC-GCC)は, GCC のアップデートに合わせて変更する必要がある. | 117 だが, GCC をベースとした CbC のコンパイラ (以下 CbC-GCC)は, GCC のアップデートに合わせて変更する必要がある. |
118 本研究では, GCC-4.5 をベースとしていた CbC-GCC を GCC-4.6 へのアップデートを行い, Intel64 に対応するとともに, CbC の拡張を行う. | 118 本研究では, GCC-4.5.0 をベースとしていた CbC-GCC を GCC-4.6.0 へのアップデートを行い, Intel64 に対応するとともに, CbC の拡張を行う. |
119 | 119 |
120 | 120 |
121 %}{ | 121 %}{ |
122 | 122 |
123 \section{Continuation based C (CbC)} | 123 \section{Continuation based C (CbC)} |
157 | 157 |
158 図\ref{fig:factorial}は CbC で書いたプログラムの例である. | 158 図\ref{fig:factorial}は CbC で書いたプログラムの例である. |
159 与えられた数 x の階上を計算して出力するプログラムとなっている. | 159 与えられた数 x の階上を計算して出力するプログラムとなっている. |
160 | 160 |
161 \begin{figure} | 161 \begin{figure} |
162 \begin{footnotesize} | |
162 \lstinputlisting[language=c]{source/factorial.cbc} | 163 \lstinputlisting[language=c]{source/factorial.cbc} |
163 \caption{階上を計算する CbC プログラムの例} | 164 \caption{階上を計算する CbC プログラムの例} |
164 \label{fig:factorial} | 165 \label{fig:factorial} |
165 \end{figure} | 166 \end{footnotesize} |
166 | 167 \end{figure} |
167 %CbC におけるプログラムの基本単位としてコードセグメントという概念がある. | 168 |
168 %コードセグメントの記述の仕方は C の関数と同じだが, 型に ``\_\_code''を使って宣言を行うところだけが違う. | 169 |
169 %関数と同じように引数を持たせて継続させることもできる. | |
170 %しかし,関数とは違ってリターンを行わない為返り値を取得することはできない. | |
171 | |
172 %コードセグメントは関数よりも小さな単位で記述される為,最適化がされやすくなる. | |
173 %コードセグメントの記述の仕方は C の関数と同じで,引数を持たせて継続を行うことができる. | |
174 \section{GCCの3つの内部表現} | 170 \section{GCCの3つの内部表現} |
175 GCC-4.6 への実装の前に,GCC で扱われる3つの内部表現について触れておく. | 171 GCC-4.6 への実装の前に,GCC で扱われる3つの内部表現について触れておく. |
176 | 172 |
177 GCC は内部で Generic Tree, GIMPLE, RTL という3つの内部表現を扱う. | 173 GCC は内部で Generic Tree, GIMPLE Tree, RTL という3つの内部表現を扱う. |
178 それぞれが | 174 それぞれが |
179 読み込んだソースコードは Generic Tree, GIMPLE, RTL の順に変換されていき, | 175 読み込んだソースコードは Generic Tree, GIMPLE Tree, RTL の順に変換されていき, |
180 最後にアセンブラ言語へと出力される. | 176 最後にアセンブラ言語へと出力される. |
181 図\ref{fig:ir}は GCC がソースコードを読み込みアセンブラ言語出力までの流れを表した図である. | 177 図\ref{fig:ir}は GCC がソースコードを読み込みアセンブラ言語出力までの流れを表した図である. |
182 | 178 |
183 \begin{figure}[htpb] | 179 \begin{figure}[htpb] |
184 \begin{center} | 180 \begin{center} |
194 関数の戻値,引数,変数の型,条件式とプログラムの処理全てが木構造で表される. | 190 関数の戻値,引数,変数の型,条件式とプログラムの処理全てが木構造で表される. |
195 | 191 |
196 CbC の実装では parse の部分からこの Generic Tree 生成の部分に手が加わっている. | 192 CbC の実装では parse の部分からこの Generic Tree 生成の部分に手が加わっている. |
197 | 193 |
198 | 194 |
199 \subsection{GIMPLE} | 195 \subsection{GIMPLE Tree} |
200 Generic Tree で表現されたデータは GIMPLE というデータ構造に変換される. | 196 Generic Tree で表現されたデータは GIMPLE Tree に変換される. |
201 GIMPLE も Generic Tree と同じ構文木だが、より制約がかかった状態で作成された構文木となる. | 197 GIMPLE Tree は Generic Tree より制約がかかった状態で作成された構文木となる. |
202 制約は「1つの枝に4つ以上の子を持たせない」等といったもので, | 198 制約は「1つの枝に4つ以上の子を持たせない」等といったもので, |
203 GIMPLE へと変換されたデータは Generic Tree より簡単な命令で表されることになり最適化がかけやすくなる. | 199 GIMPLE Tree へと変換されたデータは Generic Tree より簡単な命令で表されることになり最適化がかけやすくなる. |
204 CbC の実装では特に修正は加えていない. | 200 CbC の実装では特に修正は加えていない. |
205 | 201 |
206 | 202 |
207 \subsection{Register Transfer Language (RTL)} | 203 \subsection{Register Transfer Language (RTL)} |
208 構文木 GIMPLE は解析が行われた後 RTL へと変換される. | 204 GIMPLE Tree は解析が行われた後 RTL へと変換される. |
209 RTL はレジスタの割り当てといった低レベルの表現で,アセンブラとほぼ同じ表現を行うことができる. | 205 RTL はレジスタの割り当てといった低レベルの表現で,アセンブラとほぼ同じ表現を行うことができる. |
210 プログラム内部では RTL も木構造で表される. | 206 プログラム内部では RTL も木構造で表される. |
211 | 207 |
212 CbC における継続は,この RTL への変換で行われる最適化の1つ Tail Call Elimination が重要となってくる. | 208 CbC における継続は,この RTL への変換で行われる最適化の1つ Tail Call Elimination が重要となってくる. |
213 | 209 |
217 ここからは GCC-4.6 への実装について述べていく. | 213 ここからは GCC-4.6 への実装について述べていく. |
218 | 214 |
219 | 215 |
220 \subsection{``\_\_code'' のパース} | 216 \subsection{``\_\_code'' のパース} |
221 C の予約後は \verb+gcc/c-family/c-common.c+ の \verb+c_common_reswords+ 構造体で定義されている. | 217 C の予約後は \verb+gcc/c-family/c-common.c+ の \verb+c_common_reswords+ 構造体で定義されている. |
222 ここに,図\ref{fig:code-parse}のように \verb+code+ の登録を行う. | 218 ここに,図\ref{fig:code-parse}のように \verb+__code+ 型の登録を行う. |
223 | 219 |
224 \begin{figure}[htpb] | 220 \begin{figure}[htpb] |
225 \begin{center} | 221 \begin{center} |
226 \scalebox{0.35}{\includegraphics{figure/code-parse.eps}} | 222 \scalebox{0.35}{\includegraphics{figure/code-parse.eps}} |
227 \end{center} | 223 \end{center} |
232 | 228 |
233 これで \verb+__code+ は \verb+RID_CbC_CODE+ として判定されるようになる. | 229 これで \verb+__code+ は \verb+RID_CbC_CODE+ として判定されるようになる. |
234 次に, id を用意する. | 230 次に, id を用意する. |
235 Genric Tree が生成されるデータは一度 \verb+c_declspecs+ 構造体に保存される. | 231 Genric Tree が生成されるデータは一度 \verb+c_declspecs+ 構造体に保存される. |
236 そこに登録するコードセグメント判定用 id ``\verb+cts_CbC_code+'' を用意する. | 232 そこに登録するコードセグメント判定用 id ``\verb+cts_CbC_code+'' を用意する. |
237 これは gcc/c-tree.h で定義される(図\ref{fig:code-id}). | 233 これは gcc/c-Tree.h で定義される(図\ref{fig:code-id}). |
238 | 234 |
239 \begin{figure}[htpb] | 235 \begin{figure}[htpb] |
240 \begin{center} | 236 \begin{center} |
241 \scalebox{0.35}{\includegraphics{figure/code-id.eps}} | 237 \scalebox{0.35}{\includegraphics{figure/code-id.eps}} |
242 \end{center} | 238 \end{center} |
256 \end{figure} | 252 \end{figure} |
257 | 253 |
258 図\ref{fig:regi-id} のプログラムは void 型の id 登録を元に作られている. | 254 図\ref{fig:regi-id} のプログラムは void 型の id 登録を元に作られている. |
259 違うところは \verb+cts_CbC_code+ を登録するところだけである. | 255 違うところは \verb+cts_CbC_code+ を登録するところだけである. |
260 | 256 |
261 最後に, \verb+finish_declspecs+ 関数にて id 毎に tree タイプの決定をする. | 257 最後に, \verb+finish_declspecs+ 関数にて id 毎に Tree タイプの決定をする. |
262 コードセグメントは void 型として扱ってもらうために \verb+void_type_node+ をタイプと | 258 コードセグメントは void 型として扱ってもらうために \verb+void_type_node+ を Tree のタイプと |
263 して登録している(図\ref{fig:regi-node}). | 259 して登録している(図\ref{fig:regi-node}). |
264 | 260 |
265 \begin{figure}[htpb] | 261 \begin{figure}[htpb] |
266 \begin{center} | 262 \begin{center} |
267 \scalebox{0.35}{\includegraphics{figure/regi-node.eps}} | 263 \scalebox{0.35}{\includegraphics{figure/regi-node.eps}} |
285 \label{fig:rid-goto} | 281 \label{fig:rid-goto} |
286 \end{figure} | 282 \end{figure} |
287 | 283 |
288 %具体的には, 読み込んだ CPP_NAME が関数の場合の処理を追加した. | 284 %具体的には, 読み込んだ CPP_NAME が関数の場合の処理を追加した. |
289 具体的には | 285 具体的には |
290 void 型の tree を元にコードセグメントと判定するフラグ と Tail Call のフラグ | 286 void 型の Tree を作成している.加えてコードセグメントと判定するフラグ と Tail Call のフラグ |
291 を付けた関数として tree の作成を行なっている. | 287 を付けた関数とした Tree となる. |
288 %の作成を行なっている. | |
292 | 289 |
293 \verb+cbc_replace_argments+ 関数と \verb+c_finish_return+ 関数の動作については | 290 \verb+cbc_replace_argments+ 関数と \verb+c_finish_return+ 関数の動作については |
294 CbC においても重要になるので後に詳しく説明する. | 291 CbC においても重要になるので後に詳しく説明する. |
295 | 292 |
296 \subsection{Tail Call Elimination} | 293 \subsection{Tail Call Elimination} |
309 \end{figure} | 306 \end{figure} |
310 funcB は jmp 命令で funcC を呼び出す. | 307 funcB は jmp 命令で funcC を呼び出す. |
311 funcC は, 戻値を funcB ではなく funcA へと返すことになる. | 308 funcC は, 戻値を funcB ではなく funcA へと返すことになる. |
312 | 309 |
313 \subsubsection{expand\_call} | 310 \subsubsection{expand\_call} |
314 ある関数が Tail Call Elimination を行えるかどうかは \verb+expand_call+ 関数で判断される. | 311 \verb+expand_call+ 関数は, 関数を表す Tree から RTL を生成する関数である. |
315 \verb+expand_call+ 関数内でチェックされる Tail Call Elimination が行える条件は以下になる. | 312 Tail Call Elimination を行えるかどうかもこの関数で判断される. |
313 内部でチェックされる Tail Call Elimination の条件は以下になる. | |
314 %\verb+expand_call+ 関数内でチェックされる Tail Call Elimination が行える条件は以下になる. | |
316 | 315 |
317 %\begin{itemize} | 316 %\begin{itemize} |
318 \begin{enumerate} | 317 \begin{enumerate} |
319 \item caller 側と callee 側の戻値の型が一致している. | 318 \item caller 側と callee 側の戻値の型が一致している. |
320 \item 関数呼び出しがリターンの直前に行われている. | 319 \item 関数呼び出しがリターンの直前に行われている. |
340 戻値を持たない為, コードセグメントを void 型で統一するのは自明だろう. | 339 戻値を持たない為, コードセグメントを void 型で統一するのは自明だろう. |
341 最適化の強制付与及び 2, 3 と 4 については以下で詳しく説明を行う. | 340 最適化の強制付与及び 2, 3 と 4 については以下で詳しく説明を行う. |
342 | 341 |
343 \subsubsection{末尾最適化の強制付与} | 342 \subsubsection{末尾最適化の強制付与} |
344 Tail Call Elimination は C のプログラムにおいて末尾最適化を有効にすることで行われる. | 343 Tail Call Elimination は C のプログラムにおいて末尾最適化を有効にすることで行われる. |
345 以前の GCC の初期の実装では \verb+expand_call+ 関数を元にした \verb+expand_cbc_call+ 関数を作成して, | 344 以前の CbC-GCC の実装では \verb+expand_call+ 関数を元にした \verb+expand_cbc_call+ 関数を作成して, |
346 条件をクリアするようにしていた. | 345 条件をクリアするようにしていた. |
347 しかし, その方法では \verb+expand_call+ 関数が改良される度に \verb+expand_cbc_call+ 関数にも | 346 しかし, その方法では \verb+expand_call+ 関数が改良される度に \verb+expand_cbc_call+ 関数にも |
348 変更を加える必要があり, 手間となっていた. | 347 変更を加える必要があり, 手間となっていた. |
349 そこで, 最適化フラグを強制的に付与させることで \verb+expand_cbc_call+ 関数を取り除くことに成功した. | 348 そこで, 最適化フラグを強制的に付与させることで \verb+expand_cbc_call+ 関数を取り除くことに |
350 | 349 成功した(図\ref{fig:tail_call}:2行目). |
351 \verb+expand_call+ 関数内では, Tail Call Eliminatino に書けるためのフラグ, \verb+try_tail_call+ | 350 |
351 \begin{figure}[htpb] | |
352 \begin{center} | |
353 \scalebox{0.35}{\includegraphics{figure/tail_call_flag.eps}} | |
354 \end{center} | |
355 \caption{コードセグメントの末尾最適化の付与} | |
356 \label{fig:tail_call} | |
357 \end{figure} | |
358 | |
359 | |
360 \verb+expand_call+ 関数内では, Tail Call Eliminatino にかけるためのフラグ, \verb+try_tail_call+ | |
352 変数があり, コードセグメントはこのフラグには初め 1 がセットされている. | 361 変数があり, コードセグメントはこのフラグには初め 1 がセットされている. |
353 コードセグメントの時はこの \verb+try_tail_call+ 変数に 0 を代入させないように実装を行った. | 362 コードセグメントの時はこの \verb+try_tail_call+ 変数に 0 を代入させないように実装を行った. |
354 また, 万が一 \verb+try_tail_call+ 変数に 0 を代入された時の為にフラグに 1 を代入するコードの挿入も行った. | 363 また, 万が一 \verb+try_tail_call+ 変数に 0 を代入された時の為にフラグに 1 を代入するコードの挿入も行った. |
355 これにより末尾最適化の強制付与がなされた. | 364 これにより末尾最適化の強制付与がなされた. |
356 | 365 |
358 \subsubsection{goto の直後に return の配置} | 367 \subsubsection{goto の直後に return の配置} |
359 図\ref{fig:factorial}のコードセグメント factorial0 をlisting\ref{code:return}の様に, goto の直後に return を | 368 図\ref{fig:factorial}のコードセグメント factorial0 をlisting\ref{code:return}の様に, goto の直後に return を |
360 置く必要がある.だがそれをプログラマが記述することは実用的でない. | 369 置く必要がある.だがそれをプログラマが記述することは実用的でない. |
361 | 370 |
362 \begin{figure}[h] | 371 \begin{figure}[h] |
372 \begin{footnotesize} | |
363 \begin{minipage}[b]{.45\textwidth} | 373 \begin{minipage}[b]{.45\textwidth} |
364 \begin{lstlisting}[caption=goto の直後に return を置く,label=code:return] | 374 \begin{lstlisting}[caption=goto の直後に return を置く,label=code:return] |
365 __code factorial0(int prod, int x) | 375 __code factorial0(int prod, int x) |
366 { | 376 { |
367 if ( x >= 1) { | 377 if ( x >= 1) { |
373 } | 383 } |
374 } | 384 } |
375 \end{lstlisting} | 385 \end{lstlisting} |
376 \end{minipage} | 386 \end{minipage} |
377 \hfill | 387 \hfill |
388 \end{footnotesize} | |
378 \end{figure} | 389 \end{figure} |
379 CbC では Generic Tree の生成時に継続の直後に return を自動で組み込むことで解決している. | 390 CbC では Generic Tree の生成時に継続の直後に return を自動で組み込むことで解決している. |
380 図\ref{fig:rid-goto}の\verb+c_finish_return+ 関数がそれにあたる. | 391 図\ref{fig:rid-goto}の\verb+c_finish_return+ 関数がそれにあたる. |
381 | 392 |
382 %goto でコードセグメントの継続を行うプログラムの直後に return を表す情報を Generic Tree に追加を行う. | 393 %goto でコードセグメントの継続を行うプログラムの直後に return を表す情報を Generic Tree に追加を行う. |
387 これも CbC の1つの特徴である. | 398 これも CbC の1つの特徴である. |
388 図\ref{fig:cs_stack}はコードセグメントの継続の際にスタックに積まれる引数を表している. | 399 図\ref{fig:cs_stack}はコードセグメントの継続の際にスタックに積まれる引数を表している. |
389 | 400 |
390 \begin{figure}[htpb] | 401 \begin{figure}[htpb] |
391 \begin{center} | 402 \begin{center} |
392 \scalebox{0.33}{\includegraphics{figure/cs_stack.eps}} | 403 \scalebox{0.30}{\includegraphics{figure/cs_stack.eps}} |
393 \end{center} | 404 \end{center} |
394 \caption{継続による引数のスタック格納の様子} | 405 \caption{継続による引数のスタック格納の様子} |
395 \label{fig:cs_stack} | 406 \label{fig:cs_stack} |
396 \end{figure} | 407 \end{figure} |
397 | 408 |
403 %\subsection{スタック書き換えの問題} | 414 %\subsection{スタック書き換えの問題} |
404 \subsubsection{引数の並びの上書きコピー} | 415 \subsubsection{引数の並びの上書きコピー} |
405 CbC の継続では, 引数渡しでスタックを入れ替える為値が書き換えられる可能性がでてくる. | 416 CbC の継続では, 引数渡しでスタックを入れ替える為値が書き換えられる可能性がでてくる. |
406 例えばlistlising\ref{code:cs_prog}のような継続である. | 417 例えばlistlising\ref{code:cs_prog}のような継続である. |
407 \begin{figure}[h] | 418 \begin{figure}[h] |
419 \begin{footnotesize} | |
408 \begin{minipage}[b]{.45\textwidth} | 420 \begin{minipage}[b]{.45\textwidth} |
409 \begin{lstlisting}[caption=スタックの上書きが起こる継続の例,label=code:cs_prog] | 421 \begin{lstlisting}[caption=スタックの上書きが起こる継続の例,label=code:cs_prog] |
410 __code cs_a(int a, int b) { | 422 __code cs_a(int a, int b) { |
411 goto cs_b(b, a) | 423 goto cs_b(b, a) |
412 } | 424 } |
413 \end{lstlisting} | 425 \end{lstlisting} |
414 \end{minipage} | 426 \end{minipage} |
415 \hfill | 427 \hfill |
428 \end{footnotesize} | |
416 \end{figure} | 429 \end{figure} |
417 | 430 |
418 | 431 |
419 \begin{figure}[htpb] | 432 \begin{figure}[htpb] |
420 \begin{center} | 433 \begin{center} |
451 \item 引数と同じ型の一時変数を作成 | 464 \item 引数と同じ型の一時変数を作成 |
452 \item 一時変数に引数の値を代入 | 465 \item 一時変数に引数の値を代入 |
453 \item 関数に渡す引数のポインタを一時変数に変更 | 466 \item 関数に渡す引数のポインタを一時変数に変更 |
454 \end{itemize} | 467 \end{itemize} |
455 | 468 |
456 tree call は継続を行うコードセグメントを指す. | 469 Tree call は継続を行うコードセグメントを指す. |
457 コードセグメントに渡された引数の情報を抜き出す部分が \verb+FOR_EACH_CALL_EXPR_ARG+ である. | 470 コードセグメントに渡された引数の情報を抜き出す部分が \verb+FOR_EACH_CALL_EXPR_ARG+ である. |
458 \verb+tmp_decl+ という一時変数を作り,最後に \verb+CALL_EXPR_ARG+ を使って引数の情報が入っていた | 471 \verb+tmp_decl+ という一時変数を作り,最後に \verb+CALL_EXPR_ARG+ を使って引数の情報が入っていた |
459 ところへ一時変数を入れている. | 472 ところへ一時変数を入れている. |
460 | 473 |
461 \subsection{環境付き継続} | 474 \subsection{環境付き継続} |