------- Comment #7 from hubicka at ucw dot cz 2008-09-02 20:29 -------
Subject: Re: [4.4 Regression]: gcc.c-torture/execute/931018-1.c int-compare.c
ieee/inf-2.c mzero6.c
>
>
> ------- Comment #6 from hp at gcc dot gnu dot org 2008-09-02 10:41 -------
> (In reply to comment #5)
>
> > Well, the code is not mine, but it was wirtten at a time struct_function
> > did hold a lot of extra stuff.
>
> SVN blamed you for that code in tree-inline.c and the revision range is yours.
I've moved that code around from verioning function and enabled it by
default.
I am attaching patch I am testing now. It makes versioning to copy only
fields needed and I also noticed that we leak memory in gimple_body
pointer. This pointer is pointing to sequence holding first basicblock
after build_cfg and when this block is removed it is pointing to bogus
sequence then. Setting this pointer to 0 confuse some places that use
gimple_body to check presence of functionbody.
I added predicate for this and replaced checks by cgraph's analyzed
flag that will be needed for WHOPR anyway.
Index: cgraph.c
===================================================================
*** cgraph.c (revision 139886)
--- cgraph.c (working copy)
*************** cgraph_create_edge (struct cgraph_node *
*** 631,637 ****
gcc_assert (is_gimple_call (call_stmt));
! if (!gimple_body (callee->decl))
edge->inline_failed = N_("function body not available");
else if (callee->local.redefined_extern_inline)
edge->inline_failed = N_("redefined extern inline functions are not "
--- 631,637 ----
gcc_assert (is_gimple_call (call_stmt));
! if (!callee->analyzed)
edge->inline_failed = N_("function body not available");
else if (callee->local.redefined_extern_inline)
edge->inline_failed = N_("redefined extern inline functions are not "
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 1059,1065 ****
fprintf (f, " needed");
else if (node->reachable)
fprintf (f, " reachable");
! if (gimple_body (node->decl))
fprintf (f, " body");
if (node->output)
fprintf (f, " output");
--- 1059,1065 ----
fprintf (f, " needed");
else if (node->reachable)
fprintf (f, " reachable");
! if (gimple_has_body_p (node->decl))
fprintf (f, " body");
if (node->output)
fprintf (f, " output");
Index: cgraphunit.c
===================================================================
*** cgraphunit.c (revision 139886)
--- cgraphunit.c (working copy)
*************** verify_cgraph_node (struct cgraph_node *
*** 639,645 ****
}
if (node->analyzed
- && gimple_body (node->decl)
&& !TREE_ASM_WRITTEN (node->decl)
&& (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
{
--- 639,644 ----
*************** cgraph_analyze_functions (void)
*** 860,866 ****
{
fprintf (cgraph_dump_file, "Initial entry points:");
for (node = cgraph_nodes; node != first_analyzed; node = node->next)
! if (node->needed && gimple_body (node->decl))
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n");
}
--- 859,865 ----
{
fprintf (cgraph_dump_file, "Initial entry points:");
for (node = cgraph_nodes; node != first_analyzed; node = node->next)
! if (node->needed)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n");
}
*************** cgraph_analyze_functions (void)
*** 912,918 ****
{
fprintf (cgraph_dump_file, "Unit entry points:");
for (node = cgraph_nodes; node != first_analyzed; node = node->next)
! if (node->needed && gimple_body (node->decl))
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n\nInitial ");
dump_cgraph (cgraph_dump_file);
--- 911,917 ----
{
fprintf (cgraph_dump_file, "Unit entry points:");
for (node = cgraph_nodes; node != first_analyzed; node = node->next)
! if (node->needed)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n\nInitial ");
dump_cgraph (cgraph_dump_file);
*************** cgraph_analyze_functions (void)
*** 926,935 ****
tree decl = node->decl;
next = node->next;
! if (node->local.finalized && !gimple_body (decl))
cgraph_reset_node (node);
! if (!node->reachable && gimple_body (decl))
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
--- 925,934 ----
tree decl = node->decl;
next = node->next;
! if (node->local.finalized && !gimple_has_body_p (decl))
cgraph_reset_node (node);
! if (!node->reachable && gimple_has_body_p (decl))
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
*************** cgraph_analyze_functions (void)
*** 938,944 ****
}
else
node->next_needed = NULL;
! gcc_assert (!node->local.finalized || gimple_body (decl));
gcc_assert (node->analyzed == node->local.finalized);
}
if (cgraph_dump_file)
--- 937,943 ----
}
else
node->next_needed = NULL;
! gcc_assert (!node->local.finalized || gimple_has_body_p (decl));
gcc_assert (node->analyzed == node->local.finalized);
}
if (cgraph_dump_file)
*************** cgraph_mark_functions_to_output (void)
*** 991,997 ****
/* We need to output all local functions that are used and not
always inlined, as well as those that are reachable from
outside the current compilation unit. */
! if (gimple_body (decl)
&& !node->global.inlined_to
&& (node->needed
|| (e && node->reachable))
--- 990,996 ----
/* We need to output all local functions that are used and not
always inlined, as well as those that are reachable from
outside the current compilation unit. */
! if (node->analyzed
&& !node->global.inlined_to
&& (node->needed
|| (e && node->reachable))
*************** cgraph_mark_functions_to_output (void)
*** 1003,1009 ****
/* We should've reclaimed all functions that are not needed. */
#ifdef ENABLE_CHECKING
if (!node->global.inlined_to
! && gimple_body (decl)
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
--- 1002,1008 ----
/* We should've reclaimed all functions that are not needed. */
#ifdef ENABLE_CHECKING
if (!node->global.inlined_to
! && gimple_has_body_p (decl)
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
*************** cgraph_mark_functions_to_output (void)
*** 1011,1017 ****
}
#endif
gcc_assert (node->global.inlined_to
! || !gimple_body (decl)
|| DECL_EXTERNAL (decl));
}
--- 1010,1016 ----
}
#endif
gcc_assert (node->global.inlined_to
! || !gimple_has_body_p (decl)
|| DECL_EXTERNAL (decl));
}
*************** cgraph_expand_function (struct cgraph_no
*** 1042,1054 ****
/* ??? Can happen with nested function of extern inline. */
gcc_assert (TREE_ASM_WRITTEN (decl));
current_function_decl = NULL;
! if (!cgraph_preserve_function_body_p (decl))
! {
! cgraph_release_function_body (node);
! /* Eliminate all call edges. This is important so the call_expr no
longer
! points to the dead function body. */
! cgraph_node_remove_callees (node);
! }
cgraph_function_flags_ready = true;
}
--- 1041,1051 ----
/* ??? Can happen with nested function of extern inline. */
gcc_assert (TREE_ASM_WRITTEN (decl));
current_function_decl = NULL;
! gcc_assert (!cgraph_preserve_function_body_p (decl));
! cgraph_release_function_body (node);
! /* Eliminate all call edges. This is important so the call_expr no longer
! points to the dead function body. */
! cgraph_node_remove_callees (node);
cgraph_function_flags_ready = true;
}
*************** cgraph_optimize (void)
*** 1329,1335 ****
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
&& (node->global.inlined_to
! || gimple_body (node->decl)))
{
error_found = true;
dump_cgraph_node (stderr, node);
--- 1326,1332 ----
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
&& (node->global.inlined_to
! || gimple_has_body_p (node->decl)))
{
error_found = true;
dump_cgraph_node (stderr, node);
Index: ipa-inline.c
===================================================================
*** ipa-inline.c (revision 139886)
--- ipa-inline.c (working copy)
*************** cgraph_clone_inlined_nodes (struct cgrap
*** 212,218 ****
&& !cgraph_new_nodes)
{
gcc_assert (!e->callee->global.inlined_to);
! if (gimple_body (e->callee->decl))
overall_insns -= e->callee->global.insns, nfunctions_inlined++;
duplicate = false;
}
--- 212,218 ----
&& !cgraph_new_nodes)
{
gcc_assert (!e->callee->global.inlined_to);
! if (e->callee->analyzed)
overall_insns -= e->callee->global.insns, nfunctions_inlined++;
duplicate = false;
}
*************** cgraph_decide_inlining_incrementally (st
*** 1388,1394 ****
}
continue;
}
! if (!gimple_body (e->callee->decl) && !e->callee->inline_decl)
{
if (dump_file)
{
--- 1388,1394 ----
}
continue;
}
! if (!e->callee->analyzed && !e->callee->inline_decl)
{
if (dump_file)
{
*************** cgraph_decide_inlining_incrementally (st
*** 1463,1469 ****
}
continue;
}
! if (!gimple_body (e->callee->decl) && !e->callee->inline_decl)
{
if (dump_file)
{
--- 1463,1469 ----
}
continue;
}
! if (!e->callee->analyzed && !e->callee->inline_decl)
{
if (dump_file)
{
*************** inline_transform (struct cgraph_node *no
*** 1706,1712 ****
/* We might need the body of this function so that we can expand
it inline somewhere else. */
! if (cgraph_preserve_function_body_p (current_function_decl))
save_inline_function_body (node);
for (e = node->callees; e; e = e->next_callee)
--- 1706,1712 ----
/* We might need the body of this function so that we can expand
it inline somewhere else. */
! if (cgraph_preserve_function_body_p (node->decl))
save_inline_function_body (node);
for (e = node->callees; e; e = e->next_callee)
Index: predict.c
===================================================================
*** predict.c (revision 139886)
--- predict.c (working copy)
*************** struct gimple_opt_pass pass_strip_predic
*** 2179,2185 ****
{
{
GIMPLE_PASS,
! "", /* name */
NULL, /* gate */
strip_predict_hints, /* execute */
NULL, /* sub */
--- 2179,2185 ----
{
{
GIMPLE_PASS,
! NULL, /* name */
NULL, /* gate */
strip_predict_hints, /* execute */
NULL, /* sub */
Index: expmed.c
===================================================================
*** expmed.c (revision 139886)
--- expmed.c (working copy)
*************** expand_divmod (int rem_flag, enum tree_c
*** 4086,4093 ****
goto fail1;
}
else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
! && (rem_flag ? smod_pow2_cheap[compute_mode]
! : sdiv_pow2_cheap[compute_mode])
/* We assume that cheap metric is true if the
optab has an expander for this mode. */
&& ((optab_handler ((rem_flag ? smod_optab
--- 4086,4093 ----
goto fail1;
}
else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
! && (rem_flag ? smod_pow2_cheap[speed][compute_mode]
! : sdiv_pow2_cheap[speed][compute_mode])
/* We assume that cheap metric is true if the
optab has an expander for this mode. */
&& ((optab_handler ((rem_flag ? smod_optab
*************** expand_divmod (int rem_flag, enum tree_c
*** 4107,4113 ****
return gen_lowpart (mode, remainder);
}
! if (sdiv_pow2_cheap[compute_mode]
&& ((optab_handler (sdiv_optab,
compute_mode)->insn_code
!= CODE_FOR_nothing)
|| (optab_handler (sdivmod_optab,
compute_mode)->insn_code
--- 4107,4113 ----
return gen_lowpart (mode, remainder);
}
! if (sdiv_pow2_cheap[speed][compute_mode]
&& ((optab_handler (sdiv_optab,
compute_mode)->insn_code
!= CODE_FOR_nothing)
|| (optab_handler (sdivmod_optab,
compute_mode)->insn_code
Index: tree-inline.c
===================================================================
*** tree-inline.c (revision 139886)
--- tree-inline.c (working copy)
*************** static void
*** 1686,1693 ****
initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
int frequency)
{
- struct function *new_cfun
- = (struct function *) ggc_alloc_cleared (sizeof (struct function));
struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
gcov_type count_scale, frequency_scale;
--- 1686,1691 ----
*************** initialize_cfun (tree new_fndecl, tree c
*** 1706,1719 ****
/* Register specific tree functions. */
gimple_register_cfg_hooks ();
! *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
! new_cfun->funcdef_no = get_next_funcdef_no ();
! VALUE_HISTOGRAMS (new_cfun) = NULL;
! new_cfun->local_decls = NULL;
! new_cfun->cfg = NULL;
! new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
! DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
! push_cfun (new_cfun);
init_empty_tree_cfg ();
ENTRY_BLOCK_PTR->count =
--- 1704,1743 ----
/* Register specific tree functions. */
gimple_register_cfg_hooks ();
!
! /* Get clean struct function. */
! push_struct_function (new_fndecl);
!
! /* We will rebuild these, so just sanity check that they are empty. */
! gcc_assert (VALUE_HISTOGRAMS (cfun) == NULL);
! gcc_assert (cfun->local_decls == NULL);
! gcc_assert (cfun->cfg == NULL);
! gcc_assert (cfun->decl == new_fndecl);
!
! /* No need to copy; this is initialized later in compilation. */
! gcc_assert (!src_cfun->calls_setjmp);
! gcc_assert (!src_cfun->calls_alloca);
!
! /* Copy items we preserve during clonning. */
! cfun->static_chain_decl = src_cfun->static_chain_decl;
! cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area;
! cfun->function_end_locus = src_cfun->function_end_locus;
! cfun->curr_properties = src_cfun->curr_properties;
! cfun->last_verified = src_cfun->last_verified;
! if (src_cfun->ipa_transforms_to_apply)
! cfun->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
!
src_cfun->ipa_transforms_to_apply);
! cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
! cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
! cfun->function_frequency = src_cfun->function_frequency;
! cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
! cfun->stdarg = src_cfun->stdarg;
! cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
! cfun->after_inlining = src_cfun->after_inlining;
! cfun->returns_struct = src_cfun->returns_struct;
! cfun->returns_pcc_struct = src_cfun->returns_pcc_struct;
! cfun->after_tree_profile = src_cfun->after_tree_profile;
!
init_empty_tree_cfg ();
ENTRY_BLOCK_PTR->count =
*************** inlinable_function_p (tree fn)
*** 2575,2586 ****
inlinable = false;
}
- /* If we don't have the function body available, we can't inline it.
- However, this should not be recorded since we also get here for
- forward declared inline functions. Therefore, return at once. */
- if (!gimple_body (fn))
- return false;
-
else if (inline_forbidden_p (fn))
{
/* See if we should warn about uninlinable functions. Previously,
--- 2599,2604 ----
*************** expand_call_inline (basic_block bb, gimp
*** 3083,3089 ****
gimple_body. */
if (!DECL_INITIAL (fn)
&& DECL_ABSTRACT_ORIGIN (fn)
! && gimple_body (DECL_ABSTRACT_ORIGIN (fn)))
fn = DECL_ABSTRACT_ORIGIN (fn);
/* Objective C and fortran still calls tree_rest_of_compilation directly.
--- 3101,3107 ----
gimple_body. */
if (!DECL_INITIAL (fn)
&& DECL_ABSTRACT_ORIGIN (fn)
! && gimple_has_body_p (DECL_ABSTRACT_ORIGIN (fn)))
fn = DECL_ABSTRACT_ORIGIN (fn);
/* Objective C and fortran still calls tree_rest_of_compilation directly.
Index: gimple.c
===================================================================
*** gimple.c (revision 139886)
--- gimple.c (working copy)
*************** gimple_body (tree fndecl)
*** 1816,1821 ****
--- 1816,1829 ----
return fn ? fn->gimple_body : NULL;
}
+ /* Return true when FNDECL has Gimple body either in unlowered
+ or CFG form. */
+ bool
+ gimple_has_body_p (tree fndecl)
+ {
+ struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+ return (gimple_body (fndecl) || (fn && fn->cfg));
+ }
/* Detect flags from a GIMPLE_CALL. This is just like
call_expr_flags, but for gimple tuples. */
Index: gimple.h
===================================================================
*** gimple.h (revision 139886)
--- gimple.h (working copy)
*************** enum gimple_statement_structure_enum gss
*** 816,821 ****
--- 816,822 ----
void sort_case_labels (VEC(tree,heap) *);
void gimple_set_body (tree, gimple_seq);
gimple_seq gimple_body (tree);
+ bool gimple_has_body_p (tree);
gimple_seq gimple_seq_alloc (void);
void gimple_seq_free (gimple_seq);
void gimple_seq_add_seq (gimple_seq *, gimple_seq);
Index: tree-cfg.c
===================================================================
*** tree-cfg.c (revision 139886)
--- tree-cfg.c (working copy)
*************** build_gimple_cfg (gimple_seq seq)
*** 217,223 ****
static unsigned int
execute_build_cfg (void)
{
! build_gimple_cfg (gimple_body (current_function_decl));
return 0;
}
--- 217,226 ----
static unsigned int
execute_build_cfg (void)
{
! gimple_seq body = gimple_body (current_function_decl);
!
! build_gimple_cfg (body);
! gimple_set_body (current_function_decl, NULL);
return 0;
}
*************** dump_function_to_file (tree fn, FILE *fi
*** 5898,5904 ****
if (dsf && (flags & TDF_DETAILS))
dump_eh_tree (file, dsf);
! if (flags & TDF_RAW && !gimple_body (fn))
{
dump_node (fn, TDF_SLIM | flags, file);
return;
--- 5901,5907 ----
if (dsf && (flags & TDF_DETAILS))
dump_eh_tree (file, dsf);
! if (flags & TDF_RAW && !gimple_has_body_p (fn))
{
dump_node (fn, TDF_SLIM | flags, file);
return;
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37315