Continuation ベーシック 環境付き継続が普通。 schemeとの継続は違う light-weight スタック 会議室 SICP のContinuation Micro-C 2001 年 『GCC上の』をつける。 『行った~』くらいに。赤いみない。 難しいところがどこで、どうやって解決し方。 フルセットのCに C with Continuation それを制限するとContinuation Based Cになる。 より高度に最適化。。。の部分は外す。 どのパス コンパイラは幾つかパスを通る。 そのたんびにTree トレースをだす。 GCC をいじるというのはどういうことなのかをいいたい。 execute_pass_list: 1616 passes.c:1558 execute_one_pass() を読んでないと行けない。 pass_execute pass の前後でデバッグオプションがあるから NEXT_PASS はオプティマイゼーションパス passes.c: do_per_function() IPAモード関数単位でしかコンパイルしない場合…?。 NEXT_PASS OpenMP 様 eh = error handler worn_function_return はcbCなのにreturn NEXT_PASS (pass_build_ssa); 昔はGIMPLEは残っていたけど、消されてはまった。 INter procedure Optimization (ipa) CbC だとほとんど使わないはず。 なので、CbC で書いたほうが性能が悪くなる可能性がある。 SSAからgimpleにもどす。 昔はいきなりRTLに変換していた  SSAをRTLに変換するルーチン cse common se… elimination 共通部分の最適化 pass の中でコード生成されていたと思うので。 最終的にコード生成のところまでいくのはながい。 SSAからgimpleに戻しているところがあるはず… gimple_expand cfg pass_expand から call_expand は gimple から rtl を生成しているはず。 こっから下は rtlをSSAに変換しているアホがいる。 そこのスライドはこのパスにそって説明する必要がある。 pass_expandから上としたは全然ちがう。 call_expandはgimpleだけど途中SSAに変換してgimpleに戻す。 実際にpass_listがあって、そのpass_listの中でexpand_callがどこにあるのかっていうのを説明してほしい。 なぜか、プログラミングシンポジウムはハッカーの為の詳細なので、 GCCを今いじるならどんなふうにいじるのか。 自分が以下にGCCを理解しているのかを行って欲しい。 実際は gotoとなってるけど、単にfactorialと書いたのと同じだよね。 factorial0() goto factorial() だとtail recursive call が矯正される。 右側のgoto はとる。 実際にどんな引数渡しになるのか。 micro-C ベースのやつがレジスタ渡しだったのでださいコンパイラに負けるということになった。 Intel64はレジスタが増えた。レジスタ16になったから増えた。 basic.c は引数渡しに使われるレジスタの数を調べる。 表にする。 i386 ia64 引数は浮動小数点と整数があるよね。その浮動小数点と整数の2つを。 環境付き継続がの説明のスライド。 本来はクロージャである必要はない。 GCCで setjmpで実装しても問題はあまり変わらなくて。 それでどうなるか、static を使うと thread local な static だったらうまくいくのでは。 setjmpでない普通のやつを先に。 setjmpのソースは どうやって生成しているかのソースを内部的に生成しているのをみせてもいいと。 問題は return val 。だから意味がない。 setjmp 重要なのはretval。 これでない 問題はreturn val がmainの中の環境にある。 これが普通のローカル変数だと、tail recurcive でぬけると駄目になる。だからstatic にしないといけない。 static にすればこれを なぜまずかったのか。mainから tail recursive call で抜けてるからまずい。普通にcallすれば生きてるので、 クロージャを使ってうまくできると… mainで抜ける所で goto は二種類。 普通の関数からgotoする場合。 コードセグメントからgotoする場合で実装が違う。 statci tls をスレッドローカルにすればいんだけど、実際には決まったレジスタにすればいい。 レジスタとは->リターンするレジスタ 書きこむ先は相手側にあるので関係ない。 それをそっちの方にコピーするってのはどっかそのへんでやっている。 多分return 文の中でコピーする。 return は 正しく構造体の戻り値を指していればいいだけで、 引数がついている。 構造体の場合は引数で一個呼ばれているのでその引数をとっておかないといけなくて。 実は引数、 evnpがついてる。 値を返す evnp がさしてる allocate させてるところにおいてもいい。 evnpni Micro-C ではフレームポインタが入っている。 実装ではフレームピオンタが入っている。 さっき行ったとおり、return val はレジスタでいいので、return レジスタ simple return; return だけで戻る。 前にレジスタを設定したので戻ってくると。 関数の戻りからの動作はおもいので、 goto 剃る前にはレジスタの値がきまっているはず。 return val があればbuild1 で if(0)なので中にはいってこない。このコードが最適化で消えないように工夫しないといけない。 最適化をかけるとここがきえちゃう。消えないようにCOND をいれて〜とかある。 cbc_exit0: が外から TREE_used とか c_decl_flag_label 最適化で消えちゃわないようになってる。 最適化かけてうまく動かなかいのはこのコードが消されちゃうから。 そのあたりをチェック。 setjmp 使えば常にもどれるので。 CbCのなかでsetjmp してlongjmp をかいてももどれる。 CbC バージョン GCC バージョン typedef __rectype __selftype それを入れるためにはどうすればいいのかっていうのも議論すればいい。 typdef をやると、先輩たちがやって もちろん両方。