Commit 744f0946 by Ian Lance Taylor Committed by Ian Lance Taylor

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
parent 70187f01
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> 2011-01-25 Jonathan Wakely <jwakely.gcc@gmail.com>
* doc/invoke.texi (Warning Options): Add missing hyphen. * doc/invoke.texi (Warning Options): Add missing hyphen.
......
...@@ -404,6 +404,13 @@ struct GTY((chain_next ("%h.outer"))) c_scope { ...@@ -404,6 +404,13 @@ struct GTY((chain_next ("%h.outer"))) c_scope {
up searching for labels when popping scopes, particularly since up searching for labels when popping scopes, particularly since
labels are normally only found at function scope. */ labels are normally only found at function scope. */
BOOL_BITFIELD has_label_bindings : 1; 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. */ /* The scope currently in effect. */
...@@ -554,6 +561,31 @@ add_stmt (tree t) ...@@ -554,6 +561,31 @@ add_stmt (tree t)
return 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 void
c_print_identifier (FILE *file, tree node, int indent) c_print_identifier (FILE *file, tree node, int indent)
...@@ -602,6 +634,9 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible, ...@@ -602,6 +634,9 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible,
b->prev = scope->bindings; b->prev = scope->bindings;
scope->bindings = b; scope->bindings = b;
if (decl_jump_unsafe (decl))
scope->has_jump_unsafe_decl = 1;
if (!name) if (!name)
return; return;
...@@ -758,31 +793,6 @@ set_spot_bindings (struct c_spot_bindings *p, bool defining) ...@@ -758,31 +793,6 @@ set_spot_bindings (struct c_spot_bindings *p, bool defining)
p->left_stmt_expr = false; 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 /* Update spot bindings P as we pop out of SCOPE. Return true if we
should push decls for a label. */ should push decls for a label. */
...@@ -969,6 +979,7 @@ update_label_decls (struct c_scope *scope) ...@@ -969,6 +979,7 @@ update_label_decls (struct c_scope *scope)
{ {
struct c_label_vars *label_vars; struct c_label_vars *label_vars;
struct c_binding *b1; struct c_binding *b1;
bool hjud;
unsigned int ix; unsigned int ix;
struct c_goto_bindings *g; struct c_goto_bindings *g;
...@@ -977,18 +988,26 @@ update_label_decls (struct c_scope *scope) ...@@ -977,18 +988,26 @@ update_label_decls (struct c_scope *scope)
label_vars = b->u.label; label_vars = b->u.label;
b1 = label_vars->label_bindings.bindings_in_scope; 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)) if (update_spot_bindings (scope, &label_vars->label_bindings))
{ {
/* This label is defined in this scope. */ /* This label is defined in this scope. */
for (; b1 != NULL; b1 = b1->prev) if (hjud)
{ {
/* A goto from later in the function to this for (; b1 != NULL; b1 = b1->prev)
label will never see the initialization of {
B1, if any. Save it to issue a warning if /* A goto from later in the function to this
needed. */ label will never see the initialization
if (decl_jump_unsafe (b1->decl)) of B1, if any. Save it to issue a
VEC_safe_push (tree, gc, label_vars->decls_in_scope, warning if needed. */
b1->decl); 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) ...@@ -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 /* 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 g->scope, the goto is going to skip any binding which was
defined after g->bindings_in_scope. */ defined after g->bindings_in_scope. */
for (b = g->goto_bindings.scope->bindings; if (g->goto_bindings.scope->has_jump_unsafe_decl)
b != g->goto_bindings.bindings_in_scope;
b = b->prev)
{ {
if (decl_jump_unsafe (b->decl)) for (b = g->goto_bindings.scope->bindings;
warn_about_goto (g->loc, label, b->decl); 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 /* 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) ...@@ -3180,14 +3202,17 @@ check_earlier_gotos (tree label, struct c_label_vars* label_vars)
scope = scope->outer) scope = scope->outer)
{ {
gcc_assert (scope != NULL); gcc_assert (scope != NULL);
if (scope == label_vars->label_bindings.scope) if (scope->has_jump_unsafe_decl)
b = label_vars->label_bindings.bindings_in_scope;
else
b = scope->bindings;
for (; b != NULL; b = b->prev)
{ {
if (decl_jump_unsafe (b->decl)) if (scope == label_vars->label_bindings.scope)
warn_about_goto (g->loc, label, b->decl); 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, ...@@ -3303,6 +3328,10 @@ c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings,
struct c_binding *b; struct c_binding *b;
gcc_assert (scope != NULL); gcc_assert (scope != NULL);
if (!scope->has_jump_unsafe_decl)
continue;
for (b = scope->bindings; b != NULL; b = b->prev) for (b = scope->bindings; b != NULL; b = b->prev)
{ {
if (decl_jump_unsafe (b->decl)) if (decl_jump_unsafe (b->decl))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment