------- 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