annotate main.tex @ 5:7fdca589238f

*** empty log message ***
author kent
date Tue, 25 Mar 2008 23:16:29 +0900
parents 2c619ec34ae4
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
1 % File: main.tex
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
2 % Created: 日 3 23 18:00 PM 2008 J
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
3 % Last Change: 火 3 25 02:40 PM 2008 J
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
4 %
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
5 \documentclass[a4j,twocolumn,9pt]{jarticle}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
6 \usepackage{main}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
7 \usepackage{graphicx}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
8 \usepackage{verbatim}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
9 \usepackage{nonDefaultPackage/listings}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
10
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
11
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
12 \jtitle{Continuation based CコンパイラのGCC-4.2による実装}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
13 \etitle{The implementation of Continuation based C Compiler on GCC}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
14 \jaffiliation{琉球大学理工学研究科情報工学専攻}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
15 \eaffiliation{Information Engineering, University Of the Ryukyus}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
16 \jauthor{与儀 健人 \hspace{2cm} 河野 真治}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
17 \eauthor{KENT yogi \hspace{2cm} Shinji KONO}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
18 \year{平成19年度}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
19 \thesis{OS研究会}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
20 %\logo{%\includegraphics[width=15em]{figures/u-ryukyu-Mark.eps}}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
21
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
22 \jabstract{
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
23 当研究室ではContinuation based Cという言語を提案しており、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
24 そのコンパイルにはこれまでMicro-Cをベースにした独自のコンパイラを使用していた。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
25 また、GCCのTail call optimizationを用いた実装が可能である事を以前の論文で示した。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
26 ここではGCC上に実際にCbC言語の実装し、その評価を行った。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
27 この実装はアーキテクチャに依存しないので、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
28 GCCが対応する全てのアーキテクチャ上でCbCが動く事になるはずであるが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
29 若干の問題があり、その点に付いても考察を行う。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
30 }
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
31 \eabstract{
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
32 We are approach Continuation based C Language,
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
33 and have used Micro-C based Compiler that is developed by us to compile it.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
34 This research, We are implement a compiler for CbC into GCC and
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
35 appraising it.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
36 This implementation is supposed
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
37 to run on all archtectures that is supported by GCC,
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
38 but few problems are founded.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
39 }
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
40
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
41
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
42 \renewcommand{\lstlistingname}{リスト}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
43 \lstset{
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
44 language=C,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
45 stringstyle=\ttfamily,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
46 basicstyle=\small\ttfamily,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
47 commentstyle=\itshape,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
48 classoffset=1,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
49 keywordstyle=\bfseries,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
50 framesep=5pt,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
51 showstringspaces=false,%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
52 %frame=tRBl,
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
53 %numbers=left,stepnumber=1,numberstyle=\footnotesize%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
54 }%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
55 \def\lstlistingname{リスト}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
56 \def\lstlistlistingname{プログラムコード目次}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
57
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
58
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
59
3
220f89415656 complete
kent
parents: 2
diff changeset
60 \renewcommand{\thepage}{--- \arabic{page} ---}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
61 \begin{document}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
62 \twocolumn[\maketitle]{}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
63
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
64 \section{CbCについて}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
65 Continuation based C (以下CbC) は当研究室が提案するアセンブラよりも上位で
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
66 Cよりも下位な記述言語である\cite{kono2}。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
67 Cの仕様からループ制御や関数コールを取り除き、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
68 継続(goto) や code segmentを導入している。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
69 これによりスタックの操作やループ、関数呼び出しなどのより低レベルでの最適化を、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
70 ソースコードレベルで行うことができる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
71
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
72 図\ref{fig:continuation}はcode segment同士の関係を表したものである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
73 \begin{figure}[htpb]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
74 \begin{center}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
75 \includegraphics[width=.5\textwidth]{figures/continuation.eps}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
76 \end{center}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
77 \caption{code segment間の``継続''}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
78 \label{fig:continuation}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
79 \end{figure}%
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
80 code segment\verb|start|は実行を終えるとgotoによって
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
81 別のcode segment \verb|A|もしくは\verb|B|に実行を継続する。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
82 また、\verb|A|から\verb|B|,再び\verb|A|の用に継続を繰り返すことも可能だ。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
83 このように、code segmentからgotoを用いて別のcode segmentへ飛ぶ
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
84 構成はオートマトンと似た構造になっていることがわかる。
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
85
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
86 これらの特徴から、CbCは自身でスケジューラの記述ができ、
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
87 それにより並列処理や逐次処理をスムースに繋げることが出来る。
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
88 また、OperatingSystemの記述やハードウェアの記述が容易になる。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
89
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
90 以下では実装に必要なCbCの構文、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
91 code segmentの定義と継続(goto)について説明する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
92 \paragraph{code segment}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
93 はCbCにおける最も基本的な処理単位である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
94 構文としては通常の関数と同じであるが、型は``\_\_code''となる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
95 ただし、code segmentは関数のようにリターンすることはないので、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
96 これはcode segmentであることを示すフラグの様なものである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
97
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
98 code segmentの処理内容も通常の関数と同じように定義されるが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
99 Cと違いcode segmentではforやwhile, returnなどの構文は存在しない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
100 ループ等の制御は自分自身への再帰的な継続によって実現されることになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
101
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
102 \paragraph{継続 (goto)}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
103 はcode segment間の移動を表す。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
104 構文としてはgotoをつかっているがCにおけるlabelへのgotoとは違い、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
105 gotoの後ろに関数呼び出しの様な形をとる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
106 例として、あるcode segment \verb|cs|への継続は
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
107 \verb|goto cs(10, "test");|となる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
108 これにより、csに対して引数\verb|10|と\verb|"test"|を渡すことができる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
109 ただし関数コールとは違い、継続ではコールスタックの拡張を行わない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
110 代わりにgotoを発行したcode segmentの持つスタック自体に次のcode segment
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
111 の引数を書き込むことになる。また、returnアドレスのpushなども行わない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
112
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
113
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
114 \section{GCCの構成}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
115 \subsection{GCCの基本構造}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
116 GCCはpassと呼ばれる一連の処理の中でソースコードをアセンブリに変換する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
117 以下ではそのpassの中でも重要なものをその実行順に説明する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
118 \begin{description}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
119 \item[parsing] パーサによってソースコードを解析する。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
120 解析した結果はGeneric Treeと呼ばれるtree構造の構造体に格納される。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
121 \item[gimplification] Generic TreeをもとにこれをGIMPLEに変換する。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
122 \item[GIMPLE optimization] GIMPLEに対して最適化を行う。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
123 \item[RTL generation] GIMPLEをもとにRTLを生成する。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
124 \item[RTL optimization] RTLに対して最適化を行う。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
125 \item[Output assembly] RTLをもとにターゲットマシンのアセンブリに変換する。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
126 \end{description}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
127 これらの処理は図\ref{fig:GCC-pass}のように表される。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
128 \begin{figure}[htbp]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
129 \begin{center}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
130 \includegraphics[width=.5\textwidth]{figures/GCC-pass.eps}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
131 \end{center}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
132 \caption{GCCのpass}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
133 \label{fig:GCC-pass}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
134 \end{figure}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
135 各passは通常は各々の関数毎に行われるものだが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
136 inline関数の処理や、関数間での最適化を行う場合には
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
137 一つのソースファイル毎に行われる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
138
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
139 \subsection{Tail call elimination}\label{sec:tailcall}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
140 最適化のひとつである``Tail call elimination''は、
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
141 本研究におけるCbCコンパイラの実装に深く関わってくる。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
142 本節ではこの最適化機構について詳しく説明する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
143
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
144 \subsubsection{Tail callの概要}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
145 具体的に説明する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
146 まずmain関数から関数Aを呼び出していて、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
147 関数Aの最後の処理(return直前)では次に関数Bを呼び出している状況を考える。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
148 このあと関数Bの処理が終了すると、ret命令により一旦関数Aに戻ってきて、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
149 そこで再びret命令をつかってmainに戻ることになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
150 ``Tail call elimination''ではこのBからAに戻る無駄な処理を低減する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
151 この様子を図\ref{fig:Tail call}に示したので参考にしていただきたい。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
152 \begin{figure}[htpb]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
153 \begin{center}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
154 \includegraphics[width=0.5\textwidth]{figures/GCC-TailCall.eps}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
155 \end{center}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
156 \caption{Tail call eliminationの例}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
157 \label{fig:Tail call}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
158 \end{figure}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
159
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
160 次に``Tail call elimination''によって、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
161 アセンブリレベルでどのようにコードが変わるのか、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
162 スタックの変化も交えて見てみる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
163 この例では最も一般的に使われているi386形式のアセンブラを使用している。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
164
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
165 図\ref{fig:Tail call}と同じように呼び出される関数main, A, Bを
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
166 リスト\ref{code:main A B}の様に定義する。
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
167 \begin{lstlisting}[caption=関数main\, A\, Bの例,label=code:main A B]
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
168 void B(int A, int A, int C){
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
169 return ;
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
170 }
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
171 void A(int a, int b, int c, int d){
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
172 return B(a, b, c+d);
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
173 }
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
174 int main(int argc, char **argv){
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
175 A(10, 20, 30, 40);
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
176 return 0;
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
177 }
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
178 \end{lstlisting}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
179 これを通常通り、``Tail call elimination''を使用せずにコンパイルすると
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
180 次のリスト\ref{code:compiled A}のようなコードが出力される。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
181 (ここではTailcall最適化が影響をあたえる関数Aのみをしめした)
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
182 \begin{lstlisting}[language=,caption=関数Aのコンパイル結果(Tail callなし),label=code:compiled A]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
183 A:
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
184 pushl %ebp
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
185 movl %esp, %ebp
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
186 subl $24, %esp
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
187 movl 20(%ebp), %eax
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
188 addl 16(%ebp), %eax
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
189 movl %eax, 8(%esp)
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
190 movl 12(%ebp), %eax
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
191 movl %eax, 4(%esp)
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
192 movl 8(%ebp), %eax
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
193 movl %eax, (%esp)
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
194 call B
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
195 leave
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
196 ret
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
197 .size A, .-A
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
198 \end{lstlisting}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
199 Tail callをしない場合はAのスタック領域の上にBのスタック領域が確保され、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
200 Bが終了するとそれが破棄される形になる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
201
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
202 次にTail call eliminationが行われた場合の
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
203 コンパイル結果をリスト\ref{code:tailcalled A}に示す。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
204 \begin{center}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
205 \begin{lstlisting}[caption=Tail call eliminationの行われた関数A, label=code:tailcalled A]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
206 A:
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
207 pushl %ebp
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
208 movl %esp, %ebp
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
209 movl 20(%ebp), %eax
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
210 addl %eax, 16(%ebp)
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
211 popl %ebp
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
212 jmp B
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
213 .size A, .-A
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
214 \end{lstlisting}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
215 \end{center}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
216 \verb|20(%ebp)|は変数d、\verb|16(%ebp)|は変数cを表している。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
217 ここではBのためにスタック領域は確保せず、かわりにAのスタック領域に
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
218 Bのための引数を書き込んでいることが分かる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
219 ただし、変数aとbは書き込む位置も値も変わらないので触れられていない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
220
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
221 \subsubsection{Tail call時のスタック}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
222 このときのスタックの様子を図\ref{fig:stack-tailcall}に表した。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
223 \begin{figure}[htpb]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
224 \begin{center}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
225 \includegraphics[width=.5\textwidth]{figures/stack-tailcall.eps}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
226 \end{center}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
227 \caption{関数AからBを呼び出す時のスタックの様子}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
228 \label{fig:stack-tailcall}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
229 \end{figure}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
230 図\ref{fig:stack-tailcall}の各ステップは次のような状態を表している。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
231 \begin{description}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
232 \item[(a)] mainからAが呼ばれた直後の状態。espは引数のトップをさしてるが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
233 ebpはmainの引数をさしたまま
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
234 \item[(b)] ebpをespに合わせる。通常はebpのオフセットから引数のアドレスを指定する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
235 \item[(c)] A自身のスタックフレームにB用の引数をつめる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
236 \item[(d)] ebpを元に戻す。その後関数Bにjump。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
237 \end{description}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
238 (a),(b)は関数Aの初期化処理、 (c),(d)は関数Bの呼び出し処理である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
239 通常は関数呼び出しの際はAのスタックフレームの上に新たに作るはずである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
240 しかし、関数AのTail call elimination後のコードを見ても分かる通り、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
241 無駄な処理が少なくなっていることが分かる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
242 これがTail call eliminationにおける最適化の主な効果である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
243 最大の効果が得られるのは、caller関数が持っている引数を
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
244 callee関数に直接渡す場合である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
245 この時はスタック操作は全く必要なく、単にjump命令のみになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
246
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
247 \subsection{Tail callの条件}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
248 Tail callが可能かどうかの条件についてここで考察する。
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
249 必要に応じて前節の図\ref{fig:stack-tailcall}と、リスト\ref{code:main A B}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
250 を説明に用いるので参考にしていただきたい。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
251
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
252 まず最初の条件として、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
253 ``関数コールがreturnの直前にある''ということは自明だろう。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
254 また、これに関連して``関数の返す型がcallerとcalleeで一致している''
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
255 ことが必要となる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
256
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
257 図の(c)にてcallee関数Bのための引数をスタックに上書きしているが、
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
258 この領域はAのためのスタックフレームであることは説明した。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
259 ここでもしBの引数が5つ以上あったらどうなるだろうか?
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
260 図を見て分かる通り、mainのスタックまで書きつぶすことになってしまう。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
261 このことから``caller側の引数サイズがcallee側の引数サイズより大きいもしくは等しい''
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
262 という条件が必要だと分かる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
263
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
264 最後にcallee用の引数を格納する順番が問題になる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
265 通常、引数は関数定義の右から順にスタックにつめられる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
266 例えば図\ref{code:main A B}のコードにおいて、AからBの呼び出しが
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
267 \verb|B(c, b, c+d)|となっていたらどうだろうか?
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
268 最初に\verb|c+d|の書き込みによって変数cは上書きされてしまう。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
269 そのため、最後に書き込む引数cは上書きされたc+dが使われ、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
270 実行結果はまったく違うものになってしまうだろう。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
271 よって、``書き込んだ引数が、その後書き込む引数を上書きしてはならない''
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
272 という条件も必要となる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
273
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
274 他にも細かな条件はあるが、以上の考察より以下の4つの条件が明らかになった。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
275 \begin{itemize}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
276 \item 関数コールがreturnの直前にある
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
277 \item 関数の返す型がcallerとcalleeで一致している
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
278 \item caller側の引数サイズがcallee側の引数サイズより大きいもしくは等しい
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
279 \item 書き込んだ引数が、その後書き込む引数を上書きしてはならない
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
280 \end{itemize}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
281
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
282 CbCコンパイル機能の実装の際にはこれらの条件をパスさせる必要がある。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
283
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
284
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
285
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
286 \section{実装}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
287 GCCへのCbCのコンパイル機能の実装を行う。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
288 実装における最大の問題はgoto文でのcode segmentへのjump
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
289 の際のスタックフレームの状態をどう扱うかである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
290 先に述べたようにcode segmentへ飛ぶ時は Tail call を使用するのだが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
291 その条件としてcaller関数の引数サイズはcallee関数と同じか
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
292 より大きくなければならない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
293
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
294 これを解決するために、この実装ではcode segmentの
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
295 引数サイズを一定にすることにした。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
296 どのようなcode segmentを定義してもスタックは一定に保たれる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
297
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
298 以下の節ではそれぞれの行程について簡単に説明する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
299
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
300 \subsection{\_\_code基本型の追加とパース}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
301 まず最初に必要となるのが``\_\_code''という予約語を定義することである。
3
220f89415656 complete
kent
parents: 2
diff changeset
302 Cの予約語は全て gcc/c-parser.c にて\verb|reswords|配列に定義されており、
220f89415656 complete
kent
parents: 2
diff changeset
303 ここに``\_\_code''を定義することで、Tokenizerから
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
304 それを予約語として認識できるようになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
305
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
306 もう一つ必要なものが、\_\_code型であることを示すidである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
307 これはGCCが関数や変数の宣言を表すtreeを生成するまでの間に
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
308 データを保持する \verb|c_declapecs|構造体で使用される。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
309 void型なら\verb|cts_void|, int型なら\verb|cts_int|などで表されている。
3
220f89415656 complete
kent
parents: 2
diff changeset
310 これは gcc/c-tree.h にて定義されており、ここに\verb|cts_CbC_code|を追加する。
220f89415656 complete
kent
parents: 2
diff changeset
311
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
312 以上により、\_\_codeをパースする準備ができた。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
313 実際にはパース段階では関数の場合や変数の場合などで違う手続きが踏まれるが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
314 \verb|c_declspecs|構造体に\verb|cts_CbC_code|を格納する手続きは
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
315 \verb|declspecs_add_type()|関数に統一されている。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
316 この関数の巨大なswitch文に対して\verb|case RID_CbC_CODE|を追加すれば良い。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
317 以下のようになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
318 \begin{lstlisting}[caption=declspecs\_add\_type関数,label=code:declspecs_add_type]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
319 case RID_CbC_CODE:
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
320 if (specs->long_p)
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
321 error ("both %<long%> and %<void ..)
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
322 else if (specs->signed_p)
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
323 error ("both %<signed%> and %<vo ..)
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
324 :
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
325 else
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
326 specs->typespec_word = cts_CbC_code;
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
327 return specs;
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
328 \end{lstlisting}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
329 これは実際には\verb|case RID_VOID|とほぼ同じである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
330 違うのは\verb|specs->typespec_word = cts_CbC_code|のみとなる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
331 同様にcode segmentの型はほぼ、void型と同じように扱うことになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
332
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
333 gcc/c\_decl.cにある\verb|finish_declspecs|関数は\verb|c_declspecs|をもとに、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
334 パースされた型を決定し、その分のちいさなtreeを生成する関数である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
335 treeにする際はcode segmentは全てvoidと見なされるようにすることになっている。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
336 よってここで生成するtreeはvoidにしなければならない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
337 \begin{lstlisting}[caption=finish\_declspecs関数,label=code:finish_declspecs]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
338 case cts_void:
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
339 case cts_CbC_code:
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
340 specs->type = void_type_node;
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
341 break;
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
342 \end{lstlisting}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
343 これで\_\_codeによる型がvoid型にマップされた。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
344
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
345
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
346 \subsection{code segment のtree表現}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
347 次に、関数と同じようにパースされるcode segmentのtreeを
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
348 後の処理で識別するため、FUNCTION\_TYPE treeにフラグをつける必要がある。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
349 この特殊なFUNCTION\_TYPEを生成する関数を gcc/tree.c に作っておく。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
350 具体的には以下の様な関数になる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
351 \begin{lstlisting}[caption=build\_code\_segment\_type関数,label=code:build_code_segment]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
352 tree
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
353 build_code_segment_type(value_type ..)
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
354 {
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
355 tree t;
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
356 t = make_node (FUNCTION_TYPE);
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
357 TREE_TYPE (t) = value_type;
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
358 TYPE_ARG_TYPES (t) = arg_types;
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
359
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
360 CbC_IS_CODE_SEGMENT (t) = 1;
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
361 if (!COMPLETE_TYPE_P (t))
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
362 layout_type (t);
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
363 return t;
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
364 }
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
365 \end{lstlisting}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
366 \verb|CbC_IS_CODE_SEGMENT|というマクロがcode segmentを示すフラグである。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
367 この関数は通常のFUNCTION\_TYPEを作る \verb|build_function_type|と
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
368 ほぼ同じ構造になっているが、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
369 このtreeをハッシュ表に登録しないところだけが違っている。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
370
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
371 つづいてこの\verb|build_code_segment_type|を使用すべき関数、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
372 \verb|grokdeclarator|を修正する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
373 この関数は今までパースしてきた情報の入った構造体、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
374 \verb|c_declspecs|と\verb|c_declarator|をもとに、その変数や関数を表すtreeを
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
375 gcc/tree.c の関数を使って生成している。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
376
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
377 この関数で\verb|build_function_type|関数を使用している箇所
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
378 3番目の(巨大な)switch文の\verb|case cdk_function:|の部分である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
379 これを、code segmentの場合には\verb|build_code_segment_type|を使うようにする。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
380 \begin{lstlisting}[caption=grokdeclarator関数,label=code:grokdeclarator]
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
381 if(typespec_word==cts_CbC_code)
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
382 type =build_code_segment_type(..);
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
383 else
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
384 type =build_function_type(..);
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
385 \end{lstlisting}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
386 これで、\_\_code型がパースされた時にはFUNCITON\_TYPEにフラグが付くようになった。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
387 code segmentかをチェックする時はtree typeに対して
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
388 \verb|CbC_IS_CODE_SEGMENT (type)|として真偽値が返される。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
389
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
390
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
391 \subsection{goto のパース}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
392 つづいてgoto文のパースが必要になる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
393 goto文は通常のCの構文にも存在するが、CbCではgotoトークンの後に
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
394 関数呼び出しと同じ構文がくる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
395
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
396 Cの関数定義をパースしているのは
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
397 \verb|c_parser_statement_after_labels|という関数である。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
398 この関数内の巨大な switch文における\verb|case RID_GOTO:|
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
399 を修正することになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
400 具体的な修正は以下のようになった。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
401 \begin{lstlisting}[caption=goto文の構文解析,label=code:goto_parse]
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
402 c_parser_consume_token (parser);
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
403 if (c_parser_next_token_is(parser,..)
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
404 && _parser_peek_2nd_token(pars..))
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
405 {
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
406 stmt = c_finish_goto_label(..);
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
407 c_parser_consume_token (parser);
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
408 } else {
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
409 struct c_expr expr;
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
410 expr=c_parser_postfix_expression(..);
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
411 if(TREE_CODE(expr)==CALL_EXPR){
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
412 CbC_IS_CbC_GOTO(expr) = 1;
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
413 CALL_EXPR_TAILCALL(expr) = 1;
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
414 stmt = c_finish_return(expr);
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
415 } else
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
416 c_parser_error (parser, ..);
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
417 }
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
418 \end{lstlisting}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
419 gotoトークンを読み込むと、次のトークンが識別子で、その次がセミコロンであれば
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
420 通常のCにおけるgotoと判定できる。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
421 そうでなければCbCの継続である。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
422
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
423 \subsection{expand\_callの分割}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
424 ここではパーサによって生成されたtreeを元に、
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
425 RTLを生成する段階について説明する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
426
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
427 とはいうものの、実際にRTLをいじる必要があるのは
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
428 code segmentへのjumpのみである。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
429 これはtree上ではTail callと認識されているので、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
430 そのtreeからRTLに変換する関数\verb|expand_call|を修正することになる。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
431
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
432 関数\verb|expand_call|は CALL\_EXPR treeをもとに
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
433 関数呼び出しの際のスタック領域確保、引数の格納、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
434 関数へのcall命令の発行などを行うRTLを生成している。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
435 しかしこの\verb|expand_call|は約1200行も存在し、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
436 その大半はTail callが可能かの判定をしているにすぎない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
437 そこでこの実装ではCbCのgotoのためのRTLを生成する関数\verb|expand_cbc_goto|
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
438 を新たに作成した。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
439
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
440 \subsection{expand\_cbc\_goto}
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
441 簡単に説明すると、\verb|expand_cbc_goto|は\verb|expand_call|での
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
442 Tail callの処理を可否判定無しで行うものとなる。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
443 大まかな処理内容は以下の通り
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
444 \begin{enumerate}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
445 \item スタックフレームのベースアドレスRTLを取得
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
446 \item 各引数の格納されるアドレスRTLを取得
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
447 \item 各引数の式を計算 (一時的にレジスタに格納)
3
220f89415656 complete
kent
parents: 2
diff changeset
448 \item オーバーラップする引数を一時に変数に格納\label{overlap}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
449 \item 引数のスタックへの格納
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
450 \item call\_insn RTLの生成
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
451 \end{enumerate}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
452
3
220f89415656 complete
kent
parents: 2
diff changeset
453 これらの処理はほぼ\verb|expand_call|の内容をそのまま利用できる。
220f89415656 complete
kent
parents: 2
diff changeset
454 ただし、\ref{overlap}のオーバーラップする引数がある場合のみ問題になる。
220f89415656 complete
kent
parents: 2
diff changeset
455 gotoの実装には\ref{sec:tailcall}節で説明したTail callを用いているため
220f89415656 complete
kent
parents: 2
diff changeset
456 引数の書き込み領域と読み込み領域が重なる場合がある。
220f89415656 complete
kent
parents: 2
diff changeset
457 本来この場合はTail call不能として通常の関数呼出が用いられるところであるが、
220f89415656 complete
kent
parents: 2
diff changeset
458 CbCではこれを強制しなければならない。
220f89415656 complete
kent
parents: 2
diff changeset
459 そのため、このように重なる場合は変数の内容を一時退避する必要がある。
220f89415656 complete
kent
parents: 2
diff changeset
460 次のリスト\ref{code:push_overlaps}がこの処理を書く引数に対して行っている。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
461 \begin{lstlisting}[caption=push\_overlaps関数,label=code:push_overlaps]
3
220f89415656 complete
kent
parents: 2
diff changeset
462 push_overlaps(struct arg_data *args, int num_actuals){
220f89415656 complete
kent
parents: 2
diff changeset
463 int i;
220f89415656 complete
kent
parents: 2
diff changeset
464 for (i=0; i<num_actuals; i++)
220f89415656 complete
kent
parents: 2
diff changeset
465 {
220f89415656 complete
kent
parents: 2
diff changeset
466 int dst_offset;
220f89415656 complete
kent
parents: 2
diff changeset
467 int src_offset;
220f89415656 complete
kent
parents: 2
diff changeset
468 rtx temp;
220f89415656 complete
kent
parents: 2
diff changeset
469 if (/*args[i].stackはスタック外*/) continue;
220f89415656 complete
kent
parents: 2
diff changeset
470 if (/*args[i].valueはスタック外*/) continue;
220f89415656 complete
kent
parents: 2
diff changeset
471 temp =assign_temp(args[i].tree_value..);
220f89415656 complete
kent
parents: 2
diff changeset
472 if ( args[i].mode==BLKmode )
220f89415656 complete
kent
parents: 2
diff changeset
473 emit_block_move(temp,args[i].value..);
220f89415656 complete
kent
parents: 2
diff changeset
474 else
220f89415656 complete
kent
parents: 2
diff changeset
475 emit_move_insn(temp,args[i].value);
220f89415656 complete
kent
parents: 2
diff changeset
476 args[i].value = temp;
220f89415656 complete
kent
parents: 2
diff changeset
477 }
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
478 \end{lstlisting}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
479
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
480 \section{評価}
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
481 今回実装できたGCCによるCbCコンパイラでベンチマークを行い、
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
482 Micro-Cとの比較を行った。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
483
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
484 今回ベンチマークに使用したプログラムはこれまでもMicro-Cの測定に使われていた
3
220f89415656 complete
kent
parents: 2
diff changeset
485 テストルーチンで、普通のCのソースをプログラムでCbCに変換したものである。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
486 引数に1を入れるとそれが変換されたCbCのコード、
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
487 引数2,3では変換されたコードを手動でMicro-C用に最適化したコードが実行される。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
488 また、評価はia32アーキテクチャのFedora上で行った。
3
220f89415656 complete
kent
parents: 2
diff changeset
489 一番結果の良い引数2の場合のcode segmentをリスト\ref{code:bench}に示す。
220f89415656 complete
kent
parents: 2
diff changeset
490 \begin{lstlisting}[caption=bench,label=code:bench]
220f89415656 complete
kent
parents: 2
diff changeset
491 __code f2(int i,char *sp) {
220f89415656 complete
kent
parents: 2
diff changeset
492 int k,j;
220f89415656 complete
kent
parents: 2
diff changeset
493 k = 3+i;
220f89415656 complete
kent
parents: 2
diff changeset
494 goto g2(i,k,i+3,sp);
220f89415656 complete
kent
parents: 2
diff changeset
495 }
220f89415656 complete
kent
parents: 2
diff changeset
496 __code g2(int i,int k,int j,char *sp){
220f89415656 complete
kent
parents: 2
diff changeset
497 j = j+4;
220f89415656 complete
kent
parents: 2
diff changeset
498 goto h2(i,k+4+j,sp);
220f89415656 complete
kent
parents: 2
diff changeset
499 }
220f89415656 complete
kent
parents: 2
diff changeset
500 __code h2_1(int i,int k,int j,char *sp){
220f89415656 complete
kent
parents: 2
diff changeset
501 goto main_return2(i+j,sp);
220f89415656 complete
kent
parents: 2
diff changeset
502 }
220f89415656 complete
kent
parents: 2
diff changeset
503 __code h2(int i,int k,char *sp) {
220f89415656 complete
kent
parents: 2
diff changeset
504 goto h2_1(i,k,i+4,sp);
220f89415656 complete
kent
parents: 2
diff changeset
505 }
220f89415656 complete
kent
parents: 2
diff changeset
506 \end{lstlisting}
220f89415656 complete
kent
parents: 2
diff changeset
507 このベンチマークではCbCの継続と計算を交互に行っている。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
508 測定結果は表\ref{tab:mc,gcc,compare}に示される。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
509 \begin{table}[htpb]
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
510 \centering
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
511 \small
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
512 \begin{tabular}{|l|r|r|r|} \hline
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
513 & ./conv1 1 & ./conv1 2 & ./conv1 3 \\ \hline
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
514 Micro-C & 8.97 & 2.19 & 2.73 \\ \hline \hline
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
515 GCC & 4.87 & 3.08 & 3.65 \\ \hline
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
516 GCC (+omit) & 4.20 & 2.25 & 2.76 \\ \hline
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
517 GCC (+fast) & 3.44 & 1.76 & 2.34 \\ \hline \hline
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
518 \end{tabular}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
519 \caption{Micro-C, GCCの実行速度比較 (単位 秒)}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
520 \label{tab:mc,gcc,compare}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
521 \end{table}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
522
3
220f89415656 complete
kent
parents: 2
diff changeset
523 通常のTail call eliminationのみを有効にした場合の結果が2行目、
220f89415656 complete
kent
parents: 2
diff changeset
524 その他は次節で説明するオプションを付加したものである。
220f89415656 complete
kent
parents: 2
diff changeset
525 見てのとおり、手動で最適化された引数2,3の場合はオプションを加えなければ
220f89415656 complete
kent
parents: 2
diff changeset
526 Micro-Cの速度に及ばなかった。次節ではこの点について考察する。
220f89415656 complete
kent
parents: 2
diff changeset
527
220f89415656 complete
kent
parents: 2
diff changeset
528 \subsection{出力コード}
220f89415656 complete
kent
parents: 2
diff changeset
529 先ほどのリスト\ref{code:bench}のcode segment g2のみをMicro-Cでコンパイルした結果
220f89415656 complete
kent
parents: 2
diff changeset
530 をリスト\ref{code:bench_mc},
220f89415656 complete
kent
parents: 2
diff changeset
531 GCCのオプション無しによるコンパイル結果をリスト\ref{code:bench_gcc}に示す。
220f89415656 complete
kent
parents: 2
diff changeset
532 \begin{lstlisting}[caption=Micro-Cによる出力コード,label=code:bench_mc]
220f89415656 complete
kent
parents: 2
diff changeset
533 f2:
220f89415656 complete
kent
parents: 2
diff changeset
534 lea -_44(%ebp),%esp
220f89415656 complete
kent
parents: 2
diff changeset
535 movl $3,%eax
220f89415656 complete
kent
parents: 2
diff changeset
536 addl %esi,%eax
220f89415656 complete
kent
parents: 2
diff changeset
537 movl %eax,-28(%ebp)
220f89415656 complete
kent
parents: 2
diff changeset
538 movl %edi,-32(%ebp)
220f89415656 complete
kent
parents: 2
diff changeset
539 movl -28(%ebp),%edi
220f89415656 complete
kent
parents: 2
diff changeset
540 movl %esi,%eax
220f89415656 complete
kent
parents: 2
diff changeset
541 addl $3,%eax
220f89415656 complete
kent
parents: 2
diff changeset
542 movl %eax,-28(%ebp)
220f89415656 complete
kent
parents: 2
diff changeset
543 jmp g2
220f89415656 complete
kent
parents: 2
diff changeset
544 \end{lstlisting}
220f89415656 complete
kent
parents: 2
diff changeset
545 \begin{lstlisting}[caption=GCCによる出力コード,label=code:bench_gcc]
220f89415656 complete
kent
parents: 2
diff changeset
546 f2:
220f89415656 complete
kent
parents: 2
diff changeset
547 pushl %ebp
220f89415656 complete
kent
parents: 2
diff changeset
548 movl %esp, %ebp
220f89415656 complete
kent
parents: 2
diff changeset
549 movl 8(%ebp), %eax
220f89415656 complete
kent
parents: 2
diff changeset
550 movl 12(%ebp), %ecx
220f89415656 complete
kent
parents: 2
diff changeset
551 leal 3(%eax), %edx
220f89415656 complete
kent
parents: 2
diff changeset
552 movl %edx, 12(%ebp)
220f89415656 complete
kent
parents: 2
diff changeset
553 movl %edx, 16(%ebp)
220f89415656 complete
kent
parents: 2
diff changeset
554 movl %ecx, 20(%ebp)
220f89415656 complete
kent
parents: 2
diff changeset
555 popl %ebp
220f89415656 complete
kent
parents: 2
diff changeset
556 jmp g2
220f89415656 complete
kent
parents: 2
diff changeset
557 \end{lstlisting}
220f89415656 complete
kent
parents: 2
diff changeset
558 このとおり出力コードは10命令と、行数にはあまり差が無い。(他のsegmentも同様である)
220f89415656 complete
kent
parents: 2
diff changeset
559 しかしGCCの出力においては無駄なコードが混じっていることがわかるだろう。
220f89415656 complete
kent
parents: 2
diff changeset
560 \verb|pushl%ebp|と\verb|popl %ebp|である。
220f89415656 complete
kent
parents: 2
diff changeset
561 すべてのcode segmentにおいてこれと同じ命令が出てしまっているが、
220f89415656 complete
kent
parents: 2
diff changeset
562 これはTailcallを無理矢理適用したために出てきたコードである。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
563
3
220f89415656 complete
kent
parents: 2
diff changeset
564 このような関数の最初と最後にある無駄なフレームポインタのpushを抑制するオプションが
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
565 -fomit-frame-pointerである。このオプションを付加するとリスト\ref{code:bench_gcc_omit}
3
220f89415656 complete
kent
parents: 2
diff changeset
566 \begin{lstlisting}[caption=GCCによる出力コード,label=code:bench_gcc_omit]
220f89415656 complete
kent
parents: 2
diff changeset
567 f2:
220f89415656 complete
kent
parents: 2
diff changeset
568 movl 4(%esp), %eax
220f89415656 complete
kent
parents: 2
diff changeset
569 movl 8(%esp), %ecx
220f89415656 complete
kent
parents: 2
diff changeset
570 leal 3(%eax), %edx
220f89415656 complete
kent
parents: 2
diff changeset
571 movl %edx, 8(%esp)
220f89415656 complete
kent
parents: 2
diff changeset
572 movl %edx, 12(%esp)
220f89415656 complete
kent
parents: 2
diff changeset
573 movl %ecx, 16(%esp)
220f89415656 complete
kent
parents: 2
diff changeset
574 jmp g2
220f89415656 complete
kent
parents: 2
diff changeset
575 \end{lstlisting}
220f89415656 complete
kent
parents: 2
diff changeset
576 これによって一気に3命令減った。ベンチマークは表\ref{tab:mc,gcc,compare}の3行目、``GCC (+omit)''である。
220f89415656 complete
kent
parents: 2
diff changeset
577 しかし、(code segmentにもよるが)3/10命令減ったにもかかわらずMicro-Cとの速度差が
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
578 ほとんど無い。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
579
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
580 リスト11をみるとMicro-Cでは引数の格納にレジスタ\%edi と
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
581 \%esi を用いる分、高速なコードを生成出来ていることが分かる。
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
582 この違いが命令数の差を埋めている。
3
220f89415656 complete
kent
parents: 2
diff changeset
583 GCCでも引数をレジスタに詰めることができるfastcall属性がある。
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
584 -fomit-frame-pointerに加えてfastcallを付加した結果をリスト\ref{code:bench_gcc_fast}
3
220f89415656 complete
kent
parents: 2
diff changeset
585 に示す。
220f89415656 complete
kent
parents: 2
diff changeset
586 \begin{lstlisting}[caption=GCCによる出力コード,label=code:bench_gcc_fast]
220f89415656 complete
kent
parents: 2
diff changeset
587 f2:
220f89415656 complete
kent
parents: 2
diff changeset
588 movl %edx, %eax
220f89415656 complete
kent
parents: 2
diff changeset
589 leal 3(%ecx), %edx
220f89415656 complete
kent
parents: 2
diff changeset
590 movl %edx, 4(%esp)
220f89415656 complete
kent
parents: 2
diff changeset
591 movl %eax, 8(%esp)
220f89415656 complete
kent
parents: 2
diff changeset
592 jmp g2
220f89415656 complete
kent
parents: 2
diff changeset
593 \end{lstlisting}
220f89415656 complete
kent
parents: 2
diff changeset
594 命令数はさらに2命令減り、またメモリへのアクセスが減ったため
220f89415656 complete
kent
parents: 2
diff changeset
595 ベンチマーク結果(表\ref{tab:mc,gcc,compare}GCC (+fast))も大幅に改善した。
220f89415656 complete
kent
parents: 2
diff changeset
596
220f89415656 complete
kent
parents: 2
diff changeset
597 この評価結果から、GCCの最適化オプションを用いることで
220f89415656 complete
kent
parents: 2
diff changeset
598 CbCコードのさらなる高速化が可能であることが示された。
220f89415656 complete
kent
parents: 2
diff changeset
599 また、使用したベンチマークプログラムはCのコードをプログラムで
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
600 CbCに変換したものだが、これをCのままコンパイルすると
3
220f89415656 complete
kent
parents: 2
diff changeset
601 最適化をかけても約3.3秒かかる。
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
602 このように不要なスタック操作を減らすことによって、
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
603 C言語のみでは不可能な手動による最適化がCbCの利点としてあげられる。
3
220f89415656 complete
kent
parents: 2
diff changeset
604
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
605
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
606 \section{今後の課題と考察}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
607 本研究の実装により、GCCを使ってCbCのソースコードを
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
608 コンパイルすることができるようになった。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
609 また、これまでのMicro-Cベースのコンパイラではできなかった
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
610 最適化をGCC上で実行できるようになった。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
611
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
612 しかしまだいくつかの問題が残っているので、
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
613 今後の課題と併せて、以下に簡単に説明する。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
614 \begin{description}
2
29847c3bea64 temporary finish
kent
parents: 1
diff changeset
615 \item[environment]
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
616 CbCにはもう一つ、environment付きの継続という構文が存在する。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
617 これは関数からcode segmentにgotoした場合に関数の呼び出し元に戻る
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
618 ことを可能にするものだが、今回この実装は間に合わなかった。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
619 \item[PPCのRTL変換不能] PowerPCアーキテクチャにおいて、code segment
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
620 のポインタ参照へgotoすることができない。
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
621 これはRTLレベルで対応されてないことが原因と思われる。
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
622 \item[オプションの強制] -O2オプションや、code segmentへのfasecall属性の付加
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
623 などを強制させる必要がある。
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
624 \item[SPU対応とGCCのversion] 実装できたversionは4.2.3である。
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
625 しかし現在SPUに対応したGCCは4.1までしかでていないうえに、
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
626 GCCのversion間の差異によって移植が難しくなっている。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
627 \end{description}
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
628 ここで、二つ目のPowerPCへの対応が大きな問題となっている。
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
629 本来、このコンパイラはアーキテクチャに依存しない形で
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
630 実装したのが、実装後、PowerPCはTailcall eliminationにたいして一部対応してない
1
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
631 ことがわかった。
d9061c8bce92 *** empty log message ***
kent
parents: 0
diff changeset
632 これはMachineDescriptionとよばれるRTLからアセンブラへの対応を表す
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
633 ファイルを記述することで対応させることができるはずだが、今回その実装には至らなかった。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
634
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
635 またこれらに加えて、GCCはすでにC++や
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
636 Objective-C のコンパイルが可能である。これを活かし、
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
637 CbC++, もしくはObjective-CbC といった
5
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
638 既存の言語とCbC を組み合わせた言語に付いても今後実装していく。
7fdca589238f *** empty log message ***
kent
parents: 4
diff changeset
639 %考えてみる価値があるだろう。
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
640
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
641
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
642 \small
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
643 \begin{thebibliography}{9}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
644 \bibitem{kono1} 河野真治. ``継続を基本とした言語CbCのgcc上の実装''.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
645 日本ソフトウェア科学会第19回大会論文集, Sep, 2002.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
646 \bibitem{kono2} 河野真治. ``継続を持つCの下位言語によるシステム記述''.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
647 日本ソフトウェア科学会第17回大会論文集, Sep, 2000.
4
2c619ec34ae4 add a paper for C-- in bib.
kent
parents: 3
diff changeset
648 \bibitem{c--} Simon Peyton Jones, Thomas Nordin, and Dino Oliva, ``C--: a portable assembly language''. Implementing Functional Languages, 1997.
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
649 \bibitem{gcc1} GNU Project - Free Software Foundation, GCC internal manual.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
650 ``http://gcc.gnu.org/onlinedocs/gccint/''.
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
651 \end{thebibliography}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
652
3
220f89415656 complete
kent
parents: 2
diff changeset
653 \renewcommand{\thepage}{--- \arabic{page} ---E}
0
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
654 \end{document}
6bd50f4568a0 OS$B8&5f2qMQO@J8(B
kent
parents:
diff changeset
655