Commit c59f5d1b by Jan Hubicka Committed by Jan Hubicka

re PR tree-optimization/40556 (ICE in IPA-CP with recursion)


	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.

From-SVN: r153450
parent fb3f88cc
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.
......@@ -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:
......
......@@ -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
......
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
......
struct A {};
struct A foo()
{
return foo();
}
void bar()
{
foo();
}
struct A {};
struct A foo()
{
return foo();
}
void bar()
{
foo();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment