diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1f1bbd055ba..17ffc762973 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2009-02-27 Jan Hubicka + + PR debug/39267 + * tree.h (TREE_PROTECTED): Fix comment. + (BLOCK_HANDLER_BLOCK): Remove. + (struct tree_block): Remove handler_block add body_block. + (inlined_function_outer_scope_p): New. + (is_body_block): Remove. + * dbxout.c (dbxout_block): Remove BLOCK_HANDLER_BLOCK. + * dwarf2out.c (is_inlined_entry_point): Remove. + (add_high_low_attributes): Use inlined_function_outer_scope_p. + (gen_block_die): Use is_inlined_entry_point check; remove body block code. + * langhooks.h (struct lang_hooks): Remove no_bodu_blocks. + * gimplify.c (gimplify_expr): Gimplify body blocks. + * tree-ssa-live.c (remove_unused_scope_block_p): Allow removing wrapper block + with multiple subblocks. + (dump_scope_block): Prettier output; dump more flags and info. + (dump_scope_blocks): New. + (remove_unused_locals): Use dump_scope_blocks. + * tree-flow.h (dump_scope_blocks): Declare. + * tree-cfg.c (execute_build_cfg): Dump scope blocks. + * stmt.c (is_body_block): Remove. + * tree-inline.c (remap_block): Copy BODY_BLOCK info. + * langhooks-def.h (LANG_HOOKS_NO_BODY_BLOCKS): Remove. + 2009-02-27 Sebastian Pop PR middle-end/39308 diff --git a/gcc/c-common.c b/gcc/c-common.c index f19976b4af1..a84113f867e 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -7740,6 +7740,7 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default) tree curindex; unsigned HOST_WIDE_INT cnt; constructor_elt *ce; + bool fold_p = false; if (VEC_index (constructor_elt, v, 0)->index) maxindex = fold_convert (sizetype, @@ -7751,14 +7752,20 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default) VEC_iterate (constructor_elt, v, cnt, ce); cnt++) { + bool curfold_p = false; if (ce->index) - curindex = fold_convert (sizetype, ce->index); + curindex = ce->index, curfold_p = true; else - curindex = size_binop (PLUS_EXPR, curindex, size_one_node); - + { + if (fold_p) + curindex = fold_convert (sizetype, curindex); + curindex = size_binop (PLUS_EXPR, curindex, size_one_node); + } if (tree_int_cst_lt (maxindex, curindex)) - maxindex = curindex; + maxindex = curindex, fold_p = curfold_p; } + if (fold_p) + maxindex = fold_convert (sizetype, maxindex); } } else diff --git a/gcc/c-objc-common.h b/gcc/c-objc-common.h index b9568c97372..2a981502b84 100644 --- a/gcc/c-objc-common.h +++ b/gcc/c-objc-common.h @@ -53,8 +53,6 @@ extern void c_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_FINISH_INCOMPLETE_DECL c_finish_incomplete_decl #undef LANG_HOOKS_STATICP #define LANG_HOOKS_STATICP c_staticp -#undef LANG_HOOKS_NO_BODY_BLOCKS -#define LANG_HOOKS_NO_BODY_BLOCKS true #undef LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL c_warn_unused_global_decl #undef LANG_HOOKS_PRINT_IDENTIFIER diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 6cfa55f9328..babba15f8a5 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -3625,20 +3625,6 @@ dbxout_block (tree block, int depth, tree args) scope_start = buf; } - if (BLOCK_HANDLER_BLOCK (block)) - { - /* A catch block. Must precede N_LBRAC. */ - tree decl = BLOCK_VARS (block); - while (decl) - { - dbxout_begin_complex_stabs (); - stabstr_I (DECL_NAME (decl)); - stabstr_S (":C1"); - dbxout_finish_complex_stabs (0, N_CATCH, 0, - scope_start, 0); - decl = TREE_CHAIN (decl); - } - } dbx_output_lbrac (scope_start, begin_label); } diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index ed165c8386b..9d39a455e85 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -14135,35 +14135,6 @@ add_call_src_coords_attributes (tree stmt, dw_die_ref die) } -/* If STMT's abstract origin is a function declaration and STMT's - first subblock's abstract origin is the function's outermost block, - then we're looking at the main entry point. */ -static bool -is_inlined_entry_point (const_tree stmt) -{ - tree decl, block; - - if (!stmt || TREE_CODE (stmt) != BLOCK) - return false; - - decl = block_ultimate_origin (stmt); - - if (!decl || TREE_CODE (decl) != FUNCTION_DECL) - return false; - - block = BLOCK_SUBBLOCKS (stmt); - - if (block) - { - if (TREE_CODE (block) != BLOCK) - return false; - - block = block_ultimate_origin (block); - } - - return block == DECL_INITIAL (decl); -} - /* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die. Add low_pc and high_pc attributes to the DIE for a block STMT. */ @@ -14176,7 +14147,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die) { tree chain; - if (is_inlined_entry_point (stmt)) + if (inlined_function_outer_scope_p (stmt)) { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); @@ -14861,14 +14832,15 @@ static void gen_block_die (tree stmt, dw_die_ref context_die, int depth) { int must_output_die = 0; - tree origin; tree decl; - enum tree_code origin_code; + bool inlined_func; /* Ignore blocks that are NULL. */ if (stmt == NULL_TREE) return; + inlined_func = inlined_function_outer_scope_p (stmt); + /* If the block is one fragment of a non-contiguous block, do not process the variables, since they will have been done by the origin block. Do process subblocks. */ @@ -14882,52 +14854,34 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth) return; } - /* Determine the "ultimate origin" of this block. This block may be an - inlined instance of an inlined instance of inline function, so we have - to trace all of the way back through the origin chain to find out what - sort of node actually served as the original seed for the creation of - the current block. */ - origin = block_ultimate_origin (stmt); - origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK; - /* Determine if we need to output any Dwarf DIEs at all to represent this block. */ - if (origin_code == FUNCTION_DECL) + if (inlined_func) /* The outer scopes for inlinings *must* always be represented. We generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */ must_output_die = 1; else { - /* In the case where the current block represents an inlining of the - "body block" of an inline function, we must *NOT* output any DIE for - this block because we have already output a DIE to represent the whole - inlined function scope and the "body block" of any function doesn't - really represent a different scope according to ANSI C rules. So we - check here to make sure that this block does not represent a "body - block inlining" before trying to set the MUST_OUTPUT_DIE flag. */ - if (! is_body_block (origin ? origin : stmt)) - { - /* Determine if this block directly contains any "significant" - local declarations which we will need to output DIEs for. */ - if (debug_info_level > DINFO_LEVEL_TERSE) - /* We are not in terse mode so *any* local declaration counts - as being a "significant" one. */ - must_output_die = (BLOCK_VARS (stmt) != NULL - && (TREE_USED (stmt) - || TREE_ASM_WRITTEN (stmt) - || BLOCK_ABSTRACT (stmt))); - else - /* We are in terse mode, so only local (nested) function - definitions count as "significant" local declarations. */ - for (decl = BLOCK_VARS (stmt); - decl != NULL; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl)) - { - must_output_die = 1; - break; - } - } + /* Determine if this block directly contains any "significant" + local declarations which we will need to output DIEs for. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + /* We are not in terse mode so *any* local declaration counts + as being a "significant" one. */ + must_output_die = (BLOCK_VARS (stmt) != NULL + && (TREE_USED (stmt) + || TREE_ASM_WRITTEN (stmt) + || BLOCK_ABSTRACT (stmt))); + else + /* We are in terse mode, so only local (nested) function + definitions count as "significant" local declarations. */ + for (decl = BLOCK_VARS (stmt); + decl != NULL; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl)) + { + must_output_die = 1; + break; + } } /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block @@ -14939,7 +14893,7 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth) instances and local (nested) function definitions. */ if (must_output_die) { - if (origin_code == FUNCTION_DECL) + if (inlined_func) gen_inlined_subroutine_die (stmt, context_die, depth); else gen_lexical_block_die (stmt, context_die, depth); diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 9c85b583a2b..f9f8cde4d2a 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -97,7 +97,6 @@ extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *, #define LANG_HOOKS_STATICP lhd_staticp #define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL lhd_do_nothing_t #define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME lhd_set_decl_assembler_name -#define LANG_HOOKS_NO_BODY_BLOCKS false #define LANG_HOOKS_PRINT_STATISTICS lhd_do_nothing #define LANG_HOOKS_PRINT_XNODE lhd_print_tree_nothing #define LANG_HOOKS_PRINT_DECL lhd_print_tree_nothing @@ -246,7 +245,6 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_STATICP, \ LANG_HOOKS_DUP_LANG_SPECIFIC_DECL, \ LANG_HOOKS_SET_DECL_ASSEMBLER_NAME, \ - LANG_HOOKS_NO_BODY_BLOCKS, \ LANG_HOOKS_PRINT_STATISTICS, \ LANG_HOOKS_PRINT_XNODE, \ LANG_HOOKS_PRINT_DECL, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 752ad99501f..52d1f24448c 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -317,11 +317,6 @@ struct lang_hooks assembler does not talk about it. */ void (*set_decl_assembler_name) (tree); - /* Nonzero if this front end does not generate a dummy BLOCK between - the outermost scope of the function and the FUNCTION_DECL. See - is_body_block in stmt.c, and its callers. */ - bool no_body_blocks; - /* The front end can add its own statistics to -fmem-report with this hook. It should output to stderr. */ void (*print_statistics) (void); diff --git a/gcc/stmt.c b/gcc/stmt.c index c5369061e9d..96e63fa88f1 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -1724,38 +1724,6 @@ expand_return (tree retval) } } -/* Given a pointer to a BLOCK node return nonzero if (and only if) the node - in question represents the outermost pair of curly braces (i.e. the "body - block") of a function or method. - - For any BLOCK node representing a "body block" of a function or method, the - BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which - represents the outermost (function) scope for the function or method (i.e. - the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of - *that* node in turn will point to the relevant FUNCTION_DECL node. */ - -int -is_body_block (const_tree stmt) -{ - if (lang_hooks.no_body_blocks) - return 0; - - if (TREE_CODE (stmt) == BLOCK) - { - tree parent = BLOCK_SUPERCONTEXT (stmt); - - if (parent && TREE_CODE (parent) == BLOCK) - { - tree grandparent = BLOCK_SUPERCONTEXT (parent); - - if (grandparent && TREE_CODE (grandparent) == FUNCTION_DECL) - return 1; - } - } - - return 0; -} - /* Emit code to restore vital registers at the beginning of a nonlocal goto handler. */ static void diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 106c58fd46d..5632a8930bc 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -221,6 +221,11 @@ execute_build_cfg (void) build_gimple_cfg (body); gimple_set_body (current_function_decl, NULL); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Scope blocks:\n"); + dump_scope_blocks (dump_file, dump_flags); + } return 0; } diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 96c098ec376..3bedd358428 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -1153,6 +1153,7 @@ void compute_call_used_vars (void); /* In tree-ssa-live.c */ extern void remove_unused_locals (void); +extern void dump_scope_blocks (FILE *, int); /* In tree-ssa-address.c */ diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index 81e65f732e1..15166cc8f5e 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -541,8 +541,13 @@ remove_unused_scope_block_p (tree scope) { tree next = BLOCK_CHAIN (*t); tree supercontext = BLOCK_SUPERCONTEXT (*t); + *t = BLOCK_SUBBLOCKS (*t); - gcc_assert (!BLOCK_CHAIN (*t)); + while (BLOCK_CHAIN (*t)) + { + BLOCK_SUPERCONTEXT (*t) = supercontext; + t = &BLOCK_CHAIN (*t); + } BLOCK_CHAIN (*t) = next; BLOCK_SUPERCONTEXT (*t) = supercontext; t = &BLOCK_CHAIN (*t); @@ -556,23 +561,40 @@ remove_unused_scope_block_p (tree scope) t = &BLOCK_CHAIN (*t); nsubblocks ++; } + + + if (!unused) + ; /* Outer scope is always used. */ - if (!BLOCK_SUPERCONTEXT (scope) - || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL) + else if (!BLOCK_SUPERCONTEXT (scope) + || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL) unused = false; - /* If there are more than one live subblocks, it is used. */ - else if (nsubblocks > 1) + /* Innermost blocks with no live variables nor statements can be always + eliminated. */ + else if (!nsubblocks) + ; + /* If there are live subblocks and we still have some unused variables + or types declared, we must keep them. + Before inliing we must not depend on debug info verbosity to keep + DECL_UIDs stable. */ + else if (!cfun->after_inlining && BLOCK_VARS (scope)) unused = false; - /* When there is only one subblock, see if it is just wrapper we can - ignore. Wrappers are not declaring any variables and not changing - abstract origin. */ - else if (nsubblocks == 1 - && (BLOCK_VARS (scope) - || ((debug_info_level == DINFO_LEVEL_NORMAL - || debug_info_level == DINFO_LEVEL_VERBOSE) - && ((BLOCK_ABSTRACT_ORIGIN (scope) - != BLOCK_ABSTRACT_ORIGIN (BLOCK_SUPERCONTEXT (scope))))))) + /* For terse debug info we can eliminate info on unused variables. */ + else if (debug_info_level == DINFO_LEVEL_NONE + || debug_info_level == DINFO_LEVEL_TERSE) + ; + else if (BLOCK_VARS (scope)) unused = false; + /* See if this block is important for representation of inlined function. + Inlined functions are always represented by block with + block_ultimate_origin being set to FUNCTION_DECL and DECL_SOURCE_LOCATION + set... */ + else if (inlined_function_outer_scope_p (scope)) + unused = false; + else + /* Verfify that only blocks with source location set + are entry points to the inlined functions. */ + gcc_assert (BLOCK_SOURCE_LOCATION (scope) == UNKNOWN_LOCATION); return unused; } @@ -592,14 +614,27 @@ dump_scope_block (FILE *file, int indent, tree scope, int flags) { tree var, t; - fprintf (file, "\n%*sScope block #%i %s\n",indent, "" , BLOCK_NUMBER (scope), - TREE_USED (scope) ? "" : "(unused)"); - if (BLOCK_ABSTRACT_ORIGIN (scope) && DECL_P (block_ultimate_origin (scope))) + fprintf (file, "\n%*s{ Scope block #%i%s%s",indent, "" , BLOCK_NUMBER (scope), + TREE_USED (scope) ? "" : " (unused)", + BLOCK_ABSTRACT (scope) ? " (abstract)": ""); + if (BLOCK_SOURCE_LOCATION (scope) != UNKNOWN_LOCATION) { - fprintf (file, "\n%*sOriginating from ",indent + 1, ""); - print_generic_decl (file, block_ultimate_origin (scope), flags); - fprintf (file, "\n"); + expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (scope)); + fprintf (file, " %s:%i", s.file, s.line); } + if (BLOCK_ABSTRACT_ORIGIN (scope)) + { + tree origin = block_ultimate_origin (scope); + if (origin) + { + fprintf (file, " Originating from :"); + if (DECL_P (origin)) + print_generic_decl (file, origin, flags); + else + fprintf (file, "#%i", BLOCK_NUMBER (origin)); + } + } + fprintf (file, " \n"); for (var = BLOCK_VARS (scope); var; var = TREE_CHAIN (var)) { bool used = false; @@ -615,8 +650,14 @@ dump_scope_block (FILE *file, int indent, tree scope, int flags) } for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t)) dump_scope_block (file, indent + 2, t, flags); + fprintf (file, "\n%*s}\n",indent, ""); } +void +dump_scope_blocks (FILE *file, int flags) +{ + dump_scope_block (file, 0, DECL_INITIAL (current_function_decl), flags); +} /* Remove local variables that are not referenced in the IL. */ @@ -760,7 +801,7 @@ remove_unused_locals (void) if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Scope blocks after cleanups:\n"); - dump_scope_block (dump_file, 0, DECL_INITIAL (current_function_decl), false); + dump_scope_blocks (dump_file, dump_flags); } } diff --git a/gcc/tree.h b/gcc/tree.h index ae4291326d9..1e86bf9bc61 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1324,8 +1324,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, /* Used in classes in C++. */ #define TREE_PRIVATE(NODE) ((NODE)->base.private_flag) -/* Used in classes in C++. - In a BLOCK node, this is BLOCK_HANDLER_BLOCK. */ +/* Used in classes in C++. */ #define TREE_PROTECTED(NODE) ((NODE)->base.protected_flag) /* Nonzero in a _DECL if the use of the name is defined as a @@ -1977,11 +1976,6 @@ struct varray_head_tag; #define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK (NODE)->block.abstract_origin) #define BLOCK_ABSTRACT(NODE) (BLOCK_CHECK (NODE)->block.abstract_flag) -/* Nonzero means that this block is prepared to handle exceptions - listed in the BLOCK_VARS slot. */ -#define BLOCK_HANDLER_BLOCK(NODE) \ - (BLOCK_CHECK (NODE)->block.handler_block_flag) - /* An index number for this block. These values are not guaranteed to be unique across functions -- whether or not they are depends on the debugging output format in use. */ @@ -2022,9 +2016,8 @@ struct tree_block GTY(()) { struct tree_common common; - unsigned handler_block_flag : 1; unsigned abstract_flag : 1; - unsigned block_num : 30; + unsigned block_num : 31; location_t locus; @@ -4657,6 +4650,14 @@ function_args_iter_next (function_args_iterator *i) i->next = TREE_CHAIN (i->next); } +/* We set BLOCK_SOURCE_LOCATION only to inlined function entry points. */ + +static inline bool +inlined_function_outer_scope_p (const_tree block) +{ + return BLOCK_SOURCE_LOCATION (block) != UNKNOWN_LOCATION; +} + /* Loop over all function arguments of FNTYPE. In each iteration, PTR is set to point to the next tree element. ITER is an instance of function_args_iterator used to iterate the arguments. */ @@ -4710,7 +4711,6 @@ extern void expand_goto (tree); extern rtx expand_stack_save (void); extern void expand_stack_restore (tree); extern void expand_return (tree); -extern int is_body_block (const_tree); /* In tree-eh.c */ extern void using_eh_for_cleanups (void);