summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/ipa-pure-const.c64
-rw-r--r--gcc/ipa-reference.c155
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr40556.c22
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();
+}