Cの継続 | CbCの継続(軽量継続) |
|
|
![]() |
![]() |
__code print_factorial(int prod) { printf("factorial = %d\n",prod); exit(0); } __code factorial0(int prod, int x) { if ( x >= 1) { goto factorial0(prod*x, x-1); }else{ goto print_factorial(prod); } } |
__code factorial(int x) { goto factorial0(1, x); } int main(int argc, char **argv) { int i; i = atoi(argv[1]); goto factorial(i); return 0; } |
ソースコード | Generic Treeでの表現 |
int main() { int a, b; a = 3; b = func(a, 10); return b; } |
![]() |
tree build_code_segment_type (tree value_type, tree arg_types) { tree t; hashval_t hashcode = 0; gcc_assert (TREE_CODE (value_type) == VOID_TYPE); /* Make a node of the sort we want. */ t = make_node (FUNCTION_TYPE); TREE_TYPE (t) = value_type; TYPE_ARG_TYPES (t) = arg_types; CbC_IS_CODE_SEGMENT (t) = 1; if (!COMPLETE_TYPE_P (t)) layout_type (t); return t; } |
case RID_GOTO: c_parser_consume_token (parser); if ( c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON ) { : } #ifndef noCbC else { if (c_parser_next_token_is (parser, CPP_NAME)) { tree id = c_parser_peek_token (parser)->value; location_t loc = c_parser_peek_token (parser)->location; /** build_external_ref (id,RID_CbC_CODE , loc); **/ build_external_ref (loc, id, RID_CbC_CODE, &expr.original_type); } expr = c_parser_expr_no_commas (parser, NULL); if (TREE_CODE(expr.value) == CALL_EXPR ) { location_t loc = c_parser_peek_token (parser)->location; cbc_replace_arguments (loc, expr.value); TREE_TYPE(expr.value) = void_type_node; CbC_IS_CbC_GOTO (expr.value) = 1; CALL_EXPR_TAILCALL (expr.value) = 1; add_stmt(expr.value); stmt = c_finish_return(loc, NULL_TREE, NULL_TREE); } else c_parser_error (parser, "expected code segment jump or %<*%>"); } #else |
実際のコード | GCC内で処理されるコード |
__code test() { : goto factorial0(1, x); } |
void test() { : factorial0(1, x); return; } |
void f(int a, int b) { printf("f: a=%d b=%d\n",a,b); return ; } void g(int a, int b){ printf("g: a=%d b=%d\n",a,b); f(a,b); return; } int main() { g(3,4); return 0; } |
![]() |
if (currently_expanding_call++ != 0 || ((!fndecl || !CbC_IS_CODE_SEGMENT (TREE_TYPE (fndecl))) && !flag_optimize_sibling_calls) || args_size.var || dbg_cnt (tail_call) == false) try_tail_call = 0;
if (fndecl && CbC_IS_CODE_SEGMENT (TREE_TYPE (fndecl)) && CbC_IS_CODE_SEGMENT (TREE_TYPE (current_function_decl)) && try_tail_call == 0) { location_t loc = EXPR_LOCATION (exp); char *name_callee = IDENTIFIER_POINTER(DECL_NAME(fndecl)); warning_at (loc, 0, "transition to code segment \"%s\" with CbC goto, but tail call optimization was cut.", name_callee); try_tail_call = 1; }
if(!TARGET_64BIT) { attrs = build_tree_list (get_identifier("fastcall"), NULL_TREE); declspecs_add_attrs(specs, attrs); }
Intel64 ではレジスタが増えていてfastcallは標準でつくようになっている。
arch | int(整数型) | float(浮動小数点型) | double(浮動小数点型) |
i386 | 2 | 0 (stackを使用) |
0 (stackを使用) |
x64 | 6 | 8 | 8 |
__code c1(__code ret(int,void *),void *env) { goto ret(1,env); } int main() { goto c1(__return, __environment); } |
__environmentキーワードは関数の環境を保持する(Micro-Cの場合)。
生成しているコード | 生成するコード(GCC内部) |
//goto c1(__return, __environment); goto c1(({ __label__ _cbc_exit0; static int retval; void _cbc_internal_return(int retval_, void *_envp) { retval = retval_; goto _cbc_exit0; } if (0) { _cbc_exit0: return retval; } _cbc_internal_return; }), __environment); |
case RID_CbC_RET: { tree value, stmt, label, tlab, decl; c_parser_consume_token (parser); stmt = c_begin_stmt_expr (); cbc_return_f = c_parser_peek_token (parser)->value; location_t location = c_parser_peek_token (parser)->location; /* create label. (__label__ _cbc_exit0;) */ label = get_identifier ("_cbc_exit0"); tlab = declare_label (label); C_DECLARED_LABEL_FLAG (tlab) = 1; add_stmt (build_stmt (location, DECL_EXPR, tlab)); /* declare retval. (int retval;) */ tree decl_cond = build_decl (location, VAR_DECL, get_identifier ("retval"), TREE_TYPE (TREE_TYPE (current_function_decl))); TREE_STATIC (decl_cond) = 1; TREE_USED (decl_cond) = 1; /* Use thread-local */ DECL_TLS_MODEL (decl_cond) = decl_default_tls_model (decl_cond); DECL_NONLOCAL (decl_cond) = 1; add_stmt (build_stmt(location, DECL_EXPR, pushdecl (decl_cond))); /* define nested function. */ decl = cbc_finish_nested_function (location, label, decl_cond); TREE_USED(decl) = 1; /* define if-ed goto label and return statement. */ cbc_finish_labeled_goto (location, label, decl_cond); /* get pointer to nested function. */ value = build_addr (decl , current_function_decl); TREE_USED (current_function_decl) = 1; SET_EXPR_LOCATION (value, location); add_stmt (value); TREE_SIDE_EFFECTS (stmt) = 1; expr.value = c_finish_stmt_expr (location, stmt); expr.original_code = ERROR_MARK; } |
![]() |
![]() |
fastcall有り | fastcall無し |
![]() |
![]() |
|
|
(call_insn/j 18 17 19 3 (call (mem:QI (symbol_ref:DI ("factorial") [flags 0x403] <function_decl 0x1443b4400 factorial>) [0 S1 A8]) (const_int 1024 [0x400])) factorial.cbc:30 -1 (expr_list:REG_EH_REGION (const_int 0 [0]) (nil)) (expr_list:REG_DEP_TRUE (use (reg:SI 5 di)) (nil)))
void factorial(int n, int result, void(*print)()){ : (*print)(n,result,print,exit1, envp); }
__code factorial(int n, int result, __rectype *print) { : goto (*print)(n,result,print,exit1, envp); }
typedef sturct node { selftype *left; selftype *right; int num; }*NODE
selftype は struct node を指す。