diff options
author | Tom Tromey <tromey@redhat.com> | 2008-02-21 18:16:35 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2008-02-21 18:16:35 +0000 |
commit | c780f8ae4984f67e934c5dfab3ecd456dd45af7e (patch) | |
tree | 2a7973ba22470e082b64ca238ea46addf63491cc | |
parent | 1e902f2d33f756f8865aff8ac0de556e718c5ca2 (diff) |
* c-gimplify.c (c_gimplify_expr) <VIEW_CONVERT_EXPR>: Update
assertion.
* c-decl.c (all_global_decls): New global.
(pop_scope_internal): New function.
(pop_scope): Use it.
(pop_file_scope): Initialize all_global_decls. Use
pop_scope_internal.
(c_clear_binding_stack): Use pop_scope_internal.
(ext_block): Remove.
(c_smash_decls): Change type of 'result'. Remove 'list'
argument; add 'globals' argument. Smash field types of records
and unions.
(get_smashed_type): Don't smash field types of records and
unions.
(hand_off_decls): Walk DECL_ARGUMENTS of function.
(c_write_global_declarations): Use all_global_decls.
(c_init_decl_processing): Initialize all_global_decls.
* c-parser.c (struct can_reuse_hunk_data) <parser>: Remove.
(traverse_check_statics): New function.
(can_reuse_hunk): Call traverse_check_statics.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/incremental-compiler@132525 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/c-decl.c | 144 | ||||
-rw-r--r-- | gcc/c-gimplify.c | 8 | ||||
-rw-r--r-- | gcc/c-parser.c | 65 |
4 files changed, 163 insertions, 77 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 73bb27a4946..9d11270af0d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2008-02-21 Tom Tromey <tromey@redhat.com> + + * c-gimplify.c (c_gimplify_expr) <VIEW_CONVERT_EXPR>: Update + assertion. + * c-decl.c (all_global_decls): New global. + (pop_scope_internal): New function. + (pop_scope): Use it. + (pop_file_scope): Initialize all_global_decls. Use + pop_scope_internal. + (c_clear_binding_stack): Use pop_scope_internal. + (ext_block): Remove. + (c_smash_decls): Change type of 'result'. Remove 'list' + argument; add 'globals' argument. Smash field types of records + and unions. + (get_smashed_type): Don't smash field types of records and + unions. + (hand_off_decls): Walk DECL_ARGUMENTS of function. + (c_write_global_declarations): Use all_global_decls. + (c_init_decl_processing): Initialize all_global_decls. + * c-parser.c (struct can_reuse_hunk_data) <parser>: Remove. + (traverse_check_statics): New function. + (can_reuse_hunk): Call traverse_check_statics. + 2008-02-18 Tom Tromey <tromey@redhat.com> * c-parser.c (c_hack_token): Pop timevar in early return. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 1a259a20617..8e4b55d35e8 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -166,6 +166,11 @@ bool c_override_global_bindings_to_false; re-initializing the front end (in server mode), these are re-bound. */ static GTY ((param_is (union tree_node))) htab_t all_c_built_ins; + +/* When popping the file and external scopes, we collect the resulting + DECLs into this vector. */ +static GTY (()) VEC (tree, gc) *all_global_decls; + /* Each c_binding structure describes one binding of an identifier to a decl. All the decls in a scope - irrespective of namespace - are @@ -722,10 +727,12 @@ set_type_context (tree type, tree context) /* Exit a scope. Restore the state of the identifier-decl mappings that were in effect when this scope was entered. Return a BLOCK node containing all the DECLs in this scope that are of interest - to debug info generation. */ + to debug info generation. If RESULTS is not NULL, DECLs are not + put into the resulting block, but are instead pushed into the + supplied vector. */ -tree -pop_scope (void) +static tree +pop_scope_internal (VEC (tree, gc) **results) { struct c_scope *scope = current_scope; tree block, context, p; @@ -794,6 +801,7 @@ pop_scope (void) warn_for_unused_label (p); /* Labels go in BLOCK_VARS. */ + gcc_assert (!results); TREE_CHAIN (p) = BLOCK_VARS (block); BLOCK_VARS (block) = p; gcc_assert (I_LABEL_BINDING (b->id) == b); @@ -867,8 +875,20 @@ pop_scope (void) binding in the home scope. */ if (!b->nested) { - TREE_CHAIN (p) = BLOCK_VARS (block); - BLOCK_VARS (block) = p; + /* If RESULTS is supplied, push the decl there. We use + this rather than TREE_CHAIN because we may see a DECL + in multiple translation units, and changing + TREE_CHAIN destroys the list structure. */ + if (results) + { + gcc_assert (scope == external_scope || scope == file_scope); + VEC_safe_push (tree, gc, *results, p); + } + else + { + TREE_CHAIN (p) = BLOCK_VARS (block); + BLOCK_VARS (block) = p; + } } /* If this is the file scope, and we are processing more than one translation unit in this compilation, set @@ -936,6 +956,14 @@ pop_scope (void) return block; } +/* Like pop_scope_internal, but always supplies a NULL RESULTS + argument. */ +tree +pop_scope (void) +{ + return pop_scope_internal (NULL); +} + void push_file_scope (void) { @@ -981,8 +1009,11 @@ pop_file_scope (void) return; } + if (!all_global_decls) + all_global_decls = VEC_alloc (tree, gc, 128); + /* Pop off the file scope and close this translation unit. */ - pop_scope (); + pop_scope_internal (&all_global_decls); file_scope = 0; maybe_apply_pending_pragma_weaks (); @@ -3000,6 +3031,7 @@ c_init_decl_processing (void) current_function_decl = 0; all_translation_units = NULL_TREE; + all_global_decls = NULL; if (!did_it) gcc_obstack_init (&parser_obstack); @@ -8224,20 +8256,6 @@ get_smashed_type (htab_t map, tree type) else *slot = found; - - if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE) - && type == TYPE_MAIN_VARIANT (type)) - { - /* Canonicalize the type of each field. We do this here, and - not earlier, to avoid infinite recursion in some cases. */ - tree field; - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - { - gcc_assert (TREE_CODE (field) == FIELD_DECL); - TREE_TYPE (field) = get_smashed_type (map, TREE_TYPE (field)); - } - } - return type; } @@ -8245,26 +8263,27 @@ get_smashed_type (htab_t map, tree type) the chain. */ static void c_smash_decls (htab_t map, struct pointer_set_t *seen, - VEC (tree, heap) **result, tree list) + VEC (tree, gc) *globals, + VEC (tree, heap) **result) { tree decl; - for (decl = list; decl; decl = TREE_CHAIN (decl)) + int ix; + for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix) { tree canonical; struct c_tree_map_entry entry; void **slot; if (! map) + continue; + + /* This can happen with --combine. */ + if (pointer_set_contains (seen, decl)) { VEC_safe_push (tree, heap, *result, decl); continue; } - /* This can happen with --combine. FIXME: with combine we get - the wrong result for file-scope variables. */ - if (pointer_set_contains (seen, decl)) - continue; - /* The first time we see a decl, we insert its canonical copy into the result list. If we've already seen the canonical copy, we simply skip it and move on. */ @@ -8330,6 +8349,23 @@ c_smash_decls (htab_t map, struct pointer_set_t *seen, else TREE_TYPE (canonical) = get_smashed_type (map, TREE_TYPE (canonical)); + /* If we see a struct or union, we want to rewrite its field + types now. */ + if (TREE_CODE (canonical) == TYPE_DECL + && TREE_TYPE (canonical) == TYPE_MAIN_VARIANT (TREE_TYPE (canonical)) + && (TREE_CODE (TREE_TYPE (canonical)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (canonical)) == UNION_TYPE)) + { + tree field; + for (field = TYPE_FIELDS (TREE_TYPE (canonical)); + field; + field = TREE_CHAIN (field)) + { + gcc_assert (TREE_CODE (field) == FIELD_DECL); + TREE_TYPE (field) = get_smashed_type (map, TREE_TYPE (field)); + } + } + pointer_set_insert (seen, canonical); VEC_safe_push (tree, heap, *result, canonical); } @@ -8385,6 +8421,8 @@ hand_off_decls (htab_t map, VEC (tree, heap) *globals) map, NULL); walk_tree (&DECL_SAVED_TREE (decl), rewrite_types_and_globals, map, NULL); + walk_tree (&DECL_ARGUMENTS (decl), rewrite_types_and_globals, + map, NULL); c_override_global_bindings_to_false = save; if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node) cgraph_finalize_function (decl, false); @@ -8475,36 +8513,32 @@ c_write_global_declarations_2 (VEC (tree, heap) *globals) debug_hooks->global_decl (decl); } -/* Preserve the external declarations scope across a garbage collect. */ -static GTY(()) tree ext_block; - void c_clear_binding_stack (void) { - /* Clear this in case of early exit. */ - ext_block = NULL; - /* We don't want to do this if generating a PCH. */ if (pch_file) return; /* Close the external scope. */ - /* FIXME: we're keeping ext_block around too long in the server. */ - ext_block = pop_scope (); + /* FIXME: we're keeping all_global_decls around too long in the server. */ + gcc_assert (all_global_decls); + pop_scope_internal (&all_global_decls); external_scope = 0; gcc_assert (!current_scope); - if (ext_block) - { - tree tmp = BLOCK_VARS (ext_block); - int flags; - FILE * stream = dump_begin (TDI_tu, &flags); - if (stream && tmp) - { - dump_node (tmp, flags & ~TDF_SLIM, stream); - dump_end (TDI_tu, stream); - } - } + /* FIXME: re-enable this using all_global_decls. */ +/* if (ext_block) */ +/* { */ +/* tree tmp = BLOCK_VARS (ext_block); */ +/* int flags; */ +/* FILE * stream = dump_begin (TDI_tu, &flags); */ +/* if (stream && tmp) */ +/* { */ +/* dump_node (tmp, flags & ~TDF_SLIM, stream); */ +/* dump_end (TDI_tu, stream); */ +/* } */ +/* } */ } /* This maps trees to their canonical (smashed) variants. This must @@ -8514,12 +8548,9 @@ static GTY ((param_is (struct c_tree_map_entry))) htab_t lowering_smash_map; void c_write_global_declarations (void) { - tree t; - VEC (tree, heap) *all_decls = VEC_alloc (tree, heap, 128); struct pointer_set_t *seen_decls = NULL; - - if (! really_call_malloc (52)) - abort (); + VEC (tree, heap) *all_decls = VEC_alloc (tree, heap, + VEC_length (tree, all_global_decls)); server_assert_code_generation (); @@ -8529,12 +8560,8 @@ c_write_global_declarations (void) /* Smash all the types and decls. If we don't have a smash map, just fill ALL_DECLS with all the decls on the lists. */ - for (t = all_translation_units; t; t = TREE_CHAIN (t)) - c_smash_decls (lowering_smash_map, seen_decls, &all_decls, - BLOCK_VARS (DECL_INITIAL (t))); - if (ext_block) - c_smash_decls (lowering_smash_map, seen_decls, &all_decls, - BLOCK_VARS (ext_block)); + c_smash_decls (lowering_smash_map, seen_decls, all_global_decls, + &all_decls); /* Clean up. */ if (seen_decls) @@ -8549,6 +8576,7 @@ c_write_global_declarations (void) if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in) || pch_file) { + all_global_decls = NULL; VEC_free (tree, heap, all_decls); return; } @@ -8571,8 +8599,8 @@ c_write_global_declarations (void) timevar_pop (TV_SYMOUT); } + all_global_decls = NULL; VEC_free (tree, heap, all_decls); - ext_block = NULL; } #include "gt-c-decl.h" diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c index b4cc4b64942..324ab98a030 100644 --- a/gcc/c-gimplify.c +++ b/gcc/c-gimplify.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-dump.h" #include "c-pretty-print.h" #include "cgraph.h" +#include "opts.h" /* The gimplification pass converts the language-dependent trees @@ -232,8 +233,11 @@ c_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED) conversion should be redundant. */ if (C_SMASHED_P (*expr_p)) { - gcc_assert (TREE_TYPE (*expr_p) - == TREE_TYPE (TREE_OPERAND (*expr_p, 0))); + gcc_assert ((TREE_TYPE (*expr_p) + == TREE_TYPE (TREE_OPERAND (*expr_p, 0))) + || (num_in_fnames > 1 + && comptypes (TREE_TYPE (*expr_p), + TREE_TYPE (TREE_OPERAND (*expr_p, 0))))); *expr_p = TREE_OPERAND (*expr_p, 0); } return GS_UNHANDLED; diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 11f2187f8e0..ce674fee543 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see #include "md5.h" #include "server.h" #include "pointer-set.h" +#include "opts.h" /* The reserved keyword table. */ @@ -2099,11 +2100,37 @@ traverse_check_prereq (void **valp, void *ptd) return true; } +/* A hash table iterator callback which checks to see if a + hunk_binding_entry declares a static decl. */ +static int +traverse_check_statics (void **valp, void *ptd) +{ + bool *result = (bool *) ptd; + struct hunk_binding_entry *entry = (struct hunk_binding_entry *) *valp; + + if (entry->symbol_binding && entry->symbol_binding != hunk_binding_sentinel) + { + gcc_assert (TREE_CODE_CLASS (TREE_CODE (entry->symbol_binding)) + == tcc_declaration); + /* This is a bit over-eager, in that it would be ok to reuse a + decl if it did not come from one of the current compilation + units. However, this is an odd case and hopefully and + unimportant one. Also, ideally we could reuse a declaration + (not definition) here -- but that may mean working some magic + in the smashing pass. */ + if (TREE_STATIC (entry->symbol_binding)) + { + *result = false; + return false; + } + } + + return true; +} + /* Helper state for can_reuse_hunk and check_hunk_binding. */ struct can_reuse_hunk_data { - /* The parser. */ - c_parser *parser; /* The hunk to check for. */ struct parsed_hunk *hunk; /* The result, or NULL if nothing reusable found. */ @@ -2119,28 +2146,33 @@ check_hunk_binding (void **valp, void *crhd) { struct hunk_binding *binding = (struct hunk_binding *) *valp; struct can_reuse_hunk_data *info = (struct can_reuse_hunk_data *) crhd; -/* c_parser *parser = info->parser; */ struct parsed_hunk *hunk = info->hunk; struct parsed_hunk *binding_iter, *self_iter; bool ok; - /* We can't re-use a hunk twice in one compilation unit. FIXME: - this is a weird restriction and I think will go away once we have - anti-dependencies. The issue here is that if we see 2 decls - "extern int f;" the second time we will re_bind the same decl, - eventually tripping over the GC since the decl's chain will point - to itself (as part of scope popping). */ - /* FIXME: need more testing before really deleting this. */ -#if 0 - if (htab_find (parser->used_hunks, binding)) - return true; -#endif - /* Check prerequisites for this binding. */ ok = true; htab_traverse_noresize (binding->prereqs, traverse_check_prereq, &ok); if (!ok) - return true; + { + /* Keep looking. */ + return true; + } + + /* If we're compiling with --combine, then we don't want to reuse + static decls across compilation units, as this would give the + wrong answer. */ + if (num_in_fnames > 1) + { + htab_traverse_noresize (binding->binding_map, traverse_check_statics, + &ok); + if (!ok) + { + /* Don't bother looking any more. If one instance of the + hunk had a static decl, then the rest will as well. */ + return false; + } + } /* If we have a multi-hunk binding, check to make sure the current stream has the correct contents. */ @@ -2194,7 +2226,6 @@ can_reuse_hunk (c_parser *parser, struct parsed_hunk *hunk, *out_set = *set_slot; - info.parser = parser; info.hunk = hunk; info.binding = NULL; info.self_iter = NULL; |