comparison paper/chapter3.tex @ 17:3afb4bfe1100

fix
author Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
date Mon, 15 Feb 2016 07:30:44 +0900
parents 7161b80a7e19
children
comparison
equal deleted inserted replaced
16:bea98599d11f 17:3afb4bfe1100
1 \chapter{LLVM clang 上での CbC の実装} 1 \chapter{LLVM clang 上での CbC の実装}
2 第 \ref{chapter:CbC}, \ref{chapter:LLVM/clang} 章をもとに LLVM, clang への CbC コンパイル機能の実装を行う. コードセグメントの解釈, 軽量継続などいくつかの機能は過去の研究によって実装されたが, 本研究での実装に繋がるので説明する. 2 第 \ref{chapter:CbC}, \ref{chapter:LLVM/clang} 章をもとに LLVM, clang への CbC コンパイル機能の実装を行う. コードセグメントの解釈, 軽量継続などいくつかの機能は過去の研究によって実装されたが, 本研究での実装に繋がるのでここでも説明する.
3 3
4 以降に示される LLVM, clang のファイルパスについて, \$(CLANG) を clang のソースコードを展開したディレクトリのパス, \$(LLVM) を LLVM のソースコードを展開したディレクトリのパスとする. 4 以降に示される LLVM, clang のファイルパスについて, \$(CLANG) を clang のソースコードを展開したディレクトリのパス, \$(LLVM) を LLVM のソースコードを展開したディレクトリのパスとする.
5 \section{code segment} 5 \section{code segment}
6 \label{sec:codeSegment} 6 \label{sec:codeSegment}
7 code segment は \_\_code 型の関数のように扱えるよう実装する. また, code segment は 戻り値を返さないので void 型を参考に変更を加えていく. 最初に関数が code segment であることを示す \_\_code 型の追加を行う. これは clang, llvm 別々で行う必要がある. clang 側の作業は \_\_code を予約語として定義する改変から始める. clang では, 予約語は全て \$(CLANG)/include/ clang/Basic/TokenKinds.def に定義されており, ここで定義した予約語の頭に kw\_ を付けたものがその予約語の ID となる. ここに, 次のように変更を加えて \_\_code を追加した. ここで使われている KEYWORD マクロは予約語の定義に用いられるもので, 第一引数が登録したい予約語, 第二引数がその予約語が利用される範囲を表す. KEYALL は全ての C, C++ でサポートされることを示し, この他には C++ の予約語であることを示す KEYCXX や C++11 以降で利用されることを示す KEYCXX11 等がある. code segment は C のバージョンに関わらずサポートされるべきであるので KEYALL を選択した. ここで環境付き継続に用いる予約語である \_\_return, \_\_environment の定義も同時に行う. 7 code segment は \_\_code 型の関数のように扱えるよう実装する. また, code segment は 戻り値を返さないので void 型を参考に変更を加えていく. 最初に関数が code segment であることを示す \_\_code 型の追加を行う. これは clang, llvm 別々で行う必要がある. clang 側の作業は \_\_code を予約語として定義する改変から始める. clang では, 予約語は全て \$(CLANG)/include/ clang/Basic/TokenKinds.def に定義されており, ここで定義した予約語の頭に kw\_ を付けたものがその予約語の ID となる. ここに, 次のように変更を加えて \_\_code を追加した. ここで使われている KEYWORD マクロは予約語の定義に用いられるもので, 第一引数が登録したい予約語, 第二引数がその予約語が利用される範囲を表す. KEYALL は全ての C, C++ でサポートされることを示し, この他には C++ の予約語であることを示す KEYCXX や C++11 以降で利用されることを示す KEYCXX11 等がある. code segment は C のバージョンに関わらずサポートされるべきであるので KEYALL を選択した. ここで環境付き継続に用いる予約語である \_\_return, \_\_environment の定義も同時に行う.
329 return false; 329 return false;
330 } 330 }
331 \end{lstlisting} 331 \end{lstlisting}
332 332
333 \section{フレームポインタ操作最適化} 333 \section{フレームポインタ操作最適化}
334 フレームポインタ操作の最適化は omit leaf frame pointer を強制することで行う. この最適化は \ref{sec:olfp} 節でしたとおり leaf function に対して行われるが, 継続を続ける code segment は何もせずとも leaf function の条件を満たしているので内部で有効化するだけで良い. 334 フレームポインタ操作の最適化は omit leaf frame pointer を強制することで行う. この最適化は関数呼び出しの際に行われるフレームポインタ操作に関わる最適化である. 通常関数呼び出しを行う際にはフレームポインタの値をスタックに積み, return 直前に戻すという作業を行う. omit leaf frame pointer はこの操作を leaf function を呼び出す際に行わないようにする最適化である.
335 335 leaf function とはコールツリーの終端の位置する関数のことを指し, この関数が関数を呼び出さないことを意味する. 軽量継続を続ける code segment は何もせずとも leaf function の条件を満たしているので内部で有効化するだけで良い.
336
337 以下のリスト \ref{loptno}, \ref{lopt} はどちらもリスト \ref{leaf} をコンパイルして得られるアセンブリコードから関数 caller の部分を抜き出したものであり, 前者が omit leaf frame pointer 無し, 後者が omit leaf frame pointer ありのコードである. push, pop 命令によるフレームポインタの操作がリスト \ref{lopt} ではなくなっていることがわかる.
338
339 \begin{lstlisting}[frame=lrbt, label=leaf, caption={関数 caller}]
340 void caller(int a, int b, int c){
341 B(a, b, c, 40);
342 return;
343 }
344 \end{lstlisting}
345 \begin{lstlisting}[frame=lrbt, label=loptno, caption={関数 caller (omit leaf frame pointer 無し)}]
346 _caller: ## @caller
347 .cfi_startproc
348 ## BB#0:
349 pushq %rbp
350 Ltmp0:
351 .cfi_def_cfa_offset 16
352 Ltmp1:
353 .cfi_offset %rbp, -16
354 movq %rsp, %rbp
355 Ltmp2:
356 .cfi_def_cfa_register %rbp
357 movl %edi, -4(%rbp)
358 movl %esi, -8(%rbp)
359 movl -4(%rbp), %esi
360 addl -8(%rbp), %esi
361 movl %esi, %eax
362 popq %rbp
363 retq
364 .cfi_endproc
365 \end{lstlisting}
366 \begin{lstlisting}[frame=lrbt, label=lopt, caption={関数 caller (omit leaf frame pointer 有り)}]
367 _caller: ## @caller
368 .cfi_startproc
369 ## BB#0:
370 movl %edi, -4(%rbp)
371 movl %esi, -8(%rbp)
372 movl -4(%rbp), %esi
373 addl -8(%rbp), %esi
374 movl %esi, %eax
375 retq
376 .cfi_endproc
377 \end{lstlisting}
378
336 omit leaf frame pointer は clang 内部では CodeGenOpts.OmitLeafFramePointer として表現されている. clang は CodeGen で LLVM IR の function を生成する際にこのフラグが立っているかどうかを確認し, 立っている場合には関数の no-frame-pointer-elim という attribute を false にする. それにより最適化が当該関数に作用するようになる. この, LLVM IR function への attribute 設定を行っているのは \$(CLANG)/lib/CodeGen/CGCall.cpp である. ここをリスト \ref{olfp} のように変更した. 通常は OmitLeafFramePointer のみを確認する部分を HasCodeSegment によって code segment の有無も確認するように変更している. これにより, code segment を含むコードのコンパイル, 即ち CbC のコードのコンパイルの際には自動的に omit leaf frame pointer が有効化されるようになった. 379 omit leaf frame pointer は clang 内部では CodeGenOpts.OmitLeafFramePointer として表現されている. clang は CodeGen で LLVM IR の function を生成する際にこのフラグが立っているかどうかを確認し, 立っている場合には関数の no-frame-pointer-elim という attribute を false にする. それにより最適化が当該関数に作用するようになる. この, LLVM IR function への attribute 設定を行っているのは \$(CLANG)/lib/CodeGen/CGCall.cpp である. ここをリスト \ref{olfp} のように変更した. 通常は OmitLeafFramePointer のみを確認する部分を HasCodeSegment によって code segment の有無も確認するように変更している. これにより, code segment を含むコードのコンパイル, 即ち CbC のコードのコンパイルの際には自動的に omit leaf frame pointer が有効化されるようになった.
337 380
338 \begin{lstlisting}[frame=lrbt,label=olfp,caption={omit leaf frame pointer 有効化}] 381 \begin{lstlisting}[frame=lrbt,label=olfp,caption={omit leaf frame pointer 有効化}]
339 } else if (CodeGenOpts.OmitLeafFramePointer || LangOpts.HasCodeSegment) { 382 } else if (CodeGenOpts.OmitLeafFramePointer || LangOpts.HasCodeSegment) {
340 FuncAttrs.addAttribute("no-frame-pointer-elim", "false"); 383 FuncAttrs.addAttribute("no-frame-pointer-elim", "false");