void record_vars_into (tree vars, tree fn) { bool change_cfun = fn != current_function_decl; if (change_cfun) push_cfun (DECL_STRUCT_FUNCTION (fn)); for (; vars; vars = DECL_CHAIN (vars)) { tree var = vars; /* BIND_EXPRs contains also function/type/constant declarations we don't need to care about. */ if (TREE_CODE (var) != VAR_DECL) continue; /* Nothing to do in this case. */ if (DECL_EXTERNAL (var)) continue; /* Record the variable. */ add_local_decl (cfun, var); } if (change_cfun) pop_cfun (); }
static void pop_cfun_to (tree outer) { pop_cfun (); current_function_decl = outer; gcc_assert (cfun == DECL_STRUCT_FUNCTION (current_function_decl)); gcc_assert (cfun->decl == current_function_decl); }
static void convert_to_ssa (tree fndecl) { function *fun = DECL_STRUCT_FUNCTION (fndecl); ASSERT_TRUE (fun != NULL); ASSERT_EQ (fndecl, fun->decl); gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g); push_cfun (fun); build_ssa_pass->execute (fun); pop_cfun (); }
static void build_cfg (tree fndecl) { function *fun = DECL_STRUCT_FUNCTION (fndecl); ASSERT_TRUE (fun != NULL); ASSERT_EQ (fndecl, fun->decl); /* We first have to lower control flow; for our trivial test function this gives us: test_fn () { D.56 = 42; goto <D.57>; <D.57>: return D.56; } */ gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g); push_cfun (fun); lower_cf_pass->execute (fun); pop_cfun (); /* We can now convert to CFG form; for our trivial test function this gives us: test_fn () { <bb 2>: D.56 = 42; return D.56; } */ gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g); push_cfun (fun); build_cfg_pass->execute (fun); pop_cfun (); }
static tree build_junk_fn(unsigned id) { char fnname[32] = {0}; tree decl, resdecl, initial, proto; /* Func decl */ snprintf(fnname, 31, "__func%d", id); proto = build_varargs_function_type_list(void_type_node, NULL_TREE); decl = build_fn_decl(fnname, proto); SET_DECL_ASSEMBLER_NAME(decl, get_identifier(fnname)); printf(TAG "Creating junk function: %s\n", fnname); /* Result */ resdecl=build_decl(BUILTINS_LOCATION,RESULT_DECL,NULL_TREE,void_type_node); DECL_ARTIFICIAL(resdecl) = 1; DECL_CONTEXT(resdecl) = decl; DECL_RESULT(decl) = resdecl; /* Initial */ initial = make_node(BLOCK); TREE_USED(initial) = 1; DECL_INITIAL(decl) = initial; DECL_UNINLINABLE(decl) = 1; DECL_EXTERNAL(decl) = 0; DECL_PRESERVE_P(decl) = 1; /* Func decl */ TREE_USED(decl) = 1; TREE_PUBLIC(decl) = 1; TREE_STATIC(decl) = 1; DECL_ARTIFICIAL(decl) = 1; /* Make the function */ push_struct_function(decl); /* DECL_SAVED_TREE(decl) = gen_junk(); */ cfun->function_end_locus = BUILTINS_LOCATION; gimplify_function_tree(decl); /* Update */ cgraph_add_new_function(decl, false); cgraph_mark_needed_node(cgraph_node(decl)); current_function_decl = NULL_TREE; pop_cfun(); return decl; }
void tree_lowering_passes (tree fn) { tree saved_current_function_decl = current_function_decl; current_function_decl = fn; push_cfun (DECL_STRUCT_FUNCTION (fn)); gimple_register_cfg_hooks (); bitmap_obstack_initialize (NULL); execute_pass_list (all_lowering_passes); if (optimize && cgraph_global_info_ready) execute_pass_list (pass_early_local_passes.pass.sub); free_dominance_info (CDI_POST_DOMINATORS); free_dominance_info (CDI_DOMINATORS); compact_blocks (); current_function_decl = saved_current_function_decl; bitmap_obstack_release (NULL); pop_cfun (); }
/* parsing language hook */ static void slang_parse_file () { int i; for(i = 0; i<num_in_fnames; ++i) { parse_program(in_fnames[i]); } #if 0 tree char_p = build_pointer_type (char_type_node); tree puts_type = build_function_type_list (integer_type_node, char_p, NULL_TREE); tree puts_fndecl = build_function_decl ("puts", true, puts_type); tree main_type = build_function_type_list (integer_type_node, NULL_TREE); tree main_fndecl = build_function_decl ("main", false, main_type); const char *msg = "HelloWorld , ... This is pradeeps compiler"; tree hello_str = build_string_literal (strlen(msg) + 1, msg); tree call = build_call_expr (puts_fndecl,1, hello_str); tree block = make_node(BLOCK); tree c1 = build_pointer_type (char_type_node); tree stmts = NULL_TREE ;//alloc_stmt_list (); append_to_statement_list (call, &stmts); build_function (main_fndecl, stmts, block); FILE *fd = fopen("/home/pradeep/Desktop/dump.txt","w"); gimplify_function_tree (main_fndecl); dump_function_to_file (main_fndecl, fd, 0); fclose(fd); cgraph_finalize_function (main_fndecl, false); current_function_decl = NULL_TREE; pop_cfun(); #endif }
static funct_state analyze_function (struct cgraph_node *fn, bool ipa) { tree decl = fn->symbol.decl; funct_state l; basic_block this_block; l = XCNEW (struct funct_state_d); l->pure_const_state = IPA_CONST; l->state_previously_known = IPA_NEITHER; l->looping_previously_known = true; l->looping = false; l->can_throw = false; state_from_flags (&l->state_previously_known, &l->looping_previously_known, flags_from_decl_or_type (fn->symbol.decl), cgraph_node_cannot_return (fn)); if (fn->thunk.thunk_p || fn->symbol.alias) { /* Thunk gets propagated through, so nothing interesting happens. */ gcc_assert (ipa); return l; } if (dump_file) { fprintf (dump_file, "\n\n local analysis of %s\n ", cgraph_node_name (fn)); } push_cfun (DECL_STRUCT_FUNCTION (decl)); FOR_EACH_BB (this_block) { gimple_stmt_iterator gsi; struct walk_stmt_info wi; memset (&wi, 0, sizeof(wi)); for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi)) { check_stmt (&gsi, l, ipa); if (l->pure_const_state == IPA_NEITHER && l->looping && l->can_throw) goto end; } } end: if (l->pure_const_state != IPA_NEITHER) { /* Const functions cannot have back edges (an indication of possible infinite loop side effect. */ if (mark_dfs_back_edges ()) { /* Preheaders are needed for SCEV to work. Simple latches and recorded exits improve chances that loop will proved to be finite in testcases such as in loop-15.c and loop-24.c */ loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES | LOOPS_HAVE_RECORDED_EXITS); if (dump_file && (dump_flags & TDF_DETAILS)) flow_loops_dump (dump_file, NULL, 0); if (mark_irreducible_loops ()) { if (dump_file) fprintf (dump_file, " has irreducible loops\n"); l->looping = true; } else { loop_iterator li; struct loop *loop; scev_initialize (); FOR_EACH_LOOP (li, loop, 0) if (!finite_loop_p (loop)) { if (dump_file) fprintf (dump_file, " can not prove finiteness of " "loop %i\n", loop->num); l->looping =true; FOR_EACH_LOOP_BREAK (li); } scev_finalize (); } loop_optimizer_finalize (); } } if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " checking previously known:"); better_state (&l->pure_const_state, &l->looping, l->state_previously_known, l->looping_previously_known); if (TREE_NOTHROW (decl)) l->can_throw = false; pop_cfun (); if (dump_file) { if (l->looping) fprintf (dump_file, "Function is locally looping.\n"); if (l->can_throw) fprintf (dump_file, "Function is locally throwing.\n"); if (l->pure_const_state == IPA_CONST) fprintf (dump_file, "Function is locally const.\n"); if (l->pure_const_state == IPA_PURE) fprintf (dump_file, "Function is locally pure.\n"); } return l; }
static unsigned int tree_profiling (void) { struct cgraph_node *node; /* This is a small-ipa pass that gets called only once, from cgraphunit.c:ipa_passes(). */ gcc_assert (symtab->state == IPA_SSA); init_node_map (true); FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; /* Do not instrument extern inline functions when testing coverage. While this is not perfectly consistent (early inlined extern inlines will get acocunted), testsuite expects that. */ if (DECL_EXTERNAL (node->decl) && flag_test_coverage) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); /* Local pure-const may imply need to fixup the cfg. */ if (execute_fixup_cfg () & TODO_cleanup_cfg) cleanup_tree_cfg (); branch_prob (); if (! flag_branch_probabilities && flag_profile_values) gimple_gen_ic_func_profiler (); if (flag_branch_probabilities && flag_profile_values && flag_value_profile_transformations) gimple_value_profile_transformations (); /* The above could hose dominator info. Currently there is none coming in, this is a safety valve. It should be easy to adjust it, if and when there is some. */ free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); } /* Drop pure/const flags from instrumented functions. */ FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->decl) || !(!node->clone_of || node->decl != node->clone_of->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; node->set_const_flag (false, false); node->set_pure_flag (false, false); } /* Update call statements and rebuild the cgraph. */ FOR_EACH_DEFINED_FUNCTION (node) { basic_block bb; if (!gimple_has_body_p (node->decl) || !(!node->clone_of || node->decl != node->clone_of->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); FOR_EACH_BB_FN (bb, cfun) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_call (stmt)) update_stmt (stmt); } } /* re-merge split blocks. */ cleanup_tree_cfg (); update_ssa (TODO_update_ssa); cgraph_edge::rebuild_edges (); pop_cfun (); }
bool cgraph_process_new_functions (void) { bool output = false; tree fndecl; struct cgraph_node *node; /* Note that this queue may grow as its being processed, as the new functions may generate new ones. */ while (cgraph_new_nodes) { node = cgraph_new_nodes; fndecl = node->decl; cgraph_new_nodes = cgraph_new_nodes->next_needed; switch (cgraph_state) { case CGRAPH_STATE_CONSTRUCTION: /* At construction time we just need to finalize function and move it into reachable functions list. */ node->next_needed = NULL; cgraph_finalize_function (fndecl, false); cgraph_mark_reachable_node (node); output = true; break; case CGRAPH_STATE_IPA: case CGRAPH_STATE_IPA_SSA: /* When IPA optimization already started, do all essential transformations that has been already performed on the whole cgraph but not on this function. */ gimple_register_cfg_hooks (); if (!node->analyzed) cgraph_analyze_function (node); push_cfun (DECL_STRUCT_FUNCTION (fndecl)); current_function_decl = fndecl; compute_inline_parameters (node); if ((cgraph_state == CGRAPH_STATE_IPA_SSA && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) /* When not optimizing, be sure we run early local passes anyway to expand OMP. */ || !optimize) execute_pass_list (pass_early_local_passes.pass.sub); free_dominance_info (CDI_POST_DOMINATORS); free_dominance_info (CDI_DOMINATORS); pop_cfun (); current_function_decl = NULL; break; case CGRAPH_STATE_EXPANSION: /* Functions created during expansion shall be compiled directly. */ node->output = 0; cgraph_expand_function (node); break; default: gcc_unreachable (); break; } cgraph_call_function_insertion_hooks (node); } return output; }
static unsigned int tree_profiling (void) { struct cgraph_node *node; /* Don't profile functions produced at destruction time, particularly the gcov datastructure initializer. Don't profile if it has been already instrumented either (when OpenMP expansion creates child function from already instrumented body). */ if (cgraph_state == CGRAPH_STATE_FINISHED) return 0; init_node_map(); for (node = cgraph_nodes; node; node = node->next) { if (!node->analyzed || !gimple_has_body_p (node->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); current_function_decl = node->decl; /* Re-set global shared temporary variable for edge-counters. */ gcov_type_tmp_var = NULL_TREE; /* Local pure-const may imply need to fixup the cfg. */ execute_fixup_cfg (); branch_prob (); if (! flag_branch_probabilities && flag_profile_values) gimple_gen_ic_func_profiler (); if (flag_branch_probabilities && flag_profile_values && flag_value_profile_transformations) gimple_value_profile_transformations (); /* The above could hose dominator info. Currently there is none coming in, this is a safety valve. It should be easy to adjust it, if and when there is some. */ free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); current_function_decl = NULL; pop_cfun (); } /* Drop pure/const flags from instrumented functions. */ for (node = cgraph_nodes; node; node = node->next) { if (!node->analyzed || !gimple_has_body_p (node->decl) || !(!node->clone_of || node->decl != node->clone_of->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) continue; cgraph_set_const_flag (node, false, false); cgraph_set_pure_flag (node, false, false); } /* Update call statements and rebuild the cgraph. */ for (node = cgraph_nodes; node; node = node->next) { basic_block bb; if (!node->analyzed || !gimple_has_body_p (node->decl) || !(!node->clone_of || node->decl != node->clone_of->decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); current_function_decl = node->decl; FOR_EACH_BB (bb) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_call (stmt)) update_stmt (stmt); } } cfun->after_tree_profile = 1; update_ssa (TODO_update_ssa); rebuild_cgraph_edges (); current_function_decl = NULL; pop_cfun (); } del_node_map(); return 0; }
static void test_expansion_to_rtl () { /* As above, construct a trivial function, gimplify it, build a CFG, and convert to SSA: */ tree fndecl = build_trivial_high_gimple_function (); function *fun = DECL_STRUCT_FUNCTION (fndecl); ASSERT_TRUE (fun != NULL); build_cfg (fndecl); convert_to_ssa (fndecl); /* We need a cgraph_node for it. */ cgraph_node::get_create (fndecl); /* Normally, cgraph_node::expand () would call init_function_start (and a bunch of other stuff), and invoke the expand pass, but it also runs all of the other passes. So just do the minimum needed to get from gimple-SSA to RTL. */ rtl_opt_pass *expand_pass = make_pass_expand (g); push_cfun (fun); init_function_start (fndecl); expand_pass->execute (fun); pop_cfun (); /* On x86_64, I get this: (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG) (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ]) (const_int 42 [0x2a])) -1 (nil)) (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ]) (reg:SI 87 [ D.59 ])) -1 (nil)) (insn 10 6 11 2 (set (reg/i:SI 0 ax) (reg:SI 88 [ <retval> ])) -1 (nil)) (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil)) On cr16-elf I get this: (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (insn 2 4 3 2 (set (reg:SI 24) (reg/f:SI 16 virtual-incoming-args)) -1 (nil)) (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG) (insn 6 3 7 2 (set (reg:HI 22 [ _1 ]) (const_int 42 [0x2a])) -1 (nil)) (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ]) (reg:HI 22 [ _1 ])) -1 (nil)) (insn 11 7 12 2 (set (reg/i:HI 0 r0) (reg:HI 23 [ <retval> ])) -1 (nil)) (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1 (nil)). */ verify_three_block_rtl_cfg (fun); /* Verify as much of the RTL as we can whilst avoiding target-specific behavior. */ basic_block bb2 = get_real_block (fun); /* Expect a NOTE_INSN_BASIC_BLOCK... */ rtx_insn *insn = BB_HEAD (bb2); ASSERT_TRUE (insn != NULL); ASSERT_EQ (NOTE, insn->code); ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn)); ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn)); /* ...etc; any further checks are likely to over-specify things and run us into target dependencies. */ }
static unsigned int tree_profiling (void) { struct cgraph_node *node; /* This is a small-ipa pass that gets called only once, from cgraphunit.c:ipa_passes(). */ gcc_assert (cgraph_state == CGRAPH_STATE_IPA_SSA); init_node_map(); FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->symbol.decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION) continue; push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); /* Local pure-const may imply need to fixup the cfg. */ if (execute_fixup_cfg () & TODO_cleanup_cfg) cleanup_tree_cfg (); branch_prob (); if (! flag_branch_probabilities && flag_profile_values) gimple_gen_ic_func_profiler (); if (flag_branch_probabilities && flag_profile_values && flag_value_profile_transformations) gimple_value_profile_transformations (); /* The above could hose dominator info. Currently there is none coming in, this is a safety valve. It should be easy to adjust it, if and when there is some. */ free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); pop_cfun (); } /* Drop pure/const flags from instrumented functions. */ FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->symbol.decl) || !(!node->clone_of || node->symbol.decl != node->clone_of->symbol.decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION) continue; cgraph_set_const_flag (node, false, false); cgraph_set_pure_flag (node, false, false); } /* Update call statements and rebuild the cgraph. */ FOR_EACH_DEFINED_FUNCTION (node) { basic_block bb; if (!gimple_has_body_p (node->symbol.decl) || !(!node->clone_of || node->symbol.decl != node->clone_of->symbol.decl)) continue; /* Don't profile functions produced for builtin stuff. */ if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION) continue; push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); FOR_EACH_BB (bb) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_call (stmt)) update_stmt (stmt); } } update_ssa (TODO_update_ssa); rebuild_cgraph_edges (); pop_cfun (); } del_node_map(); return 0; }