diff options
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/ipa-pure-const.c | 64 | ||||
-rw-r--r-- | gcc/ipa-reference.c | 155 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr40556.c | 22 |
5 files changed, 186 insertions, 78 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d686d0db7be..a709e5312d5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,24 @@ 2009-10-22 Jan Hubicka <jh@suse.cz> + PR tree-optimize/40556 + * ipa-reference.c (has_proper_scope_for_analysis): Add fixme about global vars. + (check_call): Handle only indirect calls. + (propagate_bits): Update comment. + (write_node_summary_p): Turn bogus check to assert. + (ipa_reference_write_summary): Stream calls_read_all properly. + (ipa_reference_read_summary): Stream in calls_read_all properly. + (read_write_all_from_decl): New function. + (propagate): Handle OVERWRITABLE nodes and external calls here. + * ipa-pre-const.c (check_call): In IPA mode handle indirect calls + only. + (analyze_function): Do not check visibility here. + (add_new_function): We summary OVERWRITABLE too. + (generate_summary): Stream OVERWRITABLE nodes too. + (propagate): Handle external calls and OVERWRITABLE nodes here. + (local_pure_const): Check visibility here. + +2009-10-22 Jan Hubicka <jh@suse.cz> + * ipa-cp.c (ipcp_write_summary, ipcp_read_summary): New functions. (pass_ipa_cp): Register them. (ipcp_init_stage): Analyze all functions for whopr/lto. diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index ea1d81ea5e2..e37af05d08e 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -330,12 +330,11 @@ check_call (funct_state local, gimple call, bool ipa) /* When not in IPA mode, we can still handle self recursion. */ if (!ipa && callee_t == current_function_decl) local->looping = true; - /* The callee is either unknown (indirect call) or there is just no - scannable code for it (external call) . We look to see if there - are any bits available for the callee (such as by declaration or - because it is builtin) and process solely on the basis of those - bits. */ - else if (avail <= AVAIL_OVERWRITABLE || !ipa) + /* Either calle is unknown or we are doing local analysis. + Look to see if there are any bits available for the callee (such as by + declaration or because it is builtin) and process solely on the basis of + those bits. */ + else if (!ipa || !callee_t) { if (possibly_throws && flag_non_call_exceptions) { @@ -492,13 +491,6 @@ analyze_function (struct cgraph_node *fn, bool ipa) funct_state l; basic_block this_block; - if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE) - { - if (dump_file) - fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n"); - return NULL; - } - l = XCNEW (struct funct_state_d); l->pure_const_state = IPA_CONST; l->state_previously_known = IPA_NEITHER; @@ -609,7 +601,7 @@ end: static void add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) { - if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) + if (cgraph_function_body_availability (node) < AVAIL_OVERWRITABLE) return; /* There are some shared nodes, in particular the initializers on static declarations. We do not need to scan them more than once @@ -686,12 +678,12 @@ generate_summary (void) /* Process all of the functions. - We do NOT process any AVAIL_OVERWRITABLE functions, we cannot - guarantee that what we learn about the one we see will be true - for the one that overrides it. - */ + We process AVAIL_OVERWRITABLE functions. We can not use the results + by default, but the info can be used at LTO with -fwhole-program or + when function got clonned and the clone is AVAILABLE. */ + for (node = cgraph_nodes; node; node = node->next) - if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) + if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) set_function_state (node, analyze_function (node, true)); pointer_set_destroy (visited_nodes); @@ -878,6 +870,12 @@ propagate (void) if (w_l->looping) looping = true; + if (cgraph_function_body_availability (w) == AVAIL_OVERWRITABLE) + { + looping |= w_l->looping_previously_known; + if (pure_const_state < w_l->state_previously_known) + pure_const_state = w_l->state_previously_known; + } if (pure_const_state == IPA_NEITHER) break; @@ -901,6 +899,20 @@ propagate (void) if (y_l->looping) looping = true; } + else + { + int flags = flags_from_decl_or_type (y->decl); + + if (flags & ECF_LOOPING_CONST_OR_PURE) + looping = true; + if (flags & ECF_CONST) + ; + else if ((flags & ECF_PURE) && pure_const_state == IPA_CONST) + pure_const_state = IPA_PURE; + else + pure_const_state = IPA_NEITHER, looping = true; + + } } w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; @@ -988,7 +1000,8 @@ propagate (void) struct cgraph_edge *e; funct_state w_l = get_function_state (w); - if (w_l->can_throw) + if (w_l->can_throw + || cgraph_function_body_availability (w) == AVAIL_OVERWRITABLE) can_throw = true; if (can_throw) @@ -1008,6 +1021,8 @@ propagate (void) && e->can_throw_external) can_throw = true; } + else if (e->can_throw_external && !TREE_NOTHROW (y->decl)) + can_throw = true; } w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; @@ -1046,7 +1061,7 @@ propagate (void) free (node->aux); node->aux = NULL; } - if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) + if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) free (get_function_state (node)); } @@ -1109,15 +1124,16 @@ local_pure_const (void) fprintf (dump_file, "Function called in recursive cycle; ignoring\n"); return 0; } - - l = analyze_function (cgraph_node (current_function_decl), false); - if (!l) + if (cgraph_function_body_availability (cgraph_node (current_function_decl)) + <= AVAIL_OVERWRITABLE) { if (dump_file) fprintf (dump_file, "Function has wrong visibility; ignoring\n"); return 0; } + l = analyze_function (cgraph_node (current_function_decl), false); + switch (l->pure_const_state) { case IPA_CONST: diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index 2e062e45eaa..f0e8aa0aaed 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -318,6 +318,8 @@ has_proper_scope_for_analysis (tree t) if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) return false; + /* FIXME: for LTO we should include PUBLIC vars too. This is bit difficult + as summarie would need unsharing. */ if (DECL_EXTERNAL (t) || TREE_PUBLIC (t)) return false; @@ -413,31 +415,21 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt) { int flags = gimple_call_flags (stmt); tree callee_t = gimple_call_fndecl (stmt); - enum availability avail = AVAIL_NOT_AVAILABLE; - if (callee_t) + /* Process indirect calls. All direct calles are handled at propagation + time. */ + if (!callee_t) { - struct cgraph_node* callee = cgraph_node(callee_t); - avail = cgraph_function_body_availability (callee); - } - - if (avail <= AVAIL_OVERWRITABLE) - if (local) - { - if (flags & ECF_CONST) - ; - else if (flags & ECF_PURE) + if (flags & ECF_CONST) + ; + else if (flags & ECF_PURE) + local->calls_read_all = true; + else + { local->calls_read_all = true; - else - { - local->calls_read_all = true; - local->calls_write_all = true; - } - } - /* TODO: To be able to produce sane results, we should also handle - common builtins, in particular throw. - Indirect calls hsould be only counted and as inliner is replacing them - by direct calls, we can conclude if any indirect calls are left in body */ + local->calls_write_all = true; + } + } } /* TP is the part of the tree currently under the microscope. @@ -527,7 +519,7 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x { struct cgraph_node *y = e->callee; - /* Only look at the master nodes and skip external nodes. */ + /* Only look into nodes we can propagate something. */ if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE) { if (get_reference_vars_info (y)) @@ -1012,8 +1004,8 @@ generate_summary (void) static bool write_node_summary_p (struct cgraph_node *node) { + gcc_assert (node->global.inlined_to == NULL); return (node->analyzed - && node->global.inlined_to == NULL && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE && get_reference_vars_info (node) != NULL); } @@ -1053,18 +1045,28 @@ ipa_reference_write_summary (cgraph_node_set set) lto_output_uleb128_stream (ob->main_stream, node_ref); /* Stream out the statics read. */ - lto_output_uleb128_stream (ob->main_stream, - bitmap_count_bits (l->statics_read)); - EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi) - lto_output_var_decl_index(ob->decl_state, ob->main_stream, - get_static_decl (index)); + if (l->calls_read_all) + lto_output_sleb128_stream (ob->main_stream, -1); + else + { + lto_output_sleb128_stream (ob->main_stream, + bitmap_count_bits (l->statics_read)); + EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi) + lto_output_var_decl_index(ob->decl_state, ob->main_stream, + get_static_decl (index)); + } /* Stream out the statics written. */ - lto_output_uleb128_stream (ob->main_stream, - bitmap_count_bits (l->statics_written)); - EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi) - lto_output_var_decl_index(ob->decl_state, ob->main_stream, - get_static_decl (index)); + if (l->calls_write_all) + lto_output_sleb128_stream (ob->main_stream, -1); + else + { + lto_output_sleb128_stream (ob->main_stream, + bitmap_count_bits (l->statics_written)); + EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi) + lto_output_var_decl_index(ob->decl_state, ob->main_stream, + get_static_decl (index)); + } } } lto_destroy_simple_output_block (ob); @@ -1101,7 +1103,7 @@ ipa_reference_read_summary (void) unsigned int j, index; struct cgraph_node *node; ipa_reference_local_vars_info_t l; - unsigned int v_count; + int v_count; lto_cgraph_encoder_t encoder; index = lto_input_uleb128 (ib); @@ -1110,26 +1112,32 @@ ipa_reference_read_summary (void) l = init_function_info (node); /* Set the statics read. */ - v_count = lto_input_uleb128 (ib); - for (j = 0; j < v_count; j++) - { - unsigned int var_index = lto_input_uleb128 (ib); - tree v_decl = lto_file_decl_data_get_var_decl (file_data, - var_index); - add_static_var (v_decl); - bitmap_set_bit (l->statics_read, DECL_UID (v_decl)); - } + v_count = lto_input_sleb128 (ib); + if (v_count == -1) + l->calls_read_all = true; + else + for (j = 0; j < (unsigned int)v_count; j++) + { + unsigned int var_index = lto_input_uleb128 (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + add_static_var (v_decl); + bitmap_set_bit (l->statics_read, DECL_UID (v_decl)); + } /* Set the statics written. */ - v_count = lto_input_uleb128 (ib); - for (j = 0; j < v_count; j++) - { - unsigned int var_index = lto_input_uleb128 (ib); - tree v_decl = lto_file_decl_data_get_var_decl (file_data, - var_index); - add_static_var (v_decl); - bitmap_set_bit (l->statics_written, DECL_UID (v_decl)); - } + v_count = lto_input_sleb128 (ib); + if (v_count == -1) + l->calls_read_all = true; + else + for (j = 0; j < (unsigned int)v_count; j++) + { + unsigned int var_index = lto_input_uleb128 (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + add_static_var (v_decl); + bitmap_set_bit (l->statics_written, DECL_UID (v_decl)); + } } lto_destroy_simple_input_block (file_data, @@ -1141,6 +1149,26 @@ ipa_reference_read_summary (void) +/* Set READ_ALL/WRITE_ALL based on DECL flags. */ +static void +read_write_all_from_decl (tree decl, bool * read_all, bool * write_all) +{ + int flags = flags_from_decl_or_type (decl); + if (flags & ECF_CONST) + ; + else if (flags & ECF_PURE) + *read_all = true; + else + { + /* TODO: To be able to produce sane results, we should also handle + common builtins, in particular throw. + Indirect calls hsould be only counted and as inliner is replacing them + by direct calls, we can conclude if any indirect calls are left in body */ + *read_all = true; + *write_all = true; + } +} + /* Produce the global information by preforming a transitive closure on the local information that was produced by ipa_analyze_function and ipa_analyze_variable. */ @@ -1173,6 +1201,7 @@ propagate (void) ipa_reference_global_vars_info_t node_g = XCNEW (struct ipa_reference_global_vars_info_d); ipa_reference_local_vars_info_t node_l; + struct cgraph_edge *e; bool read_all; bool write_all; @@ -1193,6 +1222,15 @@ propagate (void) read_all = node_l->calls_read_all; write_all = node_l->calls_write_all; + /* When function is overwrittable, we can not assume anything. */ + if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (node->decl, &read_all, &write_all); + + for (e = node->callees; e; e = e->next_callee) + if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (e->callee->decl, &read_all, &write_all); + + /* If any node in a cycle is calls_read_all or calls_write_all they all are. */ w_info = (struct ipa_dfs_info *) node->aux; @@ -1201,6 +1239,15 @@ propagate (void) { ipa_reference_local_vars_info_t w_l = get_reference_vars_info (w)->local; + + /* When function is overwrittable, we can not assume anything. */ + if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (w->decl, &read_all, &write_all); + + for (e = w->callees; e; e = e->next_callee) + if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (e->callee->decl, &read_all, &write_all); + read_all |= w_l->calls_read_all; write_all |= w_l->calls_write_all; @@ -1208,6 +1255,7 @@ propagate (void) w = w_info->next_cycle; } + /* Initialized the bitmaps for the reduced nodes */ if (read_all) node_g->statics_read = all_module_statics; @@ -1217,7 +1265,6 @@ propagate (void) bitmap_copy (node_g->statics_read, node_l->statics_read); } - if (write_all) node_g->statics_written = all_module_statics; else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 42ca4b2cdd7..78f21bd42cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2009-10-22 Jan Hubicka <jh@suse.cz> + + * gcc.c-torture/compile/pr40556.c: New testcase. + 2009-10-22 Janus Weil <janus@gcc.gnu.org> PR fortran/41781 diff --git a/gcc/testsuite/gcc.c-torture/compile/pr40556.c b/gcc/testsuite/gcc.c-torture/compile/pr40556.c new file mode 100644 index 00000000000..a7b25b7af8f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr40556.c @@ -0,0 +1,22 @@ +struct A {}; + +struct A foo() +{ + return foo(); +} + +void bar() +{ + foo(); +} +struct A {}; + +struct A foo() +{ + return foo(); +} + +void bar() +{ + foo(); +} |