annotate main.tex @ 3:e35e566b9983

*** empty log message ***
author kent
date Wed, 18 Jun 2008 12:55:12 +0900
parents b61e7bfa07c4
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
1 % File: main.tex
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
2 % Created: 日 6 01 18:00 PM 2008 J
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
3 % Last Change: 火 6 03 13:19 PM 2008 J
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
4 %
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
5 %\documentclass[a4j,twocolumn,9pt]{dsw-style/compsoft-dsw08}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
6 \documentclass[ronbun,epsfig]{compsoft-dsw08}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
7 %see /usr/local/ptetex3/share/texmf/ptex/platex209/jarticle.sty
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
8 \usepackage[dvipdfm]{graphicx}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
9 \usepackage{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
10 \usepackage{nonDefaultPackage/listings}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
11 \usepackage{url}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
12
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
13 \title{組み込み向け低レベル言語 CbC の GCC による実装}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
14 \author{与儀 健人 \and 河野 真治}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
15
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
16 \renewcommand{\paragraph}[1]{ {\par\vspace{1em}\normalsize\bf #1} }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
17 %\renewcommand{\thepage}{--- \arabic{page} ---}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
18 %\renewcommand{\labelenumi}{\roman{enumi})}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
19 \def\theenumi{\roman{enumi}}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
20 \def\labelenumi{\theenumi)}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
21 %\def\p@enumi{i)}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
22 \renewcommand{\lstlistingname}{リスト}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
23 \lstset{
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
24 language=C,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
25 stringstyle=\ttfamily,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
26 basicstyle=\small\ttfamily,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
27 commentstyle=\itshape,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
28 classoffset=1,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
29 keywordstyle=\bfseries,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
30 framesep=5pt,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
31 showstringspaces=false,%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
32 %frame=tRBl,
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
33 %numbers=left,stepnumber=1,numberstyle=\footnotesize%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
34 }%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
35 \def\lstlistingname{リスト}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
36 \def\lstlistlistingname{プログラムコード目次}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
37
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
38
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
39
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
40
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
41 \begin{document}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
42 %\twocolumn[\maketitle]{}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
43 \maketitle
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
44
2
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
45 \section{概要}
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
46 当研究室ではContinuation based C(以下CbC)という言語を提案しており、
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
47 そのコンパイルにはこれまでMicro-Cをベースにした独自のコンパイラを使用していた。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
48 また、以前の論文で
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
49 GCCのTail call optimizationを用いてGCC上に実装が可能である事を示した。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
50 ここではGCC上に実際にCbC言語の実装し、その評価を行った。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
51 この実装はアーキテクチャに依存しないので、GCCが対応する全てのアーキテクチャ上でCbCが動く事になるはずであるが、若干の問題があり、その点に付いても考察を行う。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
52
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
53
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
54 \section{CbCについて}\label{sec:CbC}
2
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
55 Continuation based Cは当研究室が提案するアセンブラよりも上位で
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
56 Cよりも下位な記述言語である\cite{kono2}。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
57 Cの仕様からループ制御や関数コールを取り除き、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
58 継続(goto) や コードセグメントを導入している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
59 これによりスタックの操作やループ、関数呼び出しなどのより低レベルでの最適化を、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
60 ソースコードレベルで行うことができる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
61
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
62 図\ref{fig:continuation}はコードセグメント同士の関係を表したものである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
63 \begin{figure}[htpb]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
64 \begin{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
65 \includegraphics[width=.45\textwidth,bb=0 0 351 202]{figures/continuation.pdf}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
66 \end{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
67 \caption{コードセグメント間の``継続''}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
68 \label{fig:continuation}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
69 \end{figure}%
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
70 コードセグメント\verb|start|は実行を終えるとgotoによって
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
71 別のコードセグメント \verb|A|もしくは\verb|B|に実行を継続する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
72 また、\verb|A|から\verb|B|,再び\verb|A|の用に継続を繰り返すことも可能だ。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
73 このように、コードセグメントからgotoを用いて別のコードセグメントへ飛ぶ
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
74 構成はオートマトンと似た構造になっていることがわかる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
75
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
76 これらの特徴から、CbCは自身でスケジューラの記述ができ、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
77 それにより並列処理や逐次処理をスムースに繋げることが出来る。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
78 また、OperatingSystemの記述やハードウェアの記述に向いている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
79
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
80 以下では実装に必要なCbCの構文、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
81 コードセグメントの定義と継続(goto)について説明する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
82 \paragraph{コードセグメント}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
83 はCbCにおける最も基本的な処理単位である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
84 コードセグメントを定義する構文は通常の関数と同じであるが、型は``\_\_code''となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
85 ただし、コードセグメントは関数のようにリターンすることはないので、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
86 これはコードセグメントであることを示すフラグの様なものである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
87
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
88 コードセグメントの処理内容も通常の関数と同じように定義されるが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
89 Cと違いコードセグメントではforやwhile, returnなどの構文は存在しない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
90 ループ等の制御は自分自身への再帰的な継続によって実現されることになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
91
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
92 \paragraph{継続 (goto)}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
93 はコードセグメント間の移動を表す。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
94 構文としてはgotoをつかっているがCにおけるlabelへのgotoとは違い、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
95 gotoの後ろに関数呼び出しの様な形をとる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
96 例として、あるコードセグメント \verb|cs|への継続は
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
97 \verb|goto cs(10, "test");|となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
98 これにより、csに対して引数\verb|10|と\verb|"test"|を渡すことができる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
99 ただし関数コールとは違い、継続ではコールスタックの拡張を行わない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
100 代わりにgotoを発行したコードセグメントの持つスタック自体に次のコードセグメント
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
101 の引数を書き込むことになる。また、returnアドレスのpushなども行わない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
102
2
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
103 \subsection{CbCの例文}
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
104 以上の2つの構文を使った例題をリスト\ref{code:cbc_example}に示す。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
105 \begin{lstlisting}[caption=CbC 例,label=code:cbc_example]
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
106 __code while_cond(int total, int count){
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
107 if ( count <= 100 ){
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
108 goto while_process(total,count);
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
109 }else{
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
110 goto while_end(total);
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
111 }
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
112 }
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
113 __code while_process(int total,
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
114 int count){
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
115 /* some processes */
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
116 goto while_cond(total, count);
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
117 }
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
118 __code while_end(int total){
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
119 goto cs_exit(0);
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
120 }
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
121 \end{lstlisting}
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
122 これは単純なループ構造である。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
123 まず\verb|while_cond|が実行されると、そこでは条件判定により
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
124 \verb|while_process|か\verb|while_end|に継続する。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
125 \verb|while_process|では処理が終了すると再び\verb|while_cond|に
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
126 継続することでループが形成される。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
127 このようにCbCではforやwhileを使用せずコードセグメントから
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
128 同じコードセグメントへ継続する形でループが表現される。
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
129
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
130
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
131 \section{GCCの構成}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
132 今回の実装ではGCCのソースコードを修正することになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
133 また、GCCの最適化処理の一つであるTail callがその実装に深く関わってくる\cite{kono1}。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
134 この章ではGCCの基本的な動作について簡単に説明する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
135 \subsection{GCCの基本構造}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
136 GCCはpassと呼ばれる一連の処理の中でソースコードをアセンブリに変換する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
137 以下ではそのpassの中でも重要なものをその実行順に説明する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
138 \begin{description}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
139 \item[parsing] パーサによってソースコードを解析する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
140 解析した結果はGeneric Treeと呼ばれるtree構造の構造体に格納される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
141 \item[gimplification] Generic TreeをもとにこれをGIMPLEに変換する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
142 \item[GIMPLE optimization] GIMPLEに対して最適化を行う。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
143 \item[RTL generation] GIMPLEをもとにRTLを生成する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
144 \item[RTL optimization] RTLに対して最適化を行う。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
145 \item[Output assembly] RTLをもとにターゲットマシンのアセンブリに変換する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
146 \end{description}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
147 これらの処理は図\ref{fig:GCC-pass}のように表される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
148 \begin{figure}[htbp]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
149 \begin{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
150 \includegraphics[width=.45\textwidth,bb=0 0 371 214]{figures/GCC-pass.pdf}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
151 \end{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
152 \caption{GCCのpass}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
153 \label{fig:GCC-pass}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
154 \end{figure}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
155 各passは通常は各々の関数毎に行われるものだが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
156 inline関数の処理や、関数間での最適化を行う場合には
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
157 一つのソースファイル毎に行われる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
158
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
159 \subsection{Tail call elimination}\label{sec:tailcall}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
160 最適化のひとつである``Tail call elimination''
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
161 \footnote{Tail call Optimizationと呼ばれたり、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
162 単にTail callと呼ばれたり、呼称はさまざまである。}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
163 は、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
164 ``関数のreturnの前に別の関数呼び出しがある場合はcall命令でなくjump命令が
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
165 使える''というアイデアを元に設計されている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
166 この最適化は本研究におけるCbCコンパイラの実装に深く関わってくるので、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
167 以下で詳しく説明する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
168
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
169 \subsubsection{Tail callの概要}\label{ssec:tailcall}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
170 まずmain関数から関数Aを呼び出していて、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
171 関数Aの最後の処理(return直前)では次に関数Bを呼び出している状況を考える
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
172 (図\ref{fig:Tail call}参照)。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
173 このあと関数Bの処理が終了すると、ret命令により一旦関数Aに戻ってきて、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
174 そこで再びret命令をつかってmainに戻ることになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
175 ``Tail call elimination''ではこのBからAに戻る無駄な処理を低減する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
176 この様子を図\ref{fig:Tail call}に示したので参考にしていただきたい。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
177 \begin{figure}[htpb]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
178 \begin{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
179 \includegraphics[width=.45\textwidth,bb=0 0 382 263]{figures/GCC-TailCall.pdf}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
180 \end{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
181 \caption{Tail call eliminationの例}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
182 \label{fig:Tail call}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
183 \end{figure}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
184
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
185 次に``Tail call elimination''によって、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
186 アセンブリレベルでどのようにコードが変わるのか、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
187 スタックの変化も交えて見てみる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
188 この例では最も一般的に使われているi386形式のアセンブラを使用している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
189
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
190 図\ref{fig:Tail call}と同じように呼び出される関数main, A, Bを
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
191 リスト\ref{code:main A B}の様に定義する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
192 \begin{lstlisting}[caption=関数main\, A\, Bの例,label=code:main A B]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
193 void B(int A, int A, int C){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
194 /* what do you do? */
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
195 return ;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
196 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
197 void A(int a, int b, int c, int d){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
198 /* some processes.. */
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
199 return B(a, b, c+d);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
200 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
201 int main(int argc, char **argv){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
202 A(10, 20, 30, 40);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
203 return 0;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
204 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
205 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
206 これを通常通り、``Tail call elimination''を使用せずにコンパイルすると
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
207 次のリスト\ref{code:compiled A}のようなコードが出力される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
208 ここではTailcall最適化が影響をあたえる関数Aのみをしめした。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
209 また、出力アーキテクチャはi386である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
210 \begin{lstlisting}[language=,caption=関数Aのコンパイル結果(Tail callなし),label=code:compiled A]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
211 A:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
212 pushl %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
213 movl %esp, %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
214 subl $24, %esp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
215 movl 20(%ebp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
216 addl 16(%ebp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
217 movl %eax, 8(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
218 movl 12(%ebp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
219 movl %eax, 4(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
220 movl 8(%ebp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
221 movl %eax, (%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
222 call B
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
223 leave
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
224 ret
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
225 .size A, .-A
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
226 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
227 これを見ても分かる通り、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
228 Tail callをしない場合はAのスタック領域の上にBのスタック領域が確保され、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
229 Bが終了するとそれが破棄される形になる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
230
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
231 次にTail call eliminationが行われた場合の
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
232 コンパイル結果をリスト\ref{code:tailcalled A}に示す。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
233 \begin{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
234 \begin{lstlisting}[caption=Tail call eliminationの行われた関数A, label=code:tailcalled A]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
235 A:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
236 pushl %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
237 movl %esp, %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
238 movl 20(%ebp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
239 addl %eax, 16(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
240 popl %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
241 jmp B
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
242 .size A, .-A
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
243 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
244 \end{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
245 \verb|20(%ebp)|は変数d、\verb|16(%ebp)|は変数cを表している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
246 ここではBのためにスタック領域は確保せず、かわりにAのスタック領域に
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
247 Bのための引数を上書きしていることが分かる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
248 ただし、変数aとbは書き込む位置も値も変わらないので触れられていない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
249 また、call命令を使わずにjmpでBに飛んでいる
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
250 (そのためリターンアドレスも確保してない)。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
251 これにより、B側ではret命令を発効するとAに戻らず、Aの呼び出し側に直接戻ることになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
252
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
253 \subsubsection{Tail call時のスタック}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
254 このときのスタックの様子を図\ref{fig:stack-tailcall}に表した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
255 \begin{figure}[htpb]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
256 \begin{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
257 \includegraphics[width=.45\textwidth,bb=0 0 528 272]{figures/stack-tailcall.pdf}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
258 \end{center}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
259 \caption{関数AからBを呼び出す時のスタックの様子}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
260 \label{fig:stack-tailcall}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
261 \end{figure}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
262 図\ref{fig:stack-tailcall}の各ステップは次のような状態を表している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
263 \begin{description}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
264 \item[(a)] mainからAが呼ばれた直後の状態。espは引数のトップをさしてるが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
265 ebpはmainの引数をさしたまま
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
266 \item[(b)] ebpをespに合わせる。通常はebpのオフセットから引数のアドレスを指定する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
267 \item[(c)] A自身のスタックフレームにB用の引数をつめる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
268 \item[(d)] ebpを元に戻す。その後関数Bにjump。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
269 \end{description}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
270 (a),(b)は関数Aの初期化処理、 (c),(d)は関数Bの呼び出し処理である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
271 通常は関数呼び出しの際はAのスタックフレームの上に新たに作るはずである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
272 しかし、関数AのTail call elimination後のコードを見ても分かる通り、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
273 無駄な処理が少なくなっていることが分かる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
274 これがTail call eliminationにおける最適化の主な効果である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
275 最大の効果が得られるのは、caller関数が持っている引数を
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
276 callee関数に直接渡す場合である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
277 この時はスタック操作は全く必要なく、単にjump命令のみになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
278
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
279 \subsection{Tail callの条件}\label{ssec:tailcallcond}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
280 Tail callが可能かどうかの条件についてここで考察する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
281
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
282 まず最初の条件として、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
283 ``関数コールがreturnの直前にある''ということは自明だろう。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
284 また、これに関連して``関数の返す型がcallerとcalleeで一致している''
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
285 ことが必要となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
286
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
287 図\ref{fig:stack-tailcall}の(c)にてcallee関数Bのための引数をスタックに上書きしているが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
288 この領域はAのためのスタックフレームであることは説明した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
289 ここでもしBの引数が5つ以上あったらどうなるだろうか?
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
290 図を見て分かる通り、mainのスタックまで書きつぶすことになってしまう。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
291 このことから``caller側の引数サイズがcallee側の引数サイズより大きいもしくは等しい''
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
292 という条件が必要だと分かる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
293
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
294 最後にcallee用の引数を格納する順番が問題になる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
295 通常、引数は関数定義の右から順にスタックにつめられる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
296 例えば図\ref{code:main A B}のコードにおいて、AからBの呼び出しが
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
297 \verb|B(c, b, c+d)|となっていたらどうだろうか?
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
298 最初に\verb|c+d|の書き込みによって変数cは上書きされてしまう。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
299 そのため、最後に書き込む引数cは上書きされたc+dが使われ、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
300 実行結果はまったく違うものになってしまうだろう。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
301 よって、``書き込んだ引数が、その後書き込む引数を上書きしてはならない''
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
302 という条件も必要となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
303
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
304 他にも細かな条件はあるが、以上の考察より以下の4つの条件が明らかになった。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
305 \begin{enumerate}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
306 \item 関数コールがreturnの直前にある \label{i}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
307 \item 関数の返す型がcallerとcalleeで一致している \label{ii}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
308 \item caller側の引数サイズがcallee側の引数サイズより大きいもしくは等しい \label{iii}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
309 \item 書き込んだ引数が、その後書き込む引数を上書きしてはならない \label{iv}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
310 \end{enumerate}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
311
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
312 CbCコンパイル機能の実装の際にはこれらの条件をパスさせる必要がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
313
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
314
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
315
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
316 \section{実装}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
317 次に、実際の実装方法を簡単に説明する。
2
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
318 今回実装したソースコードはSourceForge上の以下のURLにて公開されている。\\
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
319 \url{http://sourceforge.jp/projects/cbc/}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
320
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
321 実装に置ける最大の問題はgoto文でのコードセグメントへのjump
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
322 の際にスタックフレームをどう扱うかということである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
323 \ref{sec:CbC}章にて説明した通り、CbCではコードセグメントへジャンプした後は
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
324 元のコードセグメントには戻らない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
325 ゆえに通常の関数コールと違い、スッタクを積む必要が無い。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
326 この特性が\ref{ssec:tailcall}で説明したTail callの性質と似ていることを利用し、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
327 ``コードセグメントへのgotoはすべてTail callに置き換える''という実装を行う。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
328
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
329
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
330 \subsection{Tail call条件のパス}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
331 上記のような実装を行う上で、\ref{ssec:tailcallcond}で説明したように、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
332 Tail callの条件を満足させる必要がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
333
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
334 条件の\ref{i}は簡単に実装できる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
335 例えば次のような継続文を考える。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
336 \begin{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
337 goto cs(10, "test");
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
338 \end{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
339 この文を構文解析する際に次のような形に置き換えることになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
340 \begin{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
341 cs(10, "test");
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
342 return;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
343 \end{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
344 これによりGeneric Treeの段階では単純な関数呼び出しとなるが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
345 Tail callのフラグをたてることにより、RTL生成時には
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
346 jump命令に置き換えられる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
347
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
348 次に条件の\ref{ii}だが、これは``\_\_code''を型に持つものは
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
349 すべてvoid型に置き換えることで対応できる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
350 すなわちコードセグメントの継続はvoid型関数へのTail callとなる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
351
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
352 条件\ref{iii}が最大の問題となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
353 もしより大きい引数サイズのコードセグメントにTail callすると、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
354 直前の呼び出した関数スタックを書きつぶしてしまう。最悪Segmentation faultとなる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
355 今回はこの解決方法として、すべてのコードセグメントでは引数スタックを
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
356 一定量とした。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
357 ゆえにこのサイズ以上の引数を持つことはできないが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
358 これは通常のプログラミングでは問題にならない程度に大きい値にしている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
359 また、継続の際にはスタック拡張を行わないので、この一定量が大きくなっても
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
360 とくに実行速度等に影響はない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
361
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
362 最後に条件\ref{iv}だが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
363 これは上書きされうる引数がある場合には直前にそれを計算し一時変数に代入するように
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
364 修正した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
365
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
366 以上の内容に基づいて修正したソースコードの大半は
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
367 RTLを生成部となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
368
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
369
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
370 \begin{comment}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
371 GCCへのCbCのコンパイル機能の実装を行う。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
372 実装における最大の問題はgoto文でのコードセグメントへのjump
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
373 の際のスタックフレームの状態をどう扱うかである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
374 先に述べたようにコードセグメントへ飛ぶ時は Tail call を使用するのだが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
375 その条件としてcaller関数の引数サイズはcallee関数と同じか
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
376 より大きくなければならない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
377
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
378 これを解決するために、この実装ではコードセグメントの
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
379 引数サイズを一定にすることにした。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
380 どのようなコードセグメントを定義してもスタックは一定に保たれる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
381
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
382 以下の節ではそれぞれの行程について簡単に説明する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
383
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
384 \subsection{\_\_code基本型の追加とパース}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
385 まず最初に必要となるのが``\_\_code''という予約語を定義することである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
386 Cの予約語は全て gcc/c-parser.c にて\verb|reswords|配列に定義されており、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
387 ここに``\_\_code''を定義することで、Tokenizerから
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
388 それを予約語として認識できるようになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
389
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
390 もう一つ必要なものが、\_\_code型であることを示すidである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
391 これはGCCが関数や変数の宣言を表すtreeを生成するまでの間に
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
392 データを保持する \verb|c_declapecs|構造体で使用される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
393 void型なら\verb|cts_void|, int型なら\verb|cts_int|などで表されている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
394 これは gcc/c-tree.h にて定義されており、ここに\verb|cts_CbC_code|を追加する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
395
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
396 以上により、\_\_codeをパースする準備ができた。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
397 実際にはパース段階では関数の場合や変数の場合などで違う手続きが踏まれるが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
398 \verb|c_declspecs|構造体に\verb|cts_CbC_code|を格納する手続きは
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
399 \verb|declspecs_add_type()|関数に統一されている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
400 この関数の巨大なswitch文に対して\verb|case RID_CbC_CODE|を追加すれば良い。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
401 以下のようになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
402 \begin{lstlisting}[caption=declspecs\_add\_type関数,label=code:declspecs_add_type]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
403 case RID_CbC_CODE:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
404 if (specs->long_p)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
405 error ("both %<long%> and %<void ..)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
406 else if (specs->signed_p)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
407 error ("both %<signed%> and %<vo ..)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
408 :
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
409 else
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
410 specs->typespec_word = cts_CbC_code;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
411 return specs;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
412 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
413 これは実際には\verb|case RID_VOID|とほぼ同じである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
414 違うのは\verb|specs->typespec_word = cts_CbC_code|のみとなる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
415 同様にコードセグメントの型はほぼ、void型と同じように扱うことになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
416
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
417 gcc/c\_decl.cにある\verb|finish_declspecs|関数は\verb|c_declspecs|をもとに、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
418 パースされた型を決定し、その分のちいさなtreeを生成する関数である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
419 treeにする際はコードセグメントは全てvoidと見なされるようにすることになっている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
420 よってここで生成するtreeはvoidにしなければならない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
421 \begin{lstlisting}[caption=finish\_declspecs関数,label=code:finish_declspecs]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
422 case cts_void:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
423 case cts_CbC_code:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
424 specs->type = void_type_node;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
425 break;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
426 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
427 これで\_\_codeによる型がvoid型にマップされた。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
428
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
429
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
430 \subsection{コードセグメント のtree表現}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
431 次に、関数と同じようにパースされるコードセグメントのtreeを
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
432 後の処理で識別するため、FUNCTION\_TYPE treeにフラグをつける必要がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
433 この特殊なFUNCTION\_TYPEを生成する関数を gcc/tree.c に作っておく。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
434 具体的には以下の様な関数になる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
435 \begin{lstlisting}[caption=build\_code\_segment\_type関数,label=code:build_code_segment]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
436 tree
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
437 build_code_segment_type(value_type ..)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
438 {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
439 tree t;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
440 t = make_node (FUNCTION_TYPE);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
441 TREE_TYPE (t) = value_type;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
442 TYPE_ARG_TYPES (t) = arg_types;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
443
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
444 CbC_IS_CODE_SEGMENT (t) = 1;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
445 if (!COMPLETE_TYPE_P (t))
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
446 layout_type (t);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
447 return t;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
448 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
449 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
450 \verb|CbC_IS_CODE_SEGMENT|というマクロがコードセグメントを示すフラグである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
451 この関数は通常のFUNCTION\_TYPEを作る \verb|build_function_type|と
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
452 ほぼ同じ構造になっているが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
453 このtreeをハッシュ表に登録しないところだけが違っている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
454
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
455 つづいてこの\verb|build_code_segment_type|を使用すべき関数、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
456 \verb|grokdeclarator|を修正する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
457 この関数は今までパースしてきた情報の入った構造体、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
458 \verb|c_declspecs|と\verb|c_declarator|をもとに、その変数や関数を表すtreeを
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
459 gcc/tree.c の関数を使って生成している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
460
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
461 この関数で\verb|build_function_type|関数を使用している箇所
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
462 3番目の(巨大な)switch文の\verb|case cdk_function:|の部分である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
463 これを、コードセグメントの場合には\verb|build_code_segment_type|を使うようにする。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
464 \begin{lstlisting}[caption=grokdeclarator関数,label=code:grokdeclarator]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
465 if(typespec_word==cts_CbC_code)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
466 type =build_code_segment_type(..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
467 else
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
468 type =build_function_type(..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
469 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
470 これで、\_\_code型がパースされた時にはFUNCITON\_TYPEにフラグが付くようになった。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
471 コードセグメントかをチェックする時はtree typeに対して
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
472 \verb|CbC_IS_CODE_SEGMENT (type)|として真偽値が返される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
473
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
474
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
475 \subsection{goto のパース}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
476 つづいてgoto文のパースが必要になる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
477 goto文は通常のCの構文にも存在するが、CbCではgotoトークンの後に
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
478 関数呼び出しと同じ構文がくる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
479
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
480 Cの関数定義をパースしているのは
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
481 \verb|c_parser_statement_after_labels|という関数である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
482 この関数内の巨大な switch文における\verb|case RID_GOTO:|
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
483 を修正することになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
484 具体的な修正は以下のようになった。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
485 \begin{lstlisting}[caption=goto文の構文解析,label=code:goto_parse]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
486 c_parser_consume_token (parser);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
487 if (c_parser_next_token_is(parser,..)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
488 && _parser_peek_2nd_token(pars..))
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
489 {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
490 stmt = c_finish_goto_label(..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
491 c_parser_consume_token (parser);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
492 } else {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
493 struct c_expr expr;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
494 expr=c_parser_postfix_expression(..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
495 if(TREE_CODE(expr)==CALL_EXPR){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
496 CbC_IS_CbC_GOTO(expr) = 1;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
497 CALL_EXPR_TAILCALL(expr) = 1;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
498 stmt = c_finish_return(expr);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
499 } else
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
500 c_parser_error (parser, ..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
501 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
502 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
503 gotoトークンを読み込むと、次のトークンが識別子で、その次がセミコロンであれば
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
504 通常のCにおけるgotoと判定できる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
505 そうでなければCbCの継続である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
506
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
507 \subsection{expand\_callの分割}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
508 ここではパーサによって生成されたtreeを元に、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
509 RTLを生成する段階について説明する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
510
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
511 とはいうものの、実際にRTLをいじる必要があるのは
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
512 コードセグメントへのjumpのみである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
513 これはtree上ではTail callと認識されているので、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
514 そのtreeからRTLに変換する関数\verb|expand_call|を修正することになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
515
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
516 関数\verb|expand_call|は CALL\_EXPR treeをもとに
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
517 関数呼び出しの際のスタック領域確保、引数の格納、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
518 関数へのcall命令の発行などを行うRTLを生成している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
519 しかしこの\verb|expand_call|は約1200行も存在し、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
520 その大半はTail callが可能かの判定をしているにすぎない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
521 そこでこの実装ではCbCのgotoのためのRTLを生成する関数\verb|expand_cbc_goto|
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
522 を新たに作成した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
523
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
524 \subsection{expand\_cbc\_goto}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
525 簡単に説明すると、\verb|expand_cbc_goto|は\verb|expand_call|での
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
526 Tail callの処理を可否判定無しで行うものとなる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
527 大まかな処理内容は以下の通り
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
528 \begin{enumerate}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
529 \item スタックフレームのベースアドレスRTLを取得
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
530 \item 各引数の格納されるアドレスRTLを取得
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
531 \item 各引数の式を計算 (一時的にレジスタに格納)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
532 \item オーバーラップする引数を一時に変数に格納\label{overlap}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
533 \item 引数のスタックへの格納
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
534 \item call\_insn RTLの生成
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
535 \end{enumerate}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
536
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
537 これらの処理はほぼ\verb|expand_call|の内容をそのまま利用できる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
538 ただし、\ref{overlap}のオーバーラップする引数がある場合のみ問題になる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
539 gotoの実装には\ref{sec:tailcall}節で説明したTail callを用いているため
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
540 引数の書き込み領域と読み込み領域が重なる場合がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
541 本来この場合はTail call不能として通常の関数呼出が用いられるところであるが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
542 CbCではこれを強制しなければならない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
543 そのため、このように重なる場合は変数の内容を一時退避する必要がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
544 次のリスト\ref{code:push_overlaps}がこの処理を書く引数に対して行っている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
545 \begin{lstlisting}[caption=push\_overlaps関数,label=code:push_overlaps]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
546 push_overlaps(struct arg_data *args, int num_actuals){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
547 int i;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
548 for (i=0; i<num_actuals; i++)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
549 {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
550 int dst_offset;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
551 int src_offset;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
552 rtx temp;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
553 if (/*args[i].stackはスタック外*/) continue;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
554 if (/*args[i].valueはスタック外*/) continue;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
555 temp =assign_temp(args[i].tree_value..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
556 if ( args[i].mode==BLKmode )
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
557 emit_block_move(temp,args[i].value..);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
558 else
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
559 emit_move_insn(temp,args[i].value);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
560 args[i].value = temp;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
561 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
562 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
563
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
564 \end{comment}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
565
2
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
566 \section{環境付き継続に関する考察}\label{sec:env}
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
567 また前説までにその実装方法を説明した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
568 しかしまだ実装されていない構文があるので、その実装方法に関して
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
569 ここで考察する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
570
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
571 \subsection{環境付き継続の概念}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
572 環境付き継続は以下に示すように、継続文の後ろに``環境''の値を
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
573 明示したものである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
574 \begin{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
575 goto cs(10, 20), env;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
576 \end{verbatim}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
577 この構文を使用することでスタックフレームを別の(環境envが示す)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
578 領域に切り替えたうえで継続を行うことができる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
579 例としてリスト\ref{code:envSwitch}の様なコードセグメントが考えられる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
580 \begin{lstlisting}[caption=環境付き継続 例,label=code:envSwitch]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
581 __code envSwitch(int a, int b, double c)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
582 {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
583 void *stack;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
584 if ((stack=malloc(STACKSIZE))==NULL)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
585 goto error(no);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
586
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
587 goto envCheck(10, 20), stack+OFFSET;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
588 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
589 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
590 このコードセグメントenvSwitchではスタック領域をmallocで取得した領域に切り替えた
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
591 上でenvCheckに継続する
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
592 \footnote{この構文を使用し、複数のスタックを交互に切り替える等の
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
593 処理を行うことでタブロー法などの検証を行うのがCbCの目的でもある。}。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
594
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
595 また、この構文を使ってコードセグメントを呼び出した関数に戻ることも可能となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
596 それにはこの関数側でも若干の修正が必要で、\verb|__return, __environment|
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
597 という二つの定義済み変数を使用する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
598 これらはそれぞれコードセグメントから関数への戻り先とその時のスタックフレームの
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
599 位置を表している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
600 これらをリスト\ref{code:ret2func}の様に用いることで
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
601 \verb|env_func|を呼び出した関数まで戻ることができる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
602 また、\verb|env_code|環境付きgotoで与えている引数は\verb|env_func|の戻り値と
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
603 して扱われる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
604 \begin{lstlisting}[caption=呼び出し元の関数へのgoto例,label=code:ret2func]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
605 __code env_code(int a, int b,
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
606 void *env, void *_ret)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
607 {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
608 __code (*ret)(int, int, int);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
609 ret = _ret;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
610 goto ret(20), env;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
611 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
612 int env_func(int a, int b, double c)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
613 {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
614 goto env_code(20, 30,
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
615 __environment, __return);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
616 /* unreachable */
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
617 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
618 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
619
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
620
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
621 \subsection{実装方法に関する考察}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
622 環境付き継続の実装方法について考察を行う。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
623 環境付き継続では通常の関数コールや継続と違い、スタックフレームを変更するため、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
624 現在のスタックフレームの位置をさすレジスタを変更しなければならない。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
625 理想的なリスト\ref{code:envSwitch}のコンパイル結果は以下のようになる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
626 \begin{lstlisting}[caption=環境付き継続 出力例,label=code:envSwitch_out]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
627 movl $env, $eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
628 movl $10, 8(%eax)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
629 movl $20, 12(%eax)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
630 movl %eax, %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
631 jmp envCheck
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
632 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
633 この結果なら新たなスタックフレームenvの先に引数を格納し、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
634 かつ\verb|%ebp|レジスタを置き換えた上でコードセグメントに継続している。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
635
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
636 しかし、現在のTail callを用いた仕様ではいくつかの問題点がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
637 一つは``Tail callはjmp命令の直前に必ず\verb|%ebp|を変更する''ということである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
638 さらに``環境''の値から引数を格納する位置までのオフセットを計算する必要がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
639 これはGCCではRTLとして\verb|virtual_incoming_args_rtx|や\verb|hard_frame_pointer_rtx|
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
640 などの固定レジスタ値が用意されてるので、これを用いて計算できるだろう。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
641 最後に、関数の呼び出し側に戻る時の\verb|__return|変数の定義が必要となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
642 この変数はただ値をつくるだけでなく、この変数が使われている場合には
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
643 特殊なコードを生成する必要がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
644
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
645
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
646
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
647 \section{評価}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
648 今回、環境付き継続は実装には至らなかったが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
649 残りの部分は実装完了した。そこでベンチマークテストを行い、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
650 Micro-Cとの比較を行った。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
651
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
652 今回ベンチマークに使用したプログラムはこれまでもMicro-Cの測定に使われていた
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
653 テストルーチンで、普通のCのソースをプログラムでCbCに変換したものである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
654 引数に1を入れるとそれが変換されたCbCのコード、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
655 引数2,3では変換されたコードを手動でMicro-C用に最適化したコードが実行される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
656 また、評価はia32アーキテクチャのFedora上で行った。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
657 一番結果の良い引数2の場合のコードセグメントをリスト\ref{code:bench}に示す。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
658 \begin{lstlisting}[caption=bench,label=code:bench]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
659 __code f2(int i,char *sp) {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
660 int k,j;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
661 k = 3+i;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
662 goto g2(i,k,i+3,sp);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
663 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
664 __code g2(int i,int k,int j,char *sp){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
665 j = j+4;
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
666 goto h2(i,k+4+j,sp);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
667 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
668 __code h2_1(int i,int k,int j,char *sp){
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
669 goto main_return2(i+j,sp);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
670 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
671 __code h2(int i,int k,char *sp) {
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
672 goto h2_1(i,k,i+4,sp);
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
673 }
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
674 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
675 このベンチマークではCbCの継続と計算を交互に行っている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
676 測定結果は表\ref{tab:mc,gcc,compare}に示される。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
677 \begin{table}[htpb]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
678 \centering
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
679 \small
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
680 \begin{tabular}{|l|r|r|r|} \hline
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
681 & ./conv1 1 & ./conv1 2 & ./conv1 3 \\ \hline
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
682 Micro-C & 8.97 & 2.19 & 2.73 \\ \hline \hline
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
683 GCC & 4.87 & 3.08 & 3.65 \\ \hline
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
684 GCC (+omit) & 4.20 & 2.25 & 2.76 \\ \hline
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
685 GCC (+fast) & 3.44 & 1.76 & 2.34 \\ \hline \hline
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
686 \end{tabular}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
687 \caption{Micro-C, GCCの実行速度比較 (単位 秒)}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
688 \label{tab:mc,gcc,compare}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
689 \end{table}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
690
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
691 通常のTail call eliminationのみを有効にした場合の結果が2行目、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
692 その他は次節で説明するオプションを付加したものである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
693 見てのとおり、手動で最適化された引数2,3の場合はオプションを加えなければ
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
694 Micro-Cの速度に及ばなかった。次節ではこの点について考察する。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
695
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
696 \subsection{出力コード}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
697 先ほどのリスト\ref{code:bench}のコードセグメント g2のみをMicro-Cでコンパイルした結果
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
698 をリスト\ref{code:bench_mc},
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
699 GCCのオプション無しによるコンパイル結果をリスト\ref{code:bench_gcc}に示す。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
700 \begin{lstlisting}[caption=Micro-Cによる出力コード,label=code:bench_mc]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
701 f2:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
702 lea -_44(%ebp),%esp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
703 movl $3,%eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
704 addl %esi,%eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
705 movl %eax,-28(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
706 movl %edi,-32(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
707 movl -28(%ebp),%edi
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
708 movl %esi,%eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
709 addl $3,%eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
710 movl %eax,-28(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
711 jmp g2
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
712 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
713 \begin{lstlisting}[caption=GCCによる出力コード,label=code:bench_gcc]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
714 f2:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
715 pushl %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
716 movl %esp, %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
717 movl 8(%ebp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
718 movl 12(%ebp), %ecx
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
719 leal 3(%eax), %edx
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
720 movl %edx, 12(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
721 movl %edx, 16(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
722 movl %ecx, 20(%ebp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
723 popl %ebp
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
724 jmp g2
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
725 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
726 このとおり出力コードは10命令と、行数にはあまり差が無い。(他のsegmentも同様である)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
727 しかしGCCの出力においては無駄なコードが混じっていることがわかるだろう。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
728 \verb|pushl%ebp|と\verb|popl %ebp|である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
729 すべてのコードセグメントにおいてこれと同じ命令が出てしまっているが、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
730 これはTailcallを無理矢理適用したために出てきたコードである。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
731
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
732 このような関数の最初と最後にある無駄なフレームポインタのpushを抑制するオプションが
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
733 -fomit-frame-pointerである。このオプションを付加するとリスト\ref{code:bench_gcc_omit}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
734 \begin{lstlisting}[caption=GCCによる出力コード,label=code:bench_gcc_omit]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
735 f2:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
736 movl 4(%esp), %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
737 movl 8(%esp), %ecx
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
738 leal 3(%eax), %edx
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
739 movl %edx, 8(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
740 movl %edx, 12(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
741 movl %ecx, 16(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
742 jmp g2
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
743 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
744 これによって一気に3命令減った。ベンチマークは表\ref{tab:mc,gcc,compare}の3行目、``GCC (+omit)''である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
745 しかし、(コードセグメントにもよるが)3/10命令減ったにもかかわらずMicro-Cとの速度差が
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
746 ほとんど無い。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
747
3
e35e566b9983 *** empty log message ***
kent
parents: 2
diff changeset
748 リスト\ref{code:bench_mc}をみるとMicro-Cでは引数の格納にレジスタ\%edi と
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
749 \%esi を用いる分、高速なコードを生成出来ていることが分かる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
750 この違いが命令数の差を埋めている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
751 GCCでも引数をレジスタに詰めることができるfastcall属性がある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
752 -fomit-frame-pointerに加えてfastcallを付加した結果をリスト\ref{code:bench_gcc_fast}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
753 に示す。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
754 \begin{lstlisting}[caption=GCCによる出力コード,label=code:bench_gcc_fast]
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
755 f2:
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
756 movl %edx, %eax
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
757 leal 3(%ecx), %edx
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
758 movl %edx, 4(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
759 movl %eax, 8(%esp)
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
760 jmp g2
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
761 \end{lstlisting}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
762 命令数はさらに2命令減り、またメモリへのアクセスが減ったため
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
763 ベンチマーク結果(表\ref{tab:mc,gcc,compare}GCC (+fast))も大幅に改善した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
764
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
765 この評価結果から、GCCの最適化オプションを用いることで
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
766 CbCコードのさらなる高速化が可能であることが示された。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
767 また、使用したベンチマークプログラムはCのコードをプログラムで
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
768 CbCに変換したものだが、これをCのままコンパイルすると
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
769 最適化をかけても約3.3秒かかる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
770 このように不要なスタック操作を減らすことによって、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
771 C言語のみでは不可能な手動による最適化がCbCの利点としてあげられる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
772
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
773
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
774
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
775
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
776
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
777 \section{まとめ}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
778 本研究の実装により、GCCを使ってCbCのソースコードを
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
779 コンパイルすることができるようになった。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
780 その結果、これまでのMicro-Cベースのコンパイラではできなかった
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
781 最適化をGCC上で実行できるようになり、CbCプログラムをより高速化することに成功した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
782 また、環境付き継続の実装方法に関して考察を行いその問題点を洗い出した。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
783
2
b61e7bfa07c4 *** empty log message ***
kent
parents: 0
diff changeset
784 今後は\ref{sec:env}で説明した様に環境付き継続の
0
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
785 実装が課題となる。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
786 また、SPUアーキテクチャにGCCが対応してないという問題もある。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
787 今回の実装の目的の一つとしてPS3上でCbCを動かしたいということがあったので、
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
788 この問題についてはPS3SDKとのマージも一つの手法として考えている。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
789 これらに加えて、GCCはすでにC++やObjective-C のコンパイルが可能である。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
790 これを活かし、CbC++, もしくはObjective-CbC といった
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
791 既存の言語とCbC を組み合わせた言語に付いても今後実装していく。
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
792
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
793
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
794 \begin{thebibliography}{9}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
795 \bibitem{kono1} 河野真治. ``継続を基本とした言語CbCのgcc上の実装''.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
796 日本ソフトウェア科学会第19回大会論文集, Sep, 2002.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
797 \bibitem{kono2} 河野真治. ``継続を持つCの下位言語によるシステム記述''.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
798 日本ソフトウェア科学会第17回大会論文集, Sep, 2000.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
799 \bibitem{c--} Simon Peyton Jones, Thomas Nordin, and Dino Oliva, ``C--: a portable assembly language''. Implementing Functional Languages, 1997.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
800 \bibitem{gcc1} GNU Project - Free Software Foundation, GCC internal manual.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
801 \url{http://gcc.gnu.org/onlinedocs/gccint/}.
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
802 \end{thebibliography}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
803
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
804 \end{document}
f2fa5b673868 *** empty log message ***
kent
parents:
diff changeset
805