Mercurial > hg > Papers > 2016 > kaito-master
view slide/blank.html @ 16:bea98599d11f
fix typo
author | Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 14 Feb 2016 20:07:43 +0900 |
parents | 57b390dce7df |
children | 1d151a4d03f6 |
line wrap: on
line source
<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>LLVM, Clang 上の Continuation based C コンパイラの改良</title> <!-- Notes on CSS media types used: 1) projection -> slideshow mode (display one slide at-a-time; hide all others) 2) screen -> outline mode (display all slides-at-once on screen) 3) print -> print (and print preview) Note: toggle between projection/screen (that is, slideshow/outline) mode using t-key Questions, comments? - send them along to the mailinglist/forum online @ http://groups.google.com/group/webslideshow --> <!-- style sheet links --> <link rel="stylesheet" href="themes/blank/projection.css" media="screen,projection"> <link rel="stylesheet" href="themes/blank/screen.css" media="screen"> <link rel="stylesheet" href="themes/blank/print.css" media="print"> <link rel="stylesheet" href="blank.css" media="screen,projection"> <!-- Notes about less css support - all less stylesheets (*.css.less) need to get listed/loaded first (before the less.js script) - find more info about less.js online @ http://lesscss.org ***** NOTE: less.js browser script currently won’t work if you’re using Google Chrome and the path to your page starts with "file:///" due to a known Chrome issue. (In the developer/js console you will see: XMLHttpRequest cannot load file:///../s6/shared/projection.css.less. Cross origin requests are only supported for HTTP.) --> <!-- add js libs (less, jquery) --> <script src="js/less-1.1.4.min.js"></script> <script src="js/jquery-1.7.min.js"></script> <!-- S6 JS --> <script src="js/jquery.slideshow.js"></script> <script src="js/jquery.slideshow.counter.js"></script> <script src="js/jquery.slideshow.controls.js"></script> <script src="js/jquery.slideshow.footer.js"></script> <script src="js/jquery.slideshow.autoplay.js"></script> <script> $(document).ready( function() { Slideshow.init(); // Example 2: Start Off in Outline Mode // Slideshow.init( { mode: 'outline' } ); // Example 3: Use Custom Transition // Slideshow.transition = transitionScrollUp; // Slideshow.init(); // Example 4: Start Off in Autoplay Mode with Custom Transition // Slideshow.transition = transitionScrollUp; // Slideshow.init( { mode: 'autoplay' } ); } ); </script> <!-- Better Browser Banner for Microsoft Internet Explorer (IE) --> <!--[if IE]> <script src="js/jquery.microsoft.js"></script> <![endif]--> </head> <body> <div class="layout"> <div id="header"></div> <div id="footer"> <div align="right"> <img src="fig/concurrency.png" width="200"> </div> </div> </div> <div class="presentation"> <!-- add slides here; example --> <div class='slide cover'> <table width="90%" height="90%" border="0" align="center"> <tr> <td><div align="center"> <h1><font color="#808db5">LLVM, Clang 上の Continuation based C コンパイラの改良</font></h1> </div></td> </tr> <tr> <td><div align="left"> Kaito TOKUMORI <script> var date = new Date(); var year = date.getFullYear(); var month = date.getMonth(); var day = date.getDate(); var monthList = new Array("January","February","March","April","May","June", "July","August","September","October","November","December"); document.write(monthList[month]+" "+day+", "+year); </script> <hr style="color:#ffcc00;background-color:#ffcc00;text-align:left;border:none;width:300%;height:0.2em;"> </div></td> </tr> </table> </div> <div class='slide'> <h2>code segment を用いるプログラミング言語 CbC</h2> <p>関数やクラス、オブジェクト等は分割、結合を行うことは困難である。</p> <p>アセンブリは分割、結合が可能だが易しくない。</p> <p>当研究室ではプログラムを code segment、data segmentという単位を用いて書くという手法を提案しており、Cerium, Continuation based C(CbC)等がそれらを利用する。</p> <p>それぞれの単位は分割と結合を行うことが可能で、プログラムの分割、結合を容易にする。</p> <p>それぞれの単位はメタレベルのものが存在し, メタ計算の記述も可能である。</p> </div> <div class='slide'> <h2>Continuation based C(CbC)</h2> <ul> <li>基本的な構文は C と同じ <li>CbC は code segment を処理の基本単位とする <li>goto による軽量継続を用いて処理を行う </ul> </div> <div class='slide'> <h2>コード例</h2> <table border='1' align='center' width='80%'> <tr><td width='50%'> <pre class='small_code'> __code f() { goto g(); } __code g() { goto h(); } </pre> </td><td valign='top'> <ul> <li>__code は code segment であることを示す <li>code segment は返り値を持たない <li>軽量継続は goto のとなりに code segment 名と引数を書く </ul> </td></tr> </table> </div> <div class='slide'> <h2>CbC コンパイラ</h2> <ul> <li>Micro-C <li>GCC <li>LLVM clang </ul> </div> <div class='slide'> <h2>LLVM Clang</h2> <ul> <li>LLVM はコンパイラバックエンド <ul> <li>LLVM IR をターゲットのアセンブリコードに変換する <li>最適化が主な処理 </ul> <li>Clang はC/C++/Obj-C のフロントエンド <ul> <li>対象言語の構文解析を行う. <li>構文解析以後は LLVM を利用する. </ul> </ul> </div> <div class='slide'> <h2>LLVM Clang を用いる利点</h2> <ul> <li>ドキュメントが整っており開発者に優しい <li>複数のアーキテクチャに対応 <li>強力な最適化機構を持つ <li>OS X デフォルトのコンパイラでビルドが GCC と比べ容易 <li>GCC に比べ開発が易しい </ul> </div> <div class='slide'> <h2>LLVM と Clang の 基本構造</h2> <p> clang はソースコードを読み込むと Parser を用いて clangAST を生成する。CodeGenがASTを元にLLVM IRを生成し, それが LLVM の入力に対応する。 </p> <p> LLVM は中間表現の形を何度も変化させる。最適化をかけながら徐々にターゲットへの依存度が高くし、最終的にアセンブリコードや実行可能ファイルを出力する。最適化を含む全ての処理がパスによって行われる。 </p> <div align="center"><img src="fig/clang_llvm_structure.svg" width="45%"></div> </div> <div class='slide'> <h2>LLVM と Clang のもつ 中間表現</h2> <ul> <li>clangAST : 抽象構文木。各ノードが式や文、値等に対応する。 <li>LLVM IR : LLVM の入力。LLVM 言語とも呼ばれる。メインの中間表現。 <li>SelectionDAG : 各ノードが命令や演算子に対応する有向非巡回グラフ。 <li>Machine Code : アセンブリコードとは異なる。レジスタの割当などはここで行う。 <li>MC Layer : 正確には中間表現を扱う層。一つの命令や演算子に対応するクラスを持ち、様々な出力を同様のAPIを用いて行える。 </ul> <div align="center"><img src="fig/clang_llvm_structure.svg" width="45%"></div> </div> <div class='slide'> <h2>LLVM IR</h2> <ul> <li>LLVM bitcode とも呼ばれる <li>人が読みやすいアセンブリ言語形式、ビットコード、実行時のメモリ上の形式の3つの形式を持つ <li>関数呼び出しに、呼び出し規約等のフラグをもつ </ul> <table width='100%'> <tr> <td style="border: double;"> <pre class='code'> define fastcc void @factorial(i32 %x) #0 { entry: tail call fastcc void @factorial0(i32 1, i32 %x) ret void } </pre> </td> </tr> </table> </div> <div class='slide'> <h2>CbC 実装概要</h2> <ul> <li>code segment は __code 型の関数とする <li>軽量継続は tail call elimination の強制によって実現 <li>code segment はプロトタイプ宣言を必要としない <li>LLVM IR に変更を加えない </ul> </div> <div class='slide'> <h2>__code 型</h2> <ul> <li>__code 型の値を返す関数というわけではなく code segment を示すフラグとする <li>code segment は戻り値を持たないので void 型と同様に実装する <li>LLVM IR として出力した際にも void になる </ul> </div> <div class='slide'> <h2>goto code_segment();</h2> <ul> <li>code segment のための goto syntax の追加 <li>通常の関数呼び出しと同じように実装し、 tail call elimination を強制することで軽量継続にする <li>AST生成の時点では関数呼び出しの直後に return 文を付加するだけ </ul> <table border='1' width='80%' align='center'> <tr> <td>元のコード <td>生成される AST に対応するコード </tr> <tr> <td><pre class='small_code'> __code code1() { : goto code2(); } </pre> <td><pre class='small_code'> void code1() { : code2(); <font color='red'>return;</font> } </pre> </tr> </table> </div> <div class='slide'> <h2>プロトタイプ宣言の自動生成</h2> <ul> <li>CbC では code segment を大量に書くことになるがそのたびにプロトタイプ宣言を書くのは手間 <li>軽量継続を解析する時にプロトタイプ宣言の有無を調べ、存在しなかった場合に code segment の定義をもとに自動で生成する <li>自分で書いてもいい </ul> <table border='1' width='80%' align='center'> <tr> <td>元のコード <td>生成される AST に対応するコード </tr> <tr> <td><pre class='small_code'> __code code1(int a, int b) { : goto code2(a,b); } __code code2(int a, int b){ : } </pre> <td><pre class='small_code'> <font color='red'>__code code2(int a, int b);</font> __code code1(int a, int b) { : goto code2(a,b); } __code code2(int a, int b){ : } </pre> </tr> </table> </div> <div class='slide'> <h2>tail call elimination の強制</h2> <ul> <li>__code 型の関数 (= code segment) に tail call elimination を強制 <li>TailCallElim というパスを利用する <li>いくつかの条件を満たさなければならない </ul> </div> <div class='slide'> <h2>tail call elimination</h2> <ul> <li>tail call に対する最適化 <li>tail call は関数の最後に位置する関数呼び出し <li>通常関数は call 命令で呼び出されるが tail call elimination によって jmp 命令を用いるようになる </ul> <div align='center'><img src="fig/TCE.svg" width="40%"></div> </div> <div class='slide'> <h2>tail call elimination の強制</h2> <ul> <li>常に TailCallElim パスを追加 <li>常に tailcallopt を有効化 <li>最適化レベルにかかわらず code segment に対して処理を行う <li>code segment の呼び出し規約に常に fastcc を付加 <li>全ての code segment の型は void (__code) で統一 </ul> </div> <div class='slide'> <h2>CbC から生成される LLVM IR</h2> <ul> <li>軽量継続は tail, fastcc 付きの void 型の関数呼び出しに <li>LLVM IR への変更は一切ない </ul> <table border='1' width='80%' align='center'> <tr> <td>元のコード <td>LLVM IR </tr> <tr> <td><pre class='small_code'> __code code1() { : goto code2(); } __code code2(){ : } </pre> <td><pre class='small_code'> define fastcc void @code1() #0 { entry: : <font color='red'>tail call fastcc void</font> @code2() ret void } define fastcc void @code2() #0 { : } </pre> </tr> </table> </div> <div class='slide'> <h2>環境付き継続</h2> <ul> <li>code segment から 関数に戻るための継続 <li>通常 code segment は環境を保持しないので前の関数に戻ることが出来ない <li>継続前の環境を __environment, 継続前の環境に戻るための code segment を __return に保存し, これらを利用して関数に戻る </ul> </div> <div class='slide'> <h2>環境付き継続の例</h2> <table width='100%'> <tr><td valign='top'> <ul> <li>__return と __environment を用いる <li>__return は funcB へ戻るための code segment <li>__environment は funcB の環境 <li>この例では funcB が -1 でなく 1 を返す </ul> <td style="border: double;"> <pre class='small_code'><div class='highlight'>__code cs(__code(*ret)(int,void *),void *env){ goto ret(1,env); } int funcB(){ goto cs(__return, __environment); /* never reached */ return -1; } int funcA(){ int retval; retval = funcB(); printf("return = %d\n",retval); return 0; } </div></pre> </tr> </table> </div> <div class='slide'> <h2>環境付き継続実装方法</h2> <ul> <li>llvm builtin setjmp/longjmp (LLVM) <li>setjmp/longjmp (LLVM old) <li>nested function (GCC) <li>アセンブリコードを用いた直接的なポインタ, 値の操作 (Micro-C) </ul> </div> <div class='slide'> <h2>LLVM Clang 上での環境付き継続実装の問題</h2> <ul> <li>__return として利用する code segment の名前が一意にならなければならない. <li>継続前の C の関数の型に応じて返す値の型を変化させなければならない. </ul> </div> <div class='slide'> <h2>code segment 名の問題の解決法</h2> <ul> <li>C の仕様では関数名に '.' (ドット) を使用することは出来ないが、LLVM IR , clang 内部では使用することが出来る <li>戻り先関数名 + '..' + ID という名前にすることで解決 </ul> </div> <div class='slide'> <h2>戻り値の型の問題の解決法</h2> <ul> <li>clang では型情報を QualType という一つのオブジェクトに保存できる. <li>下図は const int * 型に対応する QualType <li>戻り先関数の型に使われている QualType を戻り値を保存する変数の型に利用することで解決 </ul> <div align='center'><img src="fig/qualType.svg" width="80%"></div> </div> <div class='slide'> <h2>LLVM での環境付き継続の実装</h2> <table width='100%'> <tr><td valign='top'> <ul> <li>setjmp.h を自動で include <li>環境を保存するための構造体の生成 <li>C の関数で __builtin_setjmp を生成して環境を保存 <li>__builtin_longjmp を用いて元の環境に戻る code segment を生成 </ul> <td style="border: double;"> <pre class='small_code'><div class='highlight'> #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 func..ret0 (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 = func..ret0; if (__builtin_setjmp(__environment.env)){ return retval; } goto code1(30, __return, &__environment); return 0; } </div></pre> </tr> </table> </div> <div class='slide'> <h2>Gears OS サポート</h2> <ul> <li>Gears OS は CbC で記述された並列フレームワーク <li>通常の CbC には存在しない meta code segment, data segment が存在する <li>現在の CbC だけで記述するのは容易いとは言えない <li>記述を助ける機能が必要 </ul> </div> <div class='slide'> <h2>Gears OS コード例</h2> <table width='100%'> <tr><td valign='top'> <ul> <li>code segment 間の遷移に meta code segment の処理が入る <li>data segment へは context からアクセスできる <li>必要な data segment の取得は stub で行われる <div align="center"><img src="fig/meta.svg" width="90%"></div> </ul> <td style="border: double;"> <pre class='small_code'><div class='highlight'> __code meta(struct Context* context, enum Code next) { goto (context->code[next])(context); } __code code1_stub(struct Context* context) { goto code1(context, &context->data[Allocate]->allocate); } __code code1(struct Context* context, struct Allocate* allocate) { allocate->size = sizeof(long); allocator(context); goto meta(context, Code2); } __code code2(struct Context* context, long* count) { *count = 0; goto meta(context, Code3); } </div></pre> </tr> </table> </div> <div class='slide'> <h2>Gears OS サポート</h2> <ul> <li>Gears OS は CbC で記述された並列フレームワーク <li>通常の CbC には存在しない meta code segment, data segment が存在する <li>現在の CbC だけで記述するのは容易いとは言えない <li>記述を助ける機能が必要 </ul> </div> <div class='slide'> <h2>サポートする機能</h2> <ul> <li>context の隠蔽 <li>meta code segment への自動接続 <li>stub の自動生成 <li>提案した構文に柔軟に対応できるよう python スクリプトでの実装 </ul> </div> <div class='slide'> <h2>Gears OS サポート</h2> <ul> <li>右のコードをスクリプトに通すと左側のコードが生成される <li>meta code segment への継続や引数 context, stub など機械的な処理が取り除かれる <li>特に stub は1つ1つのコードセグメントに対応するので記述するコードセグメントの量が大幅に減る </ul> <table border='1' width='80%' align='center'> <tr> <td>従来のコード <td>記述を簡易化したコード </tr> <tr> <td><pre class='small_code'> __code meta(struct Context* context, enum Code next) { goto (context->code[next])(context); } __code code1_stub(struct Context* context) { goto code1(context, &context->data[Allocate]->allocate); } __code code1(struct Context* context, struct Allocate* allocate) { allocate->size = sizeof(long); allocator(context); goto meta(context, Code2); } __code code2(struct Context* context, long* count) { *count = 0; goto meta(context, Code3); } __code code2_stub(struct Context* context) { goto code2(context, &context->data[Count]->count); } </pre> <td><pre class='small_code'> __code meta(struct Context* context, enum Code next) { goto (context->code[next])(context); } __code code1(struct Allocate* allocate) { allocate->size = sizeof(long); allocator(); goto code2(); } __code code2(long* count) { *count = 0; goto code3(); } </pre> </tr> </table> </div> <div class='slide'> <h2>評価</h2> <ul> <li>出力されるアセンブリコードの確認 <li>環境付き継続の速度比較 <li>C と CbC との比較 </ul> </div> <div class='slide'> <h2>アセンブリコード</h2> <table border='1' width='80%' align='center'> <tr> <td>CbCのコード <td>出力されたアセンブリ </tr> <tr> <td><pre class='small_code'> __code f(int i,stack sp) { int k,j; k = 3+i; goto f_g0(i,k,sp); } </pre> <td><pre class='small_code'> _f: ## @f .cfi_startproc ## BB#0: ## %entry subq $24, %rsp Ltmp9: .cfi_def_cfa_offset 32 movl %edi, %eax addl $3, %eax movq %rsi, 16(%rsp) ## 8-byte Spill movl %eax, %esi movq 16(%rsp), %rdx ## 8-byte Reload addq $24, %rsp <font color='red'>jmp</font> _f_g0 ## TAILCALL .cfi_endproc </pre> </tr> </table> <ul> <li>code segment f_g0 への継続が jmp 命令で行われている <li>push, pop 命令によるフレームポインタの操作が除去されている <li>tail call elimination, omit leaf frame pointer が正しく働いている <li>万が一 tail call elimination に失敗した場合にはエラーメッセージを出す </ul> </div> <div class='slide'> <h2>環境付き継続の速度比較</h2> <ul> <li>環境付き継続を大量に繰り返すプログラムで測定 <li>x86-64 Mac OS X <li>改良前の元の比べて 7 倍近い速度 <li>nested function より高速 <li>最適化を用いることで Micro-C と同等の速度を実現 </ul> <div align="center"><img src="fig/env.svg" width="40%"></div> </div> <div class='slide'> <h2>C, Scheme との速度比較</h2> <ul> <li>四則演算を繰り返し行うプログラム <li>x86-64 Mac OS X <li>Scheme は chicken コンパイラを使用 <li>関数呼び出しよりも軽量継続の方が高速である <li>スタック操作の処理が重たいことがわかる </ul> <div align="center"><img src="fig/comp.svg" width="40%"></div> </div> <div class='slide'> <h2>まとめ</h2> <ul> <li>LLVM clang 上に実装した CbC コンパイラの改良を行った <li>omit leaf frame pointer の強制を行い、軽量継続時のフレームポインタ操作を除去した <li>環境付き継続に builtin の関数を用いることで速度が元の 7 倍になった <li>Gears OS の記述をサポートするスクリプトの作成を行い, data segment, meta code segment を用いる CbC の記述量を減らした <li>C 言語との速度比較では軽量継続が関数呼び出しより高速であるという結果が得られた </ul> </div> <div class='slide'> <h2>今後の課題</h2> <ul> <li>環境付き継続においてアセンブリコードを直接生成するbuiltin 関数の実装 <li>python スクリプトで実装した Gears OS サポート機能を LLVM 上に実装 <li>data segment の signature を利用できる構文の設計・実装 <li>強い最適化がかかった場合でも正しく tail call elimination を行えるよう改善 <li>C に依存しない、code segment, data segment を用いる新しいプログラミング言語の開発 </ul> </div> </div> <!-- presentation --> </bodypp> </html>