re PR tree-optimization/26854 (Inordinate compile times on large routines)

PR tree-optimization/26854
	* c-decl.c (struct c_scope): Add field has_jump_unsafe_decl.
	(decl_jump_unsafe): Move higher in file, with no other change.
	(bind): Set has_jump_unsafe_decl if appropriate.
	(update_label_decls): Test has_jump_unsafe_decl to avoid loop.
	(check_earlier_gotos): Likewise.
	(c_check_switch_jump_warnings): Likewise.

From-SVN: r169267
This commit is contained in:
Ian Lance Taylor 2011-01-26 01:26:48 +00:00 committed by Ian Lance Taylor
parent 70187f017b
commit 744f0946bc
2 changed files with 84 additions and 45 deletions

View file

@ -1,3 +1,13 @@
2011-01-25 Ian Lance Taylor <iant@google.com>
PR tree-optimization/26854
* c-decl.c (struct c_scope): Add field has_jump_unsafe_decl.
(decl_jump_unsafe): Move higher in file, with no other change.
(bind): Set has_jump_unsafe_decl if appropriate.
(update_label_decls): Test has_jump_unsafe_decl to avoid loop.
(check_earlier_gotos): Likewise.
(c_check_switch_jump_warnings): Likewise.
2011-01-25 Jonathan Wakely <jwakely.gcc@gmail.com>
* doc/invoke.texi (Warning Options): Add missing hyphen.

View file

@ -404,6 +404,13 @@ struct GTY((chain_next ("%h.outer"))) c_scope {
up searching for labels when popping scopes, particularly since
labels are normally only found at function scope. */
BOOL_BITFIELD has_label_bindings : 1;
/* True if we should issue a warning if a goto statement crosses any
of the bindings. We still need to check the list of bindings to
find the specific ones we need to warn about. This is true if
decl_jump_unsafe would return true for any of the bindings. This
is used to avoid looping over all the bindings unnecessarily. */
BOOL_BITFIELD has_jump_unsafe_decl : 1;
};
/* The scope currently in effect. */
@ -554,6 +561,31 @@ add_stmt (tree t)
return t;
}
/* Return true if we will want to say something if a goto statement
crosses DECL. */
static bool
decl_jump_unsafe (tree decl)
{
if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
return false;
/* Always warn about crossing variably modified types. */
if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL)
&& variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
return true;
/* Otherwise, only warn if -Wgoto-misses-init and this is an
initialized automatic decl. */
if (warn_jump_misses_init
&& TREE_CODE (decl) == VAR_DECL
&& !TREE_STATIC (decl)
&& DECL_INITIAL (decl) != NULL_TREE)
return true;
return false;
}
void
c_print_identifier (FILE *file, tree node, int indent)
@ -602,6 +634,9 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible,
b->prev = scope->bindings;
scope->bindings = b;
if (decl_jump_unsafe (decl))
scope->has_jump_unsafe_decl = 1;
if (!name)
return;
@ -758,31 +793,6 @@ set_spot_bindings (struct c_spot_bindings *p, bool defining)
p->left_stmt_expr = false;
}
/* Return true if we will want to say something if a goto statement
crosses DECL. */
static bool
decl_jump_unsafe (tree decl)
{
if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
return false;
/* Always warn about crossing variably modified types. */
if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL)
&& variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
return true;
/* Otherwise, only warn if -Wgoto-misses-init and this is an
initialized automatic decl. */
if (warn_jump_misses_init
&& TREE_CODE (decl) == VAR_DECL
&& !TREE_STATIC (decl)
&& DECL_INITIAL (decl) != NULL_TREE)
return true;
return false;
}
/* Update spot bindings P as we pop out of SCOPE. Return true if we
should push decls for a label. */
@ -969,6 +979,7 @@ update_label_decls (struct c_scope *scope)
{
struct c_label_vars *label_vars;
struct c_binding *b1;
bool hjud;
unsigned int ix;
struct c_goto_bindings *g;
@ -977,18 +988,26 @@ update_label_decls (struct c_scope *scope)
label_vars = b->u.label;
b1 = label_vars->label_bindings.bindings_in_scope;
if (label_vars->label_bindings.scope == NULL)
hjud = false;
else
hjud = label_vars->label_bindings.scope->has_jump_unsafe_decl;
if (update_spot_bindings (scope, &label_vars->label_bindings))
{
/* This label is defined in this scope. */
for (; b1 != NULL; b1 = b1->prev)
if (hjud)
{
/* A goto from later in the function to this
label will never see the initialization of
B1, if any. Save it to issue a warning if
needed. */
if (decl_jump_unsafe (b1->decl))
VEC_safe_push (tree, gc, label_vars->decls_in_scope,
b1->decl);
for (; b1 != NULL; b1 = b1->prev)
{
/* A goto from later in the function to this
label will never see the initialization
of B1, if any. Save it to issue a
warning if needed. */
if (decl_jump_unsafe (b1->decl))
VEC_safe_push (tree, gc,
label_vars->decls_in_scope,
b1->decl);
}
}
}
@ -3165,12 +3184,15 @@ check_earlier_gotos (tree label, struct c_label_vars* label_vars)
/* We have a goto to this label. The goto is going forward. In
g->scope, the goto is going to skip any binding which was
defined after g->bindings_in_scope. */
for (b = g->goto_bindings.scope->bindings;
b != g->goto_bindings.bindings_in_scope;
b = b->prev)
if (g->goto_bindings.scope->has_jump_unsafe_decl)
{
if (decl_jump_unsafe (b->decl))
warn_about_goto (g->loc, label, b->decl);
for (b = g->goto_bindings.scope->bindings;
b != g->goto_bindings.bindings_in_scope;
b = b->prev)
{
if (decl_jump_unsafe (b->decl))
warn_about_goto (g->loc, label, b->decl);
}
}
/* We also need to warn about decls defined in any scopes
@ -3180,14 +3202,17 @@ check_earlier_gotos (tree label, struct c_label_vars* label_vars)
scope = scope->outer)
{
gcc_assert (scope != NULL);
if (scope == label_vars->label_bindings.scope)
b = label_vars->label_bindings.bindings_in_scope;
else
b = scope->bindings;
for (; b != NULL; b = b->prev)
if (scope->has_jump_unsafe_decl)
{
if (decl_jump_unsafe (b->decl))
warn_about_goto (g->loc, label, b->decl);
if (scope == label_vars->label_bindings.scope)
b = label_vars->label_bindings.bindings_in_scope;
else
b = scope->bindings;
for (; b != NULL; b = b->prev)
{
if (decl_jump_unsafe (b->decl))
warn_about_goto (g->loc, label, b->decl);
}
}
}
@ -3303,6 +3328,10 @@ c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings,
struct c_binding *b;
gcc_assert (scope != NULL);
if (!scope->has_jump_unsafe_decl)
continue;
for (b = scope->bindings; b != NULL; b = b->prev)
{
if (decl_jump_unsafe (b->decl))