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(ソースコード) | GIMPLE |
void factorial(int x) { int prod,i; for(i=1,prod=1; i <= x; i++){ prod = prod*i; } print_factorial(prod); } |
factorial (int x) { int prod; int i; i = 1; prod = 1; goto <D.2846>; <D.2845>: prod = prod * i; i = i + 1; <D.2846>: if (i <= x) goto <D.2845>; else goto <D.2847>; <D.2847>: print_factorial (prod); } |
SSA | RTL(一部) |
factorial (int x) { int i; int prod; <bb 2>: i_3 = 1; prod_4 = 1; goto <bb 4>; <bb 3>: prod_6 = prod_1 * i_2; i_7 = i_2 + 1; <bb 4>: # prod_1 = PHI <prod_4(2), prod_6(3)> # i_2 = PHI <i_3(2), i_7(3)> if (i_2 <= x_5(D)) goto <bb 3>; else goto <bb 5>; <bb 5>: print_factorial (prod_1); return; } |
(jump_insn 20 19 21 5 (set (pc) (if_then_else (le (reg:CCGC 17 flags) (const_int 0 [0])) (label_ref 17) (pc))) factorial.c:12 -1 (nil) -> 17) (note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK) (insn 22 21 23 6 (set (reg:SI 62) (mem/c/i:SI (plus:DI (reg/f:DI 54 virtual-stack-vars) (const_int -4 [0xfffffffffffffffc])) [0 prod+0 S4 A32])) factorial.c:15 -1 (nil)) (insn 23 22 24 6 (set (reg:SI 5 di) (reg:SI 62)) factorial.c:15 -1 (nil)) (call_insn 24 23 25 6 (call (mem:QI (symbol_ref:DI ("print_factorial") [flags 0x403] |
値の代入:MODIFY_EXPR | 関数呼び出し:CALL_EXPR | |
命令 | b = a * 10 | func(a,10) |
Generic Tree |
![]() |
![]() |
Generic Treeでの表現
ソースコード | Generic Treeでの表現 |
int main() { int a, b; a = 3; b = func(a, 10); return b; } |
|
const struct c_common_resword c_common_reswords[] = { { "_Bool", RID_BOOL, D_CONLY }, : { "__code", RID_CbC_CODE, 0 }, |
case RID_CbC_CODE: : specs->typespec_word = cts_CbC_code; |
case cts_CbC_code: : specs->type = void_type_node; break; |
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 ) { stmt = c_finish_goto_label (loc, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); } else if (c_parser_next_token_is (parser, CPP_MULT)) { tree val; c_parser_consume_token (parser); val = c_parser_expression (parser).value; mark_exp_read (val); stmt = c_finish_goto_ptr (loc, val); } else 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); }
実際のコード | 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 ( #ifdef HAVE_sibcall_epilogue !HAVE_sibcall_epilogue #else 1 #endif || !try_tail_call || structure_value_addr != NULL_RTX #ifdef REG_PARM_STACK_SPACE || (OUTGOING_REG_PARM_STACK_SPACE (funtype) != OUTGOING_REG_PARM_STACK_SPACE (TREE_TYPE (current_function_decl))) || (reg_parm_stack_space != REG_PARM_STACK_SPACE (fndecl)) #endif || !targetm.function_ok_for_sibcall (fndecl, exp) || (flags & (ECF_RETURNS_TWICE | ECF_NORETURN)) || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr))) || (fndecl && decl_function_context (fndecl) == current_function_decl) || args_size.constant > (crtl->args.size - crtl->args.pretend_args_size) || (targetm.calls.return_pops_args (fndecl, funtype, args_size.constant) != targetm.calls.return_pops_args (current_function_decl, TREE_TYPE (current_function_decl), crtl->args.size)) || !lang_hooks.decls.ok_for_sibcall (fndecl)) try_tail_call = 0; |
/* Check if caller and callee disagree in promotion of function return value. */ #ifndef noCbC if (try_tail_call && (!fndecl || !CbC_IS_CODE_SEGMENT (TREE_TYPE (fndecl)))) #else if (try_tail_call) #endif { enum machine_mode caller_mode, caller_promoted_mode; enum machine_mode callee_mode, callee_promoted_mode; int caller_unsignedp, callee_unsignedp; tree caller_res = DECL_RESULT (current_function_decl); caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res)); caller_mode = DECL_MODE (caller_res); callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype)); callee_mode = TYPE_MODE (TREE_TYPE (funtype)); caller_promoted_mode = promote_function_mode (TREE_TYPE (caller_res), caller_mode, &caller_unsignedp, TREE_TYPE (current_function_decl), 1); callee_promoted_mode = promote_function_mode (TREE_TYPE (funtype), callee_mode, &callee_unsignedp, funtype, 1); if (caller_mode != VOIDmode && (caller_promoted_mode != callee_promoted_mode || ((caller_mode != caller_promoted_mode || callee_mode != callee_promoted_mode) && (caller_unsignedp != callee_unsignedp || GET_MODE_BITSIZE (caller_mode) < GET_MODE_BITSIZE (callee_mode))))) try_tail_call = 0; } |
#ifndef noCbC 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; } #endif |
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を使用) |
x86_64 | 6 | 8 | 8 |
__code c1(__code ret(int,void *),void *env) { goto ret(1,env); } int main() { goto c1(__return, __environment); } |
__environmentキーワードは関数の環境を保持する。
生成しているコード | 生成する為のコード |
//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); |
![]() |
生成されるTree | 生成する為のコード |
![]() |
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; } |
void factorial(int n, int result, void(*print)()){ : (*print)(n,result,print,exit1, envp); }
void factorial(int n, int result, void *print){ : void(*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 を指す。
![]() |
![]() |