changeset 8:e9a6d390a401

env
author Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
date Tue, 09 Feb 2016 21:25:40 +0900
parents 5f0a5e8cb3cc
children 7161b80a7e19
files paper/chapter2.tex paper/chapter3.tex paper/chapter5.tex paper/gotoWithEnv.tex paper/master_paper.pdf paper/master_paper.tex
diffstat 6 files changed, 393 insertions(+), 263 deletions(-) [+]
line wrap: on
line diff
--- a/paper/chapter2.tex	Tue Feb 09 17:40:53 2016 +0900
+++ b/paper/chapter2.tex	Tue Feb 09 21:25:40 2016 +0900
@@ -1,4 +1,4 @@
-\chapter{LLVM, clang}
+\chapter{LLVM clang}
 \label{chapter:LLVM/clang}
 LLVM とはコンパイラ, ツールチェーン技術等を開発するプロジェクトの名称である. 単に LLVM といった場合は LLVM Core を指し, これはコンパイラの基板となるライブラリの集合である. 以降は本論文でも, 単に LLVM といった場合は LLVM Core を指す. LLVM IR や LLVM BitCode と呼ばれる独自の言語を持ち, この言語で書かれたプログラムを実行することのできる仮想機械も持つ. また, LLVM IR を特定のターゲットの機械語に変換することが可能であり, その際に LLVM の持つ最適化機構を利用することができる. LLVM を利用する各コンパイラフロントエンドはターゲットとなるプログラミング言語を LLVM IR に変換することで LLVM の持つ最適化機構を利用する. 
 
@@ -337,6 +337,7 @@
 \end{lstlisting}
 
 \section{Tail call elimination}
+\label{sec:TCE}
 前述した通り, LLVM の処理は最適化を含め全て pass によって行われるため, pass を選択することで任意の最適化をかけることができる. 独自の pass を作ることも可能であり, pass 作成のチュートリアルは LLVM のドキュメント\cite{LLVM}にも記されている. また, pass の雛形となるクラスも用意されており, 独自の pass を作成する環境は整っていると言える.
 
 最適化機構は本研究においてはほとんど関係しないが, 継続の実装に関わる Tail Call Elimination, 関数呼び出し時のフレームポインタ操作の最適化を行う omit leaf frame pointer だけは別である. 
@@ -425,9 +426,7 @@
 
 二つのアセンブリを比較すると, tail call elimination を行った方では call 命令を用いずに jmp 命令で 関数 B に移動していることがわかる. 移動の前に popq を \%rbp に対して行っているのはベースポインタの値を戻しておき, 関数 B から直接 main 関数に戻れるようにするためである. 尚, GCC では tail call elimination を行っていない場合には関数呼び出し前にスタックの値を操作する処理が入っていたが, LLVM ではそれが行われていない. これについて, LLVM では tail call elimination を行っていない場合でも関数呼び出しが末尾にある場合には, その関数に戻ることがないことが自明であることから, 現在のスタックに割り当てられたスタックフレームをそのまま使用するようにしているのだろう. 
 
-\section{Tail call elimination の要件}
-\label{sec:TCE}
-Tail call elimination は 全ての tail call に対して行えるわけではなく, 行うためにはいくつかの条件を満たさなければならない. この条件は LLVM Document\cite{LLVM}に記されている. 現在 LLVM では x86/x86-64, PowerPC を tail call elimination のサポート対象としている. 今回の実装では x86/x86-64 を対象としたので, そちらの条件について考える. x86/x86-64 での tail call elimination の要件は以下のようになっている.
+しかし, Tail call elimination は 全ての tail call に対して行えるわけではなく, 行うためにはいくつかの条件を満たさなければならない. この条件は LLVM Document\cite{LLVM}に記されている. 現在 LLVM では x86/x86-64, PowerPC を tail call elimination のサポート対象としている. 今回の実装では x86/x86-64 を対象としたので, そちらの条件について考える. x86/x86-64 での tail call elimination の要件は以下のようになっている.
 
 \begin{enumerate}
   \item 呼び出し元と呼び出す関数の呼び出し規約が fastcc, cc 10 (GHC calling convention), cc 11 (HiPE calling convention) のいずれかである.
--- a/paper/chapter3.tex	Tue Feb 09 17:40:53 2016 +0900
+++ b/paper/chapter3.tex	Tue Feb 09 21:25:40 2016 +0900
@@ -1,4 +1,4 @@
-\chapter{LLVM, clang 上での CbC の実装}
+\chapter{LLVM clang 上での CbC の実装}
 第 \ref{chapter:CbC}, \ref{chapter:LLVM/clang} 章をもとに LLVM, clang への CbC コンパイル機能の実装を行う. コードセグメントの解釈, 軽量継続などいくつかの機能は過去の研究によって実装されたが, 本研究での実装に繋がるので説明する.
 
 以降に示される LLVM, clang のファイルパスについて, \$(CLANG) を clang のソースコードを展開したディレクトリのパス, \$(LLVM) を LLVM のソースコードを展開したディレクトリのパスとする.
@@ -239,259 +239,6 @@
 
 LLVM でのオプションの追加方法についてもここで述べておく. LLVM のオプションは TargetOptions というクラスが管理しており, その定義は \$(LLVM)/include/llvm/Target/ TargetOptions.h で行われている. こちらはマクロは使っておらずビットフィールドを用いて定義されている. TargetOptions クラスの中で変数を宣言するだけで追加できるので, コードは省略する.
 
-\section{環境付き継続}
-環境付き継続を行うためには \_\_return, \_\_environment という特殊変数を用いる. これら二つの変数の実装方法には様々な方法が考えられる. GCC 上に実装した CbC コンパイラでは GCC による C の拡張構文である内部関数を用いていた. しかし, clang ではこの拡張構文は対応しておらず, 別の方法をとる必要がある. 過去の研究においてこの機能は実装されたが, その際には setjmp, longjmp を用いた実装を行った. 
-
-環境付き継続は, \_\_return, \_\_environment が使用された時に自動的にあるコードを生成することで実現される. 具体的には, リスト \ref{autoCodeGenB} のようなコードをコンパイルした場合にリスト \ref{autoCodeGenA} のように解釈することで実現される. この置き換えられるコードについて, 以前の実装では setjmp, longjmp を用いていたが, 今回 llvm builtin の setjmp, longjmp を用いるように変更を加えた.
-
-\begin{lstlisting}[frame=lrbt,label=autoCodeGenB,caption={環境付き継続の例}]
-__code cs(int retval,__code(*ret)(int,void *),void *env){
-  goto ret(n, env);
-}
-
-int func (){
-  goto cs(30, __return, __environment);
-  return 0;
-}
-\end{lstlisting}
-\begin{lstlisting}[frame=lrbt,label=autoCodeGenA,caption={内部での解釈}]
-#include <setjmp.h>
-
-struct CbC_env {
-  void *ret_p,*env;
-};
-
-__code cs(int retval,__code(*ret)(int,void *),void *env){
-  goto ret(n, env);
-}
-
-__code return1 (int retval, void* env){
-  *(int*)((struct CbC_env *)(env))->ret_p = retcal;
-  __builtin_longjmp((int*)(((struct CbC_env *)env)->env),1);
-}
-
-int func (){
-  __code (*__return)();
-  struct CbC_env __environment;
-  jmp_buf env;
-  int retval;
-  __environment.ret_p = &retval;
-  __environment.env = &env;
-  __return = return1;
-    if (__builtin_setjmp(__environment.env)){
-      return retval;
-    }
-  goto code1(30, __return, &__environment);
-  return 0;
-}
-\end{lstlisting}
-
-追加された処理は, setjmp ヘッダのインクルード, 環境と戻り値を保持する構造体 CbC\_env の定義, 元の環境に戻るための特殊 code segment return1 の定義, そして関数 func 内の 17 行目から 26 行目までの処理であり, 27 行目の継続の第三引数も参照渡しに変更される. 追加された処理の大まかな流れを説明する. 環境付き継続を用いる関数は継続前に \_\_builtin\_setjmp を用いて戻り先の環境を保存し, 継続を行う. このとき, 引数として渡される \_\_return には特殊 code segment return1 のアドレス, \_\_environment の持つメンバには戻り値として返される値を持つ変数のアドレスと, \_\_builtin\_setjmp により保存された継続前の環境が保持されている. 元の環境に戻るための code segment は自動生成されるので, 継続先の code segment は返す戻り値と \_\_environemnt を引数として \_\_return の指す code segment を呼び出すだけで元の環境に戻れる. return1 は 構造体の持つ戻り値へのポインタを利用して戻り値を更新した後, \_\_builtin\_longjmp を用いて元の環境に戻る. \_\_builtin\_longjmp によって再度 \_\_builtin\_setjmp の呼び出しに戻るが今回は if文内に入り, 戻り値を返す.
-
-自動生成される文をまとめるといかのようになる.
-
-\begin{itemize}
-  \item \_\_return
-    \begin{itemize}
-    \item 元の環境に戻るための特殊な code segment
-    \item 各変数の宣言及び代入文
-    \end{itemize}
-  \item \_\_environment
-    \begin{itemize}
-    \item 環境を保持する構造体 CbC\_env の定義
-    \item 各変数の宣言及び代入文
-    \item \_\_builtin\_setjmp を条件文にとり, 真の場合に関数の戻り値を返す if文
-    \end{itemize}
-  \item どちらにも依存しない
-    \begin{itemize}
-    \item setjmp.h のインクルード文
-    \end{itemize}
-\end{itemize}
-
-setjmp.h のインクルード文がどちらにも属さないのは, 無条件でこのヘッダをインクルードするようにしてもよいからである. 必要のないコードは最適化によって除去されるので, 使用されない場合でもインクルードして構わない. また, これらの文を生成する際, 元の関数の型の戻り値を返せるようにしなければならないが, \ref{sec:clang} 節で説明したように, clang では型情報を QualType が管理しているので, 生成する関数や変数に対して元の関数の返り値に対応する QualType を与えるだけでこの問題は解決する. 尚, 二つの予約語を登録する処理は既に説明したので省く.
-
-まずはじめに setjmp.h のインクルード文の生成について説明する. clang では include マクロによって他のファイルのインクルードを行う場合, 字句解析対象となるのファイルの変更を行う. 本研究では, これらの処理に必要なものを IncludeHeader という一つの関数にまとめ, それを呼び出すことで任意のファイルをインクルードできるようにした. その関数のうち, 重要な部分を抜き出したものを以下のリスト \ref{IncludeHeader} に示す. この関数は引数に現在の token とインクルードするファイルの名前を求める. まずこの関数は, 現在の token の保存処理を行う. これは, この関数が呼ばれた時点で取得された token はすでに字句解析対象のバッファから取り除かれており, これを保存しておかないとインクルード処理終了後の構文解析に影響が出るために行っている. 次に, 指定されたファイルの検索を行う. その処理を行っているのは 11行目であり, このときファイルが見つからなかった場合には NULL が返るので, これを利用してエラーの生成も行っている. 解析対象の変更を行っているのが 16行目以降の処理で, 実際にファイルを移っているのは 18行目の EnterSourceFile 関数である. この関数によって字句解析対象が現在のファイルから指定したファイルへと変更される. また, この関数の戻り値はファイルのインクルード処理を行ったかどうかを判断するために用いる. 
-
-\begin{lstlisting}[frame=lrbt,label=IncludeHeader,caption={IncludeHeader 関数}]
-bool Preprocessor::IncludeHeader(Token Tok, const char* Name) {
-  if (SavedTokenFlag) // If the lexer has already entered a header file, we have to leave this function.
-    return false;
-  SourceLocation Loc = Tok.getLocation();
-  SavedToken = Tok;
-  SavedDepth = IncludeMacroStack.size();
-  SavedTokenFlag = true;
-
-       :
-
-  const FileEntry *File = LookupFile(Loc, Filename, isAngled, LookupFrom, CurDir, NULL, NULL,
-				     HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
-
-       :
-
-  FileID FID = SourceMgr.createFileID(File, Loc, FileCharacter);      
-  EnterSourceFile(FID, CurDir, FilenameTok.getLocation(), static_cast<bool>(BuildingModule));
-  return true;
-}
-\end{lstlisting}
-
-次に, 元の環境に戻るための特殊な code segment の定義生成処理の説明をする. これを行うためには clang の持つ AST に関数の定義を加えてやれば良い. 今回の実装でその処理を担うのが以下のリスト \ref{return1} に示される CreateRetCS 関数である. ただしここでは重要でない箇所を省いている. この関数は引数として生成する関数の名前を受け取る. 2, 3 行目が元の関数の QualType を取得する処理である. 5 行目から 14 行目までの処理は関数宣言のためにスコープをグローバルスコープに変更するための処理で, すべての処理を終えた後, 59 行目から 62 行目の処理によって元のスコープに戻す. 16 行目から 42 行目までが関数のプロトタイプ宣言に関する設定処理を行っており, 29 行目で 取得しておいた QualType を利用していることがわかる. 44 行目からが関数の持つ処理の定義を指定する部分にあたり, 52 行目にある StmtVector クラスのインスタンスに対して任意の文に対応する StmtResult を追加し, 54 行目の関数を呼び出すと戻り値としてこの関数の中身を表す StmtResult を得ることができる. その後これを定義や宣言を管理するクラスである Decl へと変換し, 58 行目の関数を呼び出すことで生成した関数の定義が AST に追加される. 
-
-\begin{lstlisting}[frame=lrbt,label=return1,caption={CreateRetCS 関数}]
-bool Parser::CreateRetCS(IdentifierInfo *csName){
-  FunctionDecl *CurFunctionDecl = Actions.getCurFunctionDecl();
-  QualType CurFuncResQT = CurFunctionDecl->getResultType();
-
-  Scope *SavedScope = getCurScope();
-  DeclContext *SavedContext = Actions.CurContext;
-  TypeSourceInfo *CurFuncTI = Actions.Context.CreateTypeSourceInfo(CurFuncResQT);
-  sema::FunctionScopeInfo *SavedFSI = Actions.FunctionScopes.pop_back_val();
-
-  Actions.CurContext = static_cast<DeclContext *>(Actions.Context.getTranslationUnitDecl());
-  Scope *TopScope = getCurScope();
-  while(TopScope->getParent() != NULL)
-    TopScope = TopScope->getParent();
-  Actions.CurScope = TopScope;
-
-  DeclGroupPtrTy returnDecl = DeclGroupPtrTy();
-  ParsingDeclSpec PDS(*this);
-  setTST(&PDS, DeclSpec::TST___code);
-  ParsingDeclarator D(*this, PDS, static_cast<Declarator::TheContext>(Declarator::FileContext));
-  D.SetIdentifier(csName, Loc);
-  ParseScope PrototypeScope(this,Scope::FunctionPrototypeScope|Scope::DeclScope|Scope::FunctionDeclarationScope);
-  SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
-  DeclSpec FDS(AttrFactory);
-  ParmVarDecl *Param;
-		
-  IdentifierInfo *retvalII = CreateIdentifierInfo(__CBC_RETVAL_NAME, Loc);
-  Param = CreateParam(retvalII);
-  Param->setTypeSourceInfo(CurFuncTI);
-  Param->setType(CurFuncResQT);
-
-  ParamInfo.push_back(DeclaratorChunk::ParamInfo(retvalII, Loc, Param, 0));
-  IdentifierInfo *envII = CreateIdentifierInfo(__CBC_STRUCT_ENV_NAME, Loc);
-  Param = CreateParam(envII, 1, DeclSpec::TST_void);
-  ParamInfo.push_back(DeclaratorChunk::ParamInfo(envII, Loc, Param, 0));
-
-  D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, IsAmbiguous, Loc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, Loc,
-					     FDS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, ConstQualifierLoc,
-					     VolatileQualifierLoc, SourceLocation(), ESpecType, ESpecRange.getBegin(),
-					     DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(),
-					     NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0,
-					     Loc, Loc, D, TrailingReturnType), FnAttrs, Loc);
-  PrototypeScope.Exit();
-	
-  Decl *TheDecl;
-  ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
-  Decl *BodyRes = Actions.ActOnStartOfFunctionDef(getCurScope(), D);
-
-  D.complete(BodyRes);
-  D.getMutableDeclSpec().abort();
-  Actions.ActOnDefaultCtorInitializers(BodyRes);
-  StmtResult FnBody;
-  StmtVector FnStmts;
-  /* add function body statements */
-  FnBody = Actions.ActOnCompoundStmt(Loc, Loc, FnStmts, false);
-  BodyScope.Exit();
-  TheDecl = Actions.ActOnFinishFunctionBody(BodyRes, FnBody.take());
-  returnDecl =  Actions.ConvertDeclToDeclGroup(TheDecl);
-  (&Actions.getASTConsumer())->HandleTopLevelDecl(returnDecl.get());
-  Actions.CurScope = SavedScope;
-  Actions.CurContext = SavedContext;
-  Actions.FunctionScopes.push_back(SavedFSI);
-  return false;
-}
-\end{lstlisting}
-
-つづいて構造体 CbC\_env の定義を行う. この構造体は \_\_builtin\_setjmp, \_\_builtin\_longjmp が環境の保持に使う jmp\_buf へのポインタと元の関数の戻り値となる変数へのポインタを持つ. 構造体の宣言は通常, 構文解析器によって Decl というクラスのインスタンスが生成され, それを利用して行う. 今回の実装では Decl の生成を手書きのコードで行うことで, 自動で構造体の定義を行う処理を実現した. 今回の実装ではそのコード群を Create\_\_CbC\_envStruct という一つの関数にまとめた. その関数のうち,重要な部分を抜き出したものを以下のリスト \ref{CbC_env} に示す. この関数はソースコードの位置と C++ で用いられるアクセス修飾子を引数に取る. この関数もスコープを変更する処理を持つが, それについては先ほど説明したので省いている. 12 行目から 22 行目までが, この構造体の Decl を生成する処理である. メンバの設定を行っているのが 27 行目から 30 行目で, ここで使用している Create\_\_CbC\_envBody 関数はメンバの宣言を行うために独自に作成した関数である. 構造体のメンバとして宣言するために ActOnField という Sema クラスの関数を呼び出す以外は後述する CreateDeclStmt 関数と処理内容にあまり差が無いため, この関数については本論文では説明を省く. 32 行目で呼び出している ActOnTagFinishDefinision が, 生成した Decl を元に構造体の宣言の意味解析を行ってくれる関数である. これにより, 生成した構造体に対応する Type も生成される. 
-
-\begin{lstlisting}[frame=lrbt,label=CbC_env,caption={Create\_\_CbC\_envStruct 関数}]
-void Parser::Create__CbC_envStruct(SourceLocation Loc, AccessSpecifier AS) {
-
-          :
-
-  ParsingDeclSpec SDS(*this);
-  DeclSpec::TST TagType = DeclSpec::TST_struct;
-  DeclResult TagOrTempResult = true;
-  bool Owned = false;
-  bool IsDependent = false;
-  TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, Sema::TUK_Definition, Loc,
-				     SDS.getTypeSpecScope(), Name, Loc, attrs.getList(), AS,
-				     SDS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent,
-				     SourceLocation(), false, clang::TypeResult());
-
-  Decl *TagDecl = TagOrTempResult.get();
-  ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
-  Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
-  SmallVector<Decl *, 32> FieldDecls;
-
-  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_POINTER_NAME));
-  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_ENV_NAME));
-
-  Actions.ActOnFields(getCurScope(),Loc, TagDecl, FieldDecls,Loc, Loc,attrs.getList());
-  StructScope.Exit();
-  Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, Loc);
-
-          :
-}
-\end{lstlisting}
-
-つづいて両予約語解析時に共通する処理の一つである変数の定義文に関して説明する. これも定義に関する文であるので Decl の生成がメインとなる. 今回の実装では以下のリスト\ref{DeclStmt} に示す CreateDeclStmt という関数を作り, その関数によってその処理を行う. ここでも重要でない処理は省いている. この関数は引数として変数名, code segment へのポインタかどうか, 呼び出し元の関数の型をコピーするかどうか, 変数の型, 構造体だった場合の構造体名を持つ. 4 行目の setTST 関数が指定された型修飾子を設定している箇所である. 変数名は 6 行目の SetIdentifier 関数によって設定され, その後は関数へのポインタだった場合や構造体だった場合のときにのみ行われる処理が来るがここでは省いた. その後型コピーを行うかどうかで処理が異なる. 型コピーの方法については既に述べたのでここでは省く. すべての処理を終えると, Decl の意味解析が行われ, その結果が StmtResult として返る. 
-
-\begin{lstlisting}[frame=lrbt,label=DeclStmt,caption={CreateDeclStmt 関数}]
-StmtResult Parser::CreateDeclStmt(IdentifierInfo *II, bool isRetCS, bool copyType, DeclSpec::TST valueType, IdentifierInfo* Name){
-  DeclGroupPtrTy DeclGPT;
-  ParsingDeclSpec DS(*this);
-  setTST(&DS, valueType, Name);
-  ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Declarator::BlockContext));
-  D.SetIdentifier(II, Loc);
-
-        :
-
-  SmallVector<Decl *, 8> DeclsInGroup;
-  Decl *FirstDecl;
-  
-  if (copyType)
-    FirstDecl = HandleDeclAndChangeDeclType(D);
-  else
-    FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
-  
-  D.complete(FirstDecl);
-  DeclsInGroup.push_back(FirstDecl);
-  DeclGPT =  Actions.FinalizeDeclaratorGroup(getCurScope(), *DSp, DeclsInGroup);
-  return Actions.ActOnDeclStmt(DeclGPT, Loc, Loc);
-}
-\end{lstlisting}
-
-つづいて両予約語解析時に共通するもう一つの処理, 代入文の生成について説明する. 今回の実装ではこの処理を以下のリスト \ref{assignment} に示す CreateAssginmentStmt 関数にまとめた. ここでも重要でない処理は省いている. この関数は引数として左辺,右辺の変数名と, 左辺が構造体のメンバかどうか, 右辺が演算子 \& を持つかどうか, 左辺が構造体だった場合の構造体名を求める. 8 行目から 14 行目までは左辺に対応する ExprResult を取得する処理で, ExprResult は一つの式に対応するクラスである. 同様に, 18 行目が右辺に対応する ExprResult を取得する処理で, 代入式の生成は 20 行目に当たる. ここで生成した ExprResult を ActOnExprStmt に渡すことで, 式として StmtResult に変換される.
-
-\begin{lstlisting}[frame=lrbt,label=assignment,caption={CreateAssignmentStmt 関数}]
-StmtResult Parser::CreateAssignmentStmt(IdentifierInfo* LHSII, IdentifierInfo* RHSII, bool LHSisMemberAccess, bool RHShasAmp,
-					IdentifierInfo* extraLHSII){
-  ExprResult Expr,LHS,RHS;
-  Token Next,LHSToken;
-
-        :
-
-  ExternalSpace::StatementFilterCCC Validator(Next);
-  Sema::NameClassification Classification = Actions.ClassifyName(getCurScope(), SS, LHSII, Loc, Next, false, SS.isEmpty() ? &Validator : 0);
-  setExprAnnotation(LHSToken, Classification.getExpression());
-  LHSToken.setAnnotationEndLoc(Loc);
-  PP.AnnotateCachedTokens(LHSToken);
-  
-  LHS = getExprAnnotation(LHSToken);
-
-        :
-  
-  RHS = LookupNameAndBuildExpr(RHSII);
-
-  Expr = Actions.ActOnBinOp(getCurScope(), Loc,tok::equal,LHS.take(),RHS.take());
-  
-  return Actions.ActOnExprStmt(Expr);
-}
-\end{lstlisting}
-
-さて, 残る if 文の自動生成についてであるが, これは if 文のためのスコープを生成した後条件文を作り, その後 if 文内のスコープを作りそこに文を生成していくことで行える. この処理は前述した code segment の生成に含まれる処理に酷似する. したがってここではその説明を省略する. 
-
 \section{プロトタイプ宣言の自動化}
 プロトタイプ宣言の自動化は本研究で追加された機能である. CbC の code segment の処理単位は小さく, そのままでは大量のプロトタイプ宣言を書く必要があり, 好ましくない. また, tail call elimination 強制のために付加した fastcc は正確にプロトタイプ宣言を書くことを要求する. つまりプロトタイプ宣言を自動的に行うようにすることで fastcc の条件を安定して満たすことができ, さらにプログラマは大量のプロトタイプ宣言を書く必要がなくなるのである.
 
--- a/paper/chapter5.tex	Tue Feb 09 17:40:53 2016 +0900
+++ b/paper/chapter5.tex	Tue Feb 09 21:25:40 2016 +0900
@@ -1,7 +1,7 @@
 \chapter{評価・考察}
 今回の研究により実装した LLVM/clang 上での CbC コンパイラの評価を試みる. 評価は, コンパイルして出力されたアセンブリコードの確認と, CbC プログラムを Micro-C, GCC, LLVM でコンパイルして得られたプログラムの実行速度を計測により行う. 
 \section{アセンブリコードの評価}
-以下のリスト \ref{evalCbC},\ref{evalAsmB}, \ref{evalAsmA} はそれぞれコンパイル前の CbC の code segment とコンパイル後のアセンブリコードを示している. \ref{evalAsmB} は omit leaf frame pointer 強制前のアセンブリコード, \ref{evalAsmA} は omit leaf frame pointer 強制後のアセンブリコードである. 
+以下のリスト \ref{evalCbC},\ref{evalAsmB}, \ref{evalAsmA} はそれぞれコンパイル前の CbC の code segment とコンパイル後のアセンブリコードを示している. リスト \ref{evalAsmB} は omit leaf frame pointer 強制前のアセンブリコード, リスト \ref{evalAsmA} は omit leaf frame pointer 強制後のアセンブリコードである. リスト \ref{evalAsmB} には push, pop 命令によるフレームポインタの操作が入っているのに対し, リスト \ref{evalAsmA} にはその操作がない. このことから, omit leaf frame pointer が正しく動作していることがわかる. 
 \begin{lstlisting}[frame=lrbt,label=evalCbC,caption={コンパイル前}]
 __code f(int i,stack sp) {
   int k,j;
@@ -32,7 +32,7 @@
 	.cfi_endproc
 \end{lstlisting}
 
-\begin{lstlisting}[frame=lrbt,label=evalAsmB,caption={omit leaf frame pointer 強制後}]
+\begin{lstlisting}[frame=lrbt,label=evalAsmA,caption={omit leaf frame pointer 強制後}]
 _f:                                     ## @f
 	.cfi_startproc
 ## BB#0:                                ## %entry
@@ -49,6 +49,7 @@
 	.cfi_endproc
 \end{lstlisting}
 
-\section{性能評価}
+\section{実行速度の評価}
+\section{C, ruby, アセンブラ, Scheme との比較}
 \section{LLVM, clangの利点}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/paper/gotoWithEnv.tex	Tue Feb 09 21:25:40 2016 +0900
@@ -0,0 +1,382 @@
+\chapter{環境付き継続の実装}
+環境付き継続を行うためには \_\_return, \_\_environment という特殊変数を用い, この実装にはいくつかの方法がある. GCC コンパイラでは nested function を, 以前の LLVM, Clang CbC コンパイラでは setjmp, longjmp を使用して実装を行っていた. これら二つの方法に加えて本研究では LLVM builtin の setjmp, longjmp を利用する実装を行った. 本章ではそれぞれに実装について述べる.
+
+\section{nested function による実装}
+GCC 上に実装した CbC コンパイラでは nested function を利用して環境付き継続の実装を行った. 実装の詳細は本論文の趣旨から大きくそれるので, どのようにじつげんしているかについてのみ記す.
+
+具体的には, リスト\ref{code:cbcreturn2}の関数funcBをコンパイラは次のコード\ref{code:nestedcode}の様に解釈し, 内部コードセグメントを自動生成する.
+
+
+
+6 行目から 20 行目が GCC により追加される処理である. 内部コードセグメント\verb|inner|は受け取った引数を関数の返り値として保持し, ラベル\verb|label|に jumpする. この時点で内部コードセグメントを抜けて元の関数 int の環境に復帰する.
+
+さらに jump 先も GCC により自動で追加される. しかしこの jump 先は\verb|inner|以外からは実行してはならない. そのため条件式が真にならない if 文で囲み、実行を回避している. jump 先での処理は, \verb|inner|内で代入された値を持ってリターンするのみである.
+
+\begin{lstlisting}[frame=lrbt,label=code:cbcreturn2,caption={環境付き継続の例}]
+__code cs(int retval,__code(*ret)(int,void *),void *env){
+  goto ret(n, env);
+}
+
+int func (){
+  goto cs(30, __return, __environment);
+  return 0;
+}
+\end{lstlisting}
+
+\begin{lstlisting}[frame=lrbt,label=code:nestedcode,caption={内部での解釈}]
+__code cs(int retval,__code(*ret)(int,void *),void *env){
+  goto ret(n, env);
+}
+
+int func (){
+  code (*ret)(int);
+  int retval;
+  __code inner(int val){
+    retval = val;
+    goto label;
+  }
+  if(0){
+    label:
+    return retval;
+  }
+  ret = inner;
+
+  goto cs(30, ret);
+  return 0;
+}
+ \end{lstlisting}
+
+\section{setjmp, longjmp による実装}
+nested function は clang, llvm が対応しておらず, 別の方法を取る必要があった. 過去の研究においてこの機能は実装されたが, その際には setjmp, longjmp を用いた実装を行った. 
+
+環境付き継続は, \_\_return, \_\_environment が使用された時に自動的にあるコードを生成することで実現される. 具体的には, リスト \ref{autoCodeGenB} のようなコードをコンパイルした場合にリスト \ref{autoCodeGenA} のように解釈することで実現される. 
+
+\begin{lstlisting}[frame=lrbt,label=autoCodeGenB,caption={環境付き継続の例}]
+__code cs(int retval,__code(*ret)(int,void *),void *env){
+  goto ret(n, env);
+}
+
+int func (){
+  goto cs(30, __return, __environment);
+  return 0;
+}
+\end{lstlisting}
+\begin{lstlisting}[frame=lrbt,label=autoCodeGenA,caption={内部での解釈}]
+#include <setjmp.h>
+
+struct CbC_env {
+  void *ret_p,*env;
+};
+
+__code cs(int retval,__code(*ret)(int,void *),void *env){
+  goto ret(n, env);
+}
+
+__code return1 (int retval, void* env){
+  *(int*)((struct CbC_env *)(env))->ret_p = retcal;
+  longjmp((int*)(((struct CbC_env *)env)->env),1);
+}
+
+int func (){
+  __code (*__return)();
+  struct CbC_env __environment;
+  jmp_buf env;
+  int retval;
+  __environment.ret_p = &retval;
+  __environment.env = &env;
+  __return = return1;
+    if (setjmp(__environment.env)){
+      return retval;
+    }
+  goto code1(30, __return, &__environment);
+  return 0;
+}
+\end{lstlisting}
+
+追加された処理は, setjmp ヘッダのインクルード, 環境と戻り値を保持する構造体 CbC\_env の定義, 元の環境に戻るための特殊 code segment return1 の定義, そして関数 func 内の 17 行目から 26 行目までの処理であり, 27 行目の継続の第三引数も参照渡しに変更される. 追加された処理の大まかな流れを説明する. 環境付き継続を用いる関数は継続前に setjmp を用いて戻り先の環境を保存し, 継続を行う. このとき, 引数として渡される \_\_return には特殊 code segment return1 のアドレス, \_\_environment の持つメンバには戻り値として返される値を持つ変数のアドレスと, setjmp により保存された継続前の環境が保持されている. 元の環境に戻るための code segment は自動生成されるので, 継続先の code segment は返す戻り値と \_\_environemnt を引数として \_\_return の指す code segment を呼び出すだけで元の環境に戻れる. return1 は 構造体の持つ戻り値へのポインタを利用して戻り値を更新した後, longjmp を用いて元の環境に戻る. longjmp によって再度 setjmp の呼び出しに戻るが今回は if文内に入り, 戻り値を返す.
+
+自動生成される文をまとめるといかのようになる.
+
+\begin{itemize}
+  \item \_\_return
+    \begin{itemize}
+    \item 元の環境に戻るための特殊な code segment
+    \item 各変数の宣言及び代入文
+    \end{itemize}
+  \item \_\_environment
+    \begin{itemize}
+    \item 環境を保持する構造体 CbC\_env の定義
+    \item 各変数の宣言及び代入文
+    \item setjmp を条件文にとり, 真の場合に関数の戻り値を返す if文
+    \end{itemize}
+  \item どちらにも依存しない
+    \begin{itemize}
+    \item setjmp.h のインクルード文
+    \end{itemize}
+\end{itemize}
+
+setjmp.h のインクルード文がどちらにも属さないのは, 無条件でこのヘッダをインクルードするようにしてもよいからである. 必要のないコードは最適化によって除去されるので, 使用されない場合でもインクルードして構わない. また, これらの文を生成する際, 元の関数の型の戻り値を返せるようにしなければならないが, \ref{sec:clang} 節で説明したように, clang では型情報を QualType が管理しているので, 生成する関数や変数に対して元の関数の返り値に対応する QualType を与えるだけでこの問題は解決する. 尚, 二つの予約語を登録する処理は既に説明したので省く.
+
+まずはじめに setjmp.h のインクルード文の生成について説明する. clang では include マクロによって他のファイルのインクルードを行う場合, 字句解析対象となるのファイルの変更を行う. 本研究では, これらの処理に必要なものを IncludeHeader という一つの関数にまとめ, それを呼び出すことで任意のファイルをインクルードできるようにした. その関数のうち, 重要な部分を抜き出したものを以下のリスト \ref{IncludeHeader} に示す. この関数は引数に現在の token とインクルードするファイルの名前を求める. まずこの関数は, 現在の token の保存処理を行う. これは, この関数が呼ばれた時点で取得された token はすでに字句解析対象のバッファから取り除かれており, これを保存しておかないとインクルード処理終了後の構文解析に影響が出るために行っている. 次に, 指定されたファイルの検索を行う. その処理を行っているのは 11行目であり, このときファイルが見つからなかった場合には NULL が返るので, これを利用してエラーの生成も行っている. 解析対象の変更を行っているのが 16行目以降の処理で, 実際にファイルを移っているのは 18行目の EnterSourceFile 関数である. この関数によって字句解析対象が現在のファイルから指定したファイルへと変更される. また, この関数の戻り値はファイルのインクルード処理を行ったかどうかを判断するために用いる. 
+
+\begin{lstlisting}[frame=lrbt,label=IncludeHeader,caption={IncludeHeader 関数}]
+bool Preprocessor::IncludeHeader(Token Tok, const char* Name) {
+  if (SavedTokenFlag) // If the lexer has already entered a header file, we have to leave this function.
+    return false;
+  SourceLocation Loc = Tok.getLocation();
+  SavedToken = Tok;
+  SavedDepth = IncludeMacroStack.size();
+  SavedTokenFlag = true;
+
+       :
+
+  const FileEntry *File = LookupFile(Loc, Filename, isAngled, LookupFrom, CurDir, NULL, NULL,
+				     HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
+
+       :
+
+  FileID FID = SourceMgr.createFileID(File, Loc, FileCharacter);      
+  EnterSourceFile(FID, CurDir, FilenameTok.getLocation(), static_cast<bool>(BuildingModule));
+  return true;
+}
+\end{lstlisting}
+
+次に, 元の環境に戻るための特殊な code segment の定義生成処理の説明をする. これを行うためには clang の持つ AST に関数の定義を加えてやれば良い. 今回の実装でその処理を担うのが以下のリスト \ref{return1} に示される CreateRetCS 関数である. ただしここでは重要でない箇所を省いている. この関数は引数として生成する関数の名前を受け取る. 2, 3 行目が元の関数の QualType を取得する処理である. 5 行目から 14 行目までの処理は関数宣言のためにスコープをグローバルスコープに変更するための処理で, すべての処理を終えた後, 59 行目から 62 行目の処理によって元のスコープに戻す. 16 行目から 42 行目までが関数のプロトタイプ宣言に関する設定処理を行っており, 29 行目で 取得しておいた QualType を利用していることがわかる. 44 行目からが関数の持つ処理の定義を指定する部分にあたり, 52 行目にある StmtVector クラスのインスタンスに対して任意の文に対応する StmtResult を追加し, 54 行目の関数を呼び出すと戻り値としてこの関数の中身を表す StmtResult を得ることができる. その後これを定義や宣言を管理するクラスである Decl へと変換し, 58 行目の関数を呼び出すことで生成した関数の定義が AST に追加される. 
+
+\begin{lstlisting}[frame=lrbt,label=return1,caption={CreateRetCS 関数}]
+bool Parser::CreateRetCS(IdentifierInfo *csName){
+  FunctionDecl *CurFunctionDecl = Actions.getCurFunctionDecl();
+  QualType CurFuncResQT = CurFunctionDecl->getResultType();
+
+  Scope *SavedScope = getCurScope();
+  DeclContext *SavedContext = Actions.CurContext;
+  TypeSourceInfo *CurFuncTI = Actions.Context.CreateTypeSourceInfo(CurFuncResQT);
+  sema::FunctionScopeInfo *SavedFSI = Actions.FunctionScopes.pop_back_val();
+
+  Actions.CurContext = static_cast<DeclContext *>(Actions.Context.getTranslationUnitDecl());
+  Scope *TopScope = getCurScope();
+  while(TopScope->getParent() != NULL)
+    TopScope = TopScope->getParent();
+  Actions.CurScope = TopScope;
+
+  DeclGroupPtrTy returnDecl = DeclGroupPtrTy();
+  ParsingDeclSpec PDS(*this);
+  setTST(&PDS, DeclSpec::TST___code);
+  ParsingDeclarator D(*this, PDS, static_cast<Declarator::TheContext>(Declarator::FileContext));
+  D.SetIdentifier(csName, Loc);
+  ParseScope PrototypeScope(this,Scope::FunctionPrototypeScope|Scope::DeclScope|Scope::FunctionDeclarationScope);
+  SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+  DeclSpec FDS(AttrFactory);
+  ParmVarDecl *Param;
+		
+  IdentifierInfo *retvalII = CreateIdentifierInfo(__CBC_RETVAL_NAME, Loc);
+  Param = CreateParam(retvalII);
+  Param->setTypeSourceInfo(CurFuncTI);
+  Param->setType(CurFuncResQT);
+
+  ParamInfo.push_back(DeclaratorChunk::ParamInfo(retvalII, Loc, Param, 0));
+  IdentifierInfo *envII = CreateIdentifierInfo(__CBC_STRUCT_ENV_NAME, Loc);
+  Param = CreateParam(envII, 1, DeclSpec::TST_void);
+  ParamInfo.push_back(DeclaratorChunk::ParamInfo(envII, Loc, Param, 0));
+
+  D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, IsAmbiguous, Loc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, Loc,
+					     FDS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, ConstQualifierLoc,
+					     VolatileQualifierLoc, SourceLocation(), ESpecType, ESpecRange.getBegin(),
+					     DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(),
+					     NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0,
+					     Loc, Loc, D, TrailingReturnType), FnAttrs, Loc);
+  PrototypeScope.Exit();
+	
+  Decl *TheDecl;
+  ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+  Decl *BodyRes = Actions.ActOnStartOfFunctionDef(getCurScope(), D);
+
+  D.complete(BodyRes);
+  D.getMutableDeclSpec().abort();
+  Actions.ActOnDefaultCtorInitializers(BodyRes);
+  StmtResult FnBody;
+  StmtVector FnStmts;
+  /* add function body statements */
+  FnBody = Actions.ActOnCompoundStmt(Loc, Loc, FnStmts, false);
+  BodyScope.Exit();
+  TheDecl = Actions.ActOnFinishFunctionBody(BodyRes, FnBody.take());
+  returnDecl =  Actions.ConvertDeclToDeclGroup(TheDecl);
+  (&Actions.getASTConsumer())->HandleTopLevelDecl(returnDecl.get());
+  Actions.CurScope = SavedScope;
+  Actions.CurContext = SavedContext;
+  Actions.FunctionScopes.push_back(SavedFSI);
+  return false;
+}
+\end{lstlisting}
+
+つづいて構造体 CbC\_env の定義を行う. この構造体は setjmp, longjmp が環境の保持に使う jmp\_buf へのポインタと元の関数の戻り値となる変数へのポインタを持つ. 構造体の宣言は通常, 構文解析器によって Decl というクラスのインスタンスが生成され, それを利用して行う. 今回の実装では Decl の生成を手書きのコードで行うことで, 自動で構造体の定義を行う処理を実現した. 今回の実装ではそのコード群を Create\_\_CbC\_envStruct という一つの関数にまとめた. その関数のうち,重要な部分を抜き出したものを以下のリスト \ref{CbC_env} に示す. この関数はソースコードの位置と C++ で用いられるアクセス修飾子を引数に取る. この関数もスコープを変更する処理を持つが, それについては先ほど説明したので省いている. 12 行目から 22 行目までが, この構造体の Decl を生成する処理である. メンバの設定を行っているのが 27 行目から 30 行目で, ここで使用している Create\_\_CbC\_envBody 関数はメンバの宣言を行うために独自に作成した関数である. 構造体のメンバとして宣言するために ActOnField という Sema クラスの関数を呼び出す以外は後述する CreateDeclStmt 関数と処理内容にあまり差が無いため, この関数については本論文では説明を省く. 32 行目で呼び出している ActOnTagFinishDefinision が, 生成した Decl を元に構造体の宣言の意味解析を行ってくれる関数である. これにより, 生成した構造体に対応する Type も生成される. 
+
+\begin{lstlisting}[frame=lrbt,label=CbC_env,caption={Create\_\_CbC\_envStruct 関数}]
+void Parser::Create__CbC_envStruct(SourceLocation Loc, AccessSpecifier AS) {
+
+          :
+
+  ParsingDeclSpec SDS(*this);
+  DeclSpec::TST TagType = DeclSpec::TST_struct;
+  DeclResult TagOrTempResult = true;
+  bool Owned = false;
+  bool IsDependent = false;
+  TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, Sema::TUK_Definition, Loc,
+				     SDS.getTypeSpecScope(), Name, Loc, attrs.getList(), AS,
+				     SDS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent,
+				     SourceLocation(), false, clang::TypeResult());
+
+  Decl *TagDecl = TagOrTempResult.get();
+  ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
+  Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
+  SmallVector<Decl *, 32> FieldDecls;
+
+  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_POINTER_NAME));
+  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_int, Loc, __CBC_STRUCT_ENV_NAME));
+
+  Actions.ActOnFields(getCurScope(),Loc, TagDecl, FieldDecls,Loc, Loc,attrs.getList());
+  StructScope.Exit();
+  Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, Loc);
+
+          :
+}
+\end{lstlisting}
+
+つづいて両予約語解析時に共通する処理の一つである変数の定義文に関して説明する. これも定義に関する文であるので Decl の生成がメインとなる. 今回の実装では以下のリスト\ref{DeclStmt} に示す CreateDeclStmt という関数を作り, その関数によってその処理を行う. ここでも重要でない処理は省いている. この関数は引数として変数名, code segment へのポインタかどうか, 呼び出し元の関数の型をコピーするかどうか, 変数の型, 構造体だった場合の構造体名を持つ. 4 行目の setTST 関数が指定された型修飾子を設定している箇所である. 変数名は 6 行目の SetIdentifier 関数によって設定され, その後は関数へのポインタだった場合や構造体だった場合のときにのみ行われる処理が来るがここでは省いた. その後型コピーを行うかどうかで処理が異なる. 型コピーの方法については既に述べたのでここでは省く. すべての処理を終えると, Decl の意味解析が行われ, その結果が StmtResult として返る. 
+
+\begin{lstlisting}[frame=lrbt,label=DeclStmt,caption={CreateDeclStmt 関数}]
+StmtResult Parser::CreateDeclStmt(IdentifierInfo *II, bool isRetCS, bool copyType, DeclSpec::TST valueType, IdentifierInfo* Name){
+  DeclGroupPtrTy DeclGPT;
+  ParsingDeclSpec DS(*this);
+  setTST(&DS, valueType, Name);
+  ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Declarator::BlockContext));
+  D.SetIdentifier(II, Loc);
+
+        :
+
+  SmallVector<Decl *, 8> DeclsInGroup;
+  Decl *FirstDecl;
+  
+  if (copyType)
+    FirstDecl = HandleDeclAndChangeDeclType(D);
+  else
+    FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
+  
+  D.complete(FirstDecl);
+  DeclsInGroup.push_back(FirstDecl);
+  DeclGPT =  Actions.FinalizeDeclaratorGroup(getCurScope(), *DSp, DeclsInGroup);
+  return Actions.ActOnDeclStmt(DeclGPT, Loc, Loc);
+}
+\end{lstlisting}
+
+つづいて両予約語解析時に共通するもう一つの処理, 代入文の生成について説明する. 今回の実装ではこの処理を以下のリスト \ref{assignment} に示す CreateAssginmentStmt 関数にまとめた. ここでも重要でない処理は省いている. この関数は引数として左辺,右辺の変数名と, 左辺が構造体のメンバかどうか, 右辺が演算子 \& を持つかどうか, 左辺が構造体だった場合の構造体名を求める. 8 行目から 14 行目までは左辺に対応する ExprResult を取得する処理で, ExprResult は一つの式に対応するクラスである. 同様に, 18 行目が右辺に対応する ExprResult を取得する処理で, 代入式の生成は 20 行目に当たる. ここで生成した ExprResult を ActOnExprStmt に渡すことで, 式として StmtResult に変換される.
+
+\begin{lstlisting}[frame=lrbt,label=assignment,caption={CreateAssignmentStmt 関数}]
+StmtResult Parser::CreateAssignmentStmt(IdentifierInfo* LHSII, IdentifierInfo* RHSII, bool LHSisMemberAccess, bool RHShasAmp,
+					IdentifierInfo* extraLHSII){
+  ExprResult Expr,LHS,RHS;
+  Token Next,LHSToken;
+
+        :
+
+  ExternalSpace::StatementFilterCCC Validator(Next);
+  Sema::NameClassification Classification = Actions.ClassifyName(getCurScope(), SS, LHSII, Loc, Next, false, SS.isEmpty() ? &Validator : 0);
+  setExprAnnotation(LHSToken, Classification.getExpression());
+  LHSToken.setAnnotationEndLoc(Loc);
+  PP.AnnotateCachedTokens(LHSToken);
+  
+  LHS = getExprAnnotation(LHSToken);
+
+        :
+  
+  RHS = LookupNameAndBuildExpr(RHSII);
+
+  Expr = Actions.ActOnBinOp(getCurScope(), Loc,tok::equal,LHS.take(),RHS.take());
+  
+  return Actions.ActOnExprStmt(Expr);
+}
+\end{lstlisting}
+
+if 文の自動生成についてであるが, これは if 文のためのスコープを生成した後条件文を作り, その後 if 文内のスコープを作りそこに文を生成していくことで行える. この処理を実現する関数がリスト \ref{} である. この処理は前述した code segment の生成に含まれる処理に酷似する. したがってここではその説明を省略する. 
+
+\begin{lstlisting}[frame=lrbt,label=assignment,caption={CreateAssignmentStmt 関数}]
+  StmtResult Parser::CreateSjForContinuationWithTheEnv(){
+    SourceLocation Loc = Tok.getLocation();
+    StmtResult IfRes;
+    ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, true/* C99 or CXX */);
+    ExprResult CondExp;
+    Decl *CondVar = 0;
+
+    CondExp = LookupNameAndBuildExpr(CreateIdentifierInfo(``setjmp'', Loc));
+    ExprVector ArgExprs;
+    ExprResult __envExprRes = CondExp.get();
+
+    __envExprRes = LookupNameAndBuildExpr(CreateIdentifierInfo(__CBC_ENVIRONMENT_NAME, Loc));
+    __envExprRes = LookupMemberAndBuildExpr(CreateIdentifierInfo(__CBC_STRUCT_ENV_NAME, Loc), __envExprRes.get(), false);
+
+    ArgExprs.push_back(__envExprRes.get());
+    CondExp = Actions.ActOnCallExpr(getCurScope(), CondExp.get(), Loc, ArgExprs, Loc, 0);
+    CondExp = Actions.ActOnBooleanCondition(getCurScope(), Loc, CondExp.get());
+
+    FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get(), Loc));
+    ParseScope InnerScope(this, Scope::DeclScope,false);
+    SourceLocation InnerStatementTrailingElseLoc;
+
+    StmtResult StmtRes;
+    ParseScope CompoundScope(this, Scope::DeclScope);
+    PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),Loc,''in create setjmp statement for CbC'');
+    StmtVector innerStmts;
+    StmtResult innerStmtRes;
+    ExprResult innerExprRes;
+    innerExprRes = LookupNameAndBuildExpr(CreateIdentifierInfo(__CBC_RETVAL_NAME, Loc));
+    innerStmtRes = Actions.ActOnReturnStmt(Loc, innerExprRes.get(), getCurScope());
+    if (innerStmtRes.isUsable())
+    innerStmts.push_back(innerStmtRes.get());
+    StmtRes = Actions.ActOnCompoundStmt(Loc, Loc,innerStmts, false);
+    StmtResult ThenStmt(StmtRes);
+    InnerScope.Exit();
+    IfScope.Exit();
+    StmtResult ElseStmt;
+    IfRes = Actions.ActOnIfStmt(Loc, FullCondExp, CondVar, ThenStmt.get(),Loc, ElseStmt.get());
+    return IfRes;
+  }
+\end{lstlisting}
+
+\section{\_\_builtin\_setjmp, \_\_builtin\_longjmp を用いた実装}
+本研究では llvm, clang 上に実装した CbC の環境付き継続に, \_\_builtin\_setjmp, \_\_builtin\_longjmp を用いるように変更を加えた. これらの関数は LLVM builtin の関数であり, setjmp, longjmp よりも軽量なものであり, 互換性もある.
+
+これらの関数を利用するために変更を加えなければならないのは以下の二点である.
+
+\begin{itemize}
+\item 使用する関数名の変更
+\item \_\_builtin\_setjmp 用に生成するコードの引数の型を変更
+\end{itemize}
+
+使用する関数名の変更は単純に与える文字列を変更すれば良い. なのでこの説明については省く.
+
+引数の型について, setjmp も \_\_builtin\_setjmp も引数として jmp\_buf を受け取るが, setjmp が int** で受けるのに対して, \_\_builtin\_setjmp は void** で受ける. そのままでもコンパイル及び実行は可能であるが, コンパイルするたびに警告文が出るのでよろしくない. そのため void** で jmp\_buf を持つように変更を加え, 警告文が出ないよう変更した. 
+
+変更を行うのはリスト \ref{CbC_env} に示した Create\_\_CbC\_envStruct の一部だけで良い. 変更前がリスト \ref{typeB}, 変更後がリスト \ref{typeA} である. TST\_int を TST\_void に変えただけで他に変更を加える必要はない. これは \ref{sec:clang} 節で説明したとおり, clang が型の表現を QualType を使って簡潔にしている恩恵だと言える.
+\begin{lstlisting}[frame=lrbt,label=typeB,caption={CreateAssignmentStmt 関数変更前}]
+void Parser::Create__CbC_envStruct(SourceLocation Loc, AccessSpecifier AS) {
+
+          :
+
+  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_POINTER_NAME));
+  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_int, Loc, __CBC_STRUCT_ENV_NAME));
+
+          :
+}
+\end{lstlisting}
+
+\begin{lstlisting}[frame=lrbt,label=typeA,caption={CreateAssignmentStmt 関数変更後}]
+void Parser::Create__CbC_envStruct(SourceLocation Loc, AccessSpecifier AS) {
+
+          :
+
+  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_POINTER_NAME));
+  FieldDecls.push_back(Create__CbC_envBody(TagDecl, DeclSpec::TST_void, Loc, __CBC_STRUCT_ENV_NAME));
+
+          :
+}
+\end{lstlisting}
Binary file paper/master_paper.pdf has changed
--- a/paper/master_paper.tex	Tue Feb 09 17:40:53 2016 +0900
+++ b/paper/master_paper.tex	Tue Feb 09 21:25:40 2016 +0900
@@ -7,7 +7,7 @@
 \usepackage{comment}
 %\input{dummy.tex} %% font
 
-\jtitle{LLVM, Clang 上の Continuation based C コンパイラの改良}
+\jtitle{LLVM Clang 上の Continuation based C コンパイラの改良}
 \etitle{Improvement of Continuation based C compiler on LLVM and Clang}
 \year{2016年 3月}
 \eyear{March 2016}
@@ -26,7 +26,7 @@
 \end{minipage}}
 \markleftfoot{% 左下に挿入
   \begin{minipage}{.8\textwidth}
-    LLVM, Clang 上の Continuation based C コンパイラの改良
+    LLVM Clang 上の Continuation based C コンパイラの改良
 \end{minipage}}
 
 \newcommand\figref[1]{図 \ref{fig:#1}}
@@ -81,6 +81,7 @@
 \input{chapter1.tex}
 \input{chapter2.tex}
 \input{chapter3.tex}
+\input{gotoWithEnv.tex}
 \input{chapter4.tex}
 \input{chapter5.tex}