GCC への CbC コンパイル機能の実装について ___________________________________________________________ Code Segmentの実装 ----------------------------------------------------------- Code SegmentをC言語に組み込む。 コンパイラとしては単なるvoidの関数として扱い、parse treeにcode segmentであることのフラグを追加する。 * 予約語''__code``の追加 c-common.cで定義されているc_common_reswords配列に追加 { "__code", RID_CbC_CODE, 0} # D_CONLYも入れるか? * treeの生成関数 関数の型を表すtreeはbuild_funciton_type関数で生成されるが、code segmentではこれを使えない。build_function_typeはhash管理でまったく同 じ引数型、返り値型を持つものは同じオブジェクトを使うから。 なのでbuild_code_segment_typeでこの代わりを行う。 # 本当はbuild_function_typeのhashにcbcフラグも含める方がいいかもし # れない。 この関数は主にgrokdeclaratorから呼ばれる * cbc_set_codesegment関数 Undocumented. でも今は意味なかったような… ___________________________________________________________ goto文の実装 ----------------------------------------------------------- CbCについて重要な構文''goto cs(a, b, c);``を実装する。 c-parser.c内の c_parser_statement_after_labels()関数における巨大なスイ ッチ文のcase RID_GOTOのコードを修正する。 * アイデア 全てのgoto文を単なる関数呼び出しとその後のリターン文と解釈することで tail callを可能にする。 次のgoto文は goto cs(a); このparse treeでもこの様に解釈される cs(a); return; * Parser側での修正 オリジナルC言語のパース方法 1. gotoに続くトークンがCPP_NAME 通常のgoto文として処理 2. gotoに続くトークンが'*` computed gotoとして処理 see "GCC Manual" Sec 6.3. (not internals Manual) これを以下の様に変更する CbCでのパース方法 1. gotoに続くトークンがCPP_NAME && CPP_NAMEに次ぐトークンが';` 通常のgoto文として処理 2. gotoに続くトークンが'*` computed gotoとして処理 3. それ以外 CbCのgotoとして処理 処理内容 1. gotoトークンに続く文を関数呼び出しとみて c_parser_expr_no_commas()関数を使ってパース、treeを取得 # これで(*csp)(a)などにも対応できる 2. 取得したtreeがCALL_EXPRでなければエラー 3. treeにCbC_GOTOのフラグを立てる 4. treeにTAILCALLのフラグを立てる 5. add_stmt 6. return文のtreeを生成 * RTL expansion 通常のCALL_EXPRを解析するexpand_callを一部修正する。この関数の途中か らでexpand_cbc_goto関数に切り替えてRTLの生成はそこで全てを請け負う。 本来expand_callではtreeにsibcallフラグが立っていても、生成の過程で不 可能と検知するとsibcallを中断して通常のcallになるが、cbc_expand_call では無理やりsibcallにする。 expand_callでの修正内容 Undocumented. expand_cbc_gotoの処理内容 Undocumented. ___________________________________________________________ goto文における並列代入の実装 Nov 26, 2009 ----------------------------------------------------------- c-parser.c: c_parser_statement_after_labels()における goto文のパースの 段階で全ての引数を一時変数に代入する形に変更する。 もちろんこれだけで並列代入ができる分けではないが、おそらくGCCの最適化 機構でできると考える。 1. c_parser_expr_no_commasでCALL_EXPRを取得 2. 全ての引数に対して一時変数を作成 3. それぞれを代入 4. CALL_EXPRの引数を一時変数に置き換え 2-4の処理をcbc_replace_argumentsで行う。 ___________________________________________________________ return擬似変数の実装 ----------------------------------------------------------- ___________________________________________________________ environmentの実装 ----------------------------------------------------------- ___________________________________________ * goto文における並列代入実装について考える ------------------------------------------- Nov 26, 2009 c-parser.c: c_parser_statement_after_labels()における goto文のパースの 段階で全ての引数を一時変数に代入する形に変更する。 もちろんこれだけで並列代入ができる分けではないが、おそらくGCCの最適化 機構でできると考える。 1. c_parser_expr_no_commasでCALL_EXPRを取得 2. 全ての引数に対して一時変数を作成 build_decl? 名前なしでできるか? 3. それぞれを代入 4. CALL_EXPRの引数を一時変数に置き換え 5. expand_callでの実装を元に戻す? 現状のままでも動きはするはず 引数のタイプ 関数 o ADDR_EXPR o PARM_DECL, VAR_DECL, other o *_EXPR o PARM_DECL, VAR_DECL, 実装の準備 o CALL_EXPRから引数リストを取得 DECL_ARGUMENTS(fundecl) tree args = DECL_ARGUMENTS (fndecl); for (; args; args = TREE_CHAIN (args)) { tree type = TREE_TYPE (args); if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) DECL_ARG_TYPE (args) = integer_type_node; } o 名前なしの変数作成 var = build_decl(VAR_DECL, NULL_TREE, TYPE); DECL_ARTIFICIAL (val) = 1; o 代入文 build_modify_expr (loc, TO_EXPR, NOP_EXPR, FROM_EXPR) o Constantなら一時変数いらない もしくはcallerの引数と同じ場合にのみ一時変数を使うか o CALL_EXPRは取得後に引数を変えても大丈夫なのか? o expand_callでのstore_one_arg, check_sibcall_argument_overlapの動作 実装に邪魔ないくつかの関数の解析 o mem_overlaps_already_clobbered_arg_p(addr, size) 指定したメモリ[addr,addr+size]範囲がすでに前の引数格納によって上書 きされていないかをチェックする。 引数範囲を1byte毎にbitmapの1bitに表し、上書きされた場所は1がセット されている。それにかぶるとNG. また、addrが動的(esp+eaxなど)ならNG. o sotre_one_args() この実装ではexpand_cbc_gotoをいじらない事にした * DEBUG手法 gccコマンドではなくcc1コマンドに対してgdbを起動 $ ls GCC/ build-test/ test/ $ cd test $ gdb ../build-test/gcc/cc1 treeの表示 (gdb) p browse_tree (exp) <== expはtree構造体 rtxの表示 (gdb) p debug_rtx (exp) <== expはrtx構造体 browse_treeはtree, debug_rtxはrtxをconfigureの --enable-checkingで指定している必要がある