This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tree-ssa] Fix variables getting out of their scope
Hello,
> > > > Changelog:
> > > > * tree-flow.h (struct block_tree): New.
> > > > (block_tree): Declare.
> > > >
> > > Why is this necessary? Why not use the existing BLOCK_* macros? As we
> > > build the CFG we annotate statements with the BLOCK that contains them.
> >
> > I am not quite sure what you refer to here? Neither stmt_ann_d nor
> > bb_ann_d contain anything that seems related.
> >
> Sorry, I wasn't very clear. What I mean is that instead of creating a
> new struct block_tree, we could just record the BLOCK where each
> statement belongs.
>
> When you start building the basic blocks for the function, you start
> pointing all statements to DECL_INITIAL (fndecl). Then every time you
> find a BIND_EXPR statement, you set the current block to be
> BIND_EXPR_BLOCK(stmt) so that statements inside that BIND_EXPR get
> associated with the new block.
>
> In stmt_ann_d and bb_ann_d you just need a 'tree' field to record the
> block where the statement/block belongs to.
here is the updated patch. I still don't use BLOCK_* stuff, because
I don't know how would I get from BLOCK back to BIND_EXPR; so I
just remember the BIND_EXPR + level in statement annotations.
Zdenek
* tree-flow.h (struct var_ann_d): New field scope.
(struct stmt_ann_d): New field scope.
(propagate_copy): Declaration changed.
* tree-cfg.c (make_blocks, make_cond_expr_blocks,
make_catch_expr_blocks, make_eh_filter_expr_blocks,
make_try_expr_blocks, make_loop_expr_blocks, make_switch_expr_blocks,
make_bind_expr_blocks, build_tree_cfg): Assign variables and statements
to scopes.
(assign_vars_to_scope): New.
* tree-ssa-copyprop.c (move_var_to_scope): New.
(copyprop_stmt): Pass scope of statement to propagate_copy.
(propagate_copy): Assign variable to the right bind_expr.
* tree-ssa-dom.c (optimize_stmt): Pass scope of statement to
propagate_copy.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.147
diff -c -3 -p -r1.1.4.147 tree-cfg.c
*** tree-cfg.c 14 Aug 2003 15:37:55 -0000 1.1.4.147
--- tree-cfg.c 14 Aug 2003 21:56:53 -0000
*************** static void create_blocks_annotations (v
*** 84,97 ****
static void create_block_annotation (basic_block);
static void free_blocks_annotations (void);
static void clear_blocks_annotations (void);
! static basic_block make_blocks (tree *, tree, tree, basic_block);
! static void make_cond_expr_blocks (tree *, tree, basic_block);
! static void make_catch_expr_blocks (tree *, tree, basic_block);
! static void make_eh_filter_expr_blocks (tree *, tree, basic_block);
! static void make_try_expr_blocks (tree *, tree, basic_block);
! static void make_loop_expr_blocks (tree *, basic_block);
! static void make_switch_expr_blocks (tree *, tree, basic_block);
! static basic_block make_bind_expr_blocks (tree *, tree, basic_block, tree);
static inline void add_stmt_to_bb (tree *, basic_block, tree);
static inline void append_stmt_to_bb (tree *, basic_block, tree);
static inline void set_parent_stmt (tree *, tree);
--- 84,98 ----
static void create_block_annotation (basic_block);
static void free_blocks_annotations (void);
static void clear_blocks_annotations (void);
! static basic_block make_blocks (tree *, tree, tree, basic_block, tree);
! static void make_loop_expr_blocks (tree *, basic_block, tree);
! static void make_cond_expr_blocks (tree *, tree, basic_block, tree);
! static void make_catch_expr_blocks (tree *, tree, basic_block, tree);
! static void make_eh_filter_expr_blocks (tree *, tree, basic_block, tree);
! static void make_try_expr_blocks (tree *, tree, basic_block, tree);
! static void make_switch_expr_blocks (tree *, tree, basic_block, tree);
! static basic_block make_bind_expr_blocks (tree *, tree, basic_block, tree,
! tree);
static inline void add_stmt_to_bb (tree *, basic_block, tree);
static inline void append_stmt_to_bb (tree *, basic_block, tree);
static inline void set_parent_stmt (tree *, tree);
*************** static void make_goto_expr_edges (basic_
*** 106,111 ****
--- 107,113 ----
static void make_case_label_edges (basic_block);
/* Various helpers. */
+ static void assign_vars_to_scope (tree);
static basic_block successor_block (basic_block);
static basic_block last_exec_block (tree *);
static tree *first_exec_stmt (tree *);
*************** build_tree_cfg (tree fnbody)
*** 261,267 ****
first_p = first_exec_stmt (&BIND_EXPR_BODY (fnbody));
if (first_p)
{
! make_blocks (first_p, NULL_TREE, NULL, NULL);
if (n_basic_blocks > 0)
{
--- 263,269 ----
first_p = first_exec_stmt (&BIND_EXPR_BODY (fnbody));
if (first_p)
{
! make_blocks (first_p, NULL_TREE, NULL, NULL, fnbody);
if (n_basic_blocks > 0)
{
*************** clear_blocks_annotations (void)
*** 381,393 ****
BB is the block where the statements should be added to. If BB is NULL,
a new basic block will be created for the statements.
Return the last basic block added to the graph. This is used to know if
a recursive invocation built a sub-graph whose last block can accept
more statements or not. */
static basic_block
make_blocks (tree *first_p, tree next_block_link, tree parent_stmt,
! basic_block bb)
{
tree_stmt_iterator i;
tree stmt, last;
--- 383,397 ----
BB is the block where the statements should be added to. If BB is NULL,
a new basic block will be created for the statements.
+ SCOPE is the actual bind block.
+
Return the last basic block added to the graph. This is used to know if
a recursive invocation built a sub-graph whose last block can accept
more statements or not. */
static basic_block
make_blocks (tree *first_p, tree next_block_link, tree parent_stmt,
! basic_block bb, tree scope)
{
tree_stmt_iterator i;
tree stmt, last;
*************** make_blocks (tree *first_p, tree next_bl
*** 423,441 ****
/* Now add STMT to BB and create the subgraphs for special statement
codes. */
append_stmt_to_bb (stmt_p, bb, parent_stmt);
if (code == LOOP_EXPR)
! make_loop_expr_blocks (stmt_p, bb);
else if (code == COND_EXPR)
! make_cond_expr_blocks (stmt_p, next_block_link, bb);
else if (code == SWITCH_EXPR)
! make_switch_expr_blocks (stmt_p, next_block_link, bb);
else if (code == CATCH_EXPR)
! make_catch_expr_blocks (stmt_p, next_block_link, bb);
else if (code == EH_FILTER_EXPR)
! make_eh_filter_expr_blocks (stmt_p, next_block_link, bb);
else if (code == TRY_CATCH_EXPR || code == TRY_FINALLY_EXPR)
! make_try_expr_blocks (stmt_p, next_block_link, bb);
else if (code == BIND_EXPR)
{
int num_blocks_before;
--- 427,446 ----
/* Now add STMT to BB and create the subgraphs for special statement
codes. */
append_stmt_to_bb (stmt_p, bb, parent_stmt);
+ get_stmt_ann (stmt)->scope = scope;
if (code == LOOP_EXPR)
! make_loop_expr_blocks (stmt_p, bb, scope);
else if (code == COND_EXPR)
! make_cond_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == SWITCH_EXPR)
! make_switch_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == CATCH_EXPR)
! make_catch_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == EH_FILTER_EXPR)
! make_eh_filter_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == TRY_CATCH_EXPR || code == TRY_FINALLY_EXPR)
! make_try_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == BIND_EXPR)
{
int num_blocks_before;
*************** make_blocks (tree *first_p, tree next_bl
*** 447,455 ****
will be the last basic block of the BIND_EXPR's subgraph. We
point STMT to LAST_BB's last statement to determine if we
should start a new block or not. */
! num_blocks_before = n_basic_blocks;
last_bb = make_bind_expr_blocks (stmt_p, next_block_link, bb,
! parent_stmt);
if (last_bb)
{
bb = last_bb;
--- 452,463 ----
will be the last basic block of the BIND_EXPR's subgraph. We
point STMT to LAST_BB's last statement to determine if we
should start a new block or not. */
! num_blocks_before = n_basic_blocks;
! assign_vars_to_scope (stmt);
! stmt_ann (stmt)->scope_level = get_stmt_ann (scope)->scope_level + 1;
!
last_bb = make_bind_expr_blocks (stmt_p, next_block_link, bb,
! parent_stmt, stmt);
if (last_bb)
{
bb = last_bb;
*************** could_trap_p (tree expr)
*** 544,550 ****
ENTRY is the block whose last statement is *LOOP_P. */
static void
! make_loop_expr_blocks (tree *loop_p, basic_block entry)
{
tree_stmt_iterator si;
tree loop = *loop_p;
--- 552,558 ----
ENTRY is the block whose last statement is *LOOP_P. */
static void
! make_loop_expr_blocks (tree *loop_p, basic_block entry, tree scope)
{
tree_stmt_iterator si;
tree loop = *loop_p;
*************** make_loop_expr_blocks (tree *loop_p, bas
*** 578,584 ****
next_block_link = *(tsi_container (si));
}
! make_blocks (&LOOP_EXPR_BODY (loop), next_block_link, loop, NULL);
}
--- 586,592 ----
next_block_link = *(tsi_container (si));
}
! make_blocks (&LOOP_EXPR_BODY (loop), next_block_link, loop, NULL, scope);
}
*************** make_loop_expr_blocks (tree *loop_p, bas
*** 589,599 ****
lexical scope, this will be the statement that comes after COND_P's
container (see the documentation for NEXT_BLOCK_LINK).
! ENTRY is the block whose last statement is *COND_P. */
static void
make_cond_expr_blocks (tree *cond_p, tree next_block_link,
! basic_block entry)
{
tree_stmt_iterator si;
tree cond = *cond_p;
--- 597,609 ----
lexical scope, this will be the statement that comes after COND_P's
container (see the documentation for NEXT_BLOCK_LINK).
! ENTRY is the block whose last statement is *COND_P.
!
! SCOPE is the bind scope to that it belongs. */
static void
make_cond_expr_blocks (tree *cond_p, tree next_block_link,
! basic_block entry, tree scope)
{
tree_stmt_iterator si;
tree cond = *cond_p;
*************** make_cond_expr_blocks (tree *cond_p, tre
*** 611,618 ****
next_block_link = *(tsi_container (si));
STRIP_CONTAINERS (cond);
! make_blocks (&COND_EXPR_THEN (cond), next_block_link, cond, NULL);
! make_blocks (&COND_EXPR_ELSE (cond), next_block_link, cond, NULL);
}
/* Derive an exception handling region type from STMT. */
--- 621,628 ----
next_block_link = *(tsi_container (si));
STRIP_CONTAINERS (cond);
! make_blocks (&COND_EXPR_THEN (cond), next_block_link, cond, NULL, scope);
! make_blocks (&COND_EXPR_ELSE (cond), next_block_link, cond, NULL, scope);
}
/* Derive an exception handling region type from STMT. */
*************** get_eh_region_type (tree stmt)
*** 639,645 ****
static void
make_try_expr_blocks (tree *expr_p, tree next_block_link,
! basic_block entry)
{
tree_stmt_iterator si;
tree expr = *expr_p;
--- 649,655 ----
static void
make_try_expr_blocks (tree *expr_p, tree next_block_link,
! basic_block entry, tree scope)
{
tree_stmt_iterator si;
tree expr = *expr_p;
*************** make_try_expr_blocks (tree *expr_p, tree
*** 663,675 ****
VARRAY_PUSH_TREE (eh_stack, expr);
/* Make blocks for the TRY block. */
! make_blocks (&TREE_OPERAND (expr, 0), next_block_link, expr, NULL);
/* And pop the stack of exception handlers. */
VARRAY_POP (eh_stack);
/* Make blocks for the handler itself. */
! make_blocks (&TREE_OPERAND (expr, 1), next_block_link, expr, NULL);
/* If this is a cleanup, then record which cleanup higher in the
stack it can directly reach. */
--- 673,685 ----
VARRAY_PUSH_TREE (eh_stack, expr);
/* Make blocks for the TRY block. */
! make_blocks (&TREE_OPERAND (expr, 0), next_block_link, expr, NULL, scope);
/* And pop the stack of exception handlers. */
VARRAY_POP (eh_stack);
/* Make blocks for the handler itself. */
! make_blocks (&TREE_OPERAND (expr, 1), next_block_link, expr, NULL, scope);
/* If this is a cleanup, then record which cleanup higher in the
stack it can directly reach. */
*************** make_try_expr_blocks (tree *expr_p, tree
*** 686,692 ****
static void
make_catch_expr_blocks (tree *expr_p, tree next_block_link,
! basic_block entry)
{
tree_stmt_iterator si;
tree expr = *expr_p;
--- 696,702 ----
static void
make_catch_expr_blocks (tree *expr_p, tree next_block_link,
! basic_block entry, tree scope)
{
tree_stmt_iterator si;
tree expr = *expr_p;
*************** make_catch_expr_blocks (tree *expr_p, tr
*** 701,714 ****
tsi_next (&si);
STRIP_CONTAINERS (expr);
! make_blocks (&CATCH_BODY (expr), next_block_link, expr, NULL);
}
/* Create the blocks for the EH_FILTER_EXPR node pointed to by expr_p. */
static void
make_eh_filter_expr_blocks (tree *expr_p, tree next_block_link,
! basic_block entry)
{
tree_stmt_iterator si;
tree expr = *expr_p;
--- 711,724 ----
tsi_next (&si);
STRIP_CONTAINERS (expr);
! make_blocks (&CATCH_BODY (expr), next_block_link, expr, NULL, scope);
}
/* Create the blocks for the EH_FILTER_EXPR node pointed to by expr_p. */
static void
make_eh_filter_expr_blocks (tree *expr_p, tree next_block_link,
! basic_block entry, tree scope)
{
tree_stmt_iterator si;
tree expr = *expr_p;
*************** make_eh_filter_expr_blocks (tree *expr_p
*** 723,729 ****
tsi_next (&si);
STRIP_CONTAINERS (expr);
! make_blocks (&EH_FILTER_FAILURE (expr), next_block_link, expr, NULL);
}
--- 733,739 ----
tsi_next (&si);
STRIP_CONTAINERS (expr);
! make_blocks (&EH_FILTER_FAILURE (expr), next_block_link, expr, NULL, scope);
}
*************** make_eh_filter_expr_blocks (tree *expr_p
*** 738,744 ****
static void
make_switch_expr_blocks (tree *switch_e_p, tree next_block_link,
! basic_block entry)
{
tree_stmt_iterator si;
tree switch_e = *switch_e_p;
--- 748,754 ----
static void
make_switch_expr_blocks (tree *switch_e_p, tree next_block_link,
! basic_block entry, tree scope)
{
tree_stmt_iterator si;
tree switch_e = *switch_e_p;
*************** make_switch_expr_blocks (tree *switch_e_
*** 756,762 ****
next_block_link = *(tsi_container (si));
STRIP_CONTAINERS (switch_e);
! make_blocks (&SWITCH_BODY (switch_e), next_block_link, switch_e, NULL);
}
--- 766,772 ----
next_block_link = *(tsi_container (si));
STRIP_CONTAINERS (switch_e);
! make_blocks (&SWITCH_BODY (switch_e), next_block_link, switch_e, NULL, scope);
}
*************** make_switch_expr_blocks (tree *switch_e_
*** 779,785 ****
static basic_block
make_bind_expr_blocks (tree *bind_p, tree next_block_link,
! basic_block entry, tree parent_stmt)
{
tree_stmt_iterator si;
tree bind = *bind_p;
--- 789,795 ----
static basic_block
make_bind_expr_blocks (tree *bind_p, tree next_block_link,
! basic_block entry, tree parent_stmt, tree scope)
{
tree_stmt_iterator si;
tree bind = *bind_p;
*************** make_bind_expr_blocks (tree *bind_p, tre
*** 803,809 ****
ends with a block terminating statement. */
STRIP_CONTAINERS (bind);
return make_blocks (&BIND_EXPR_BODY (bind), next_block_link, parent_stmt,
! entry);
}
--- 813,819 ----
ends with a block terminating statement. */
STRIP_CONTAINERS (bind);
return make_blocks (&BIND_EXPR_BODY (bind), next_block_link, parent_stmt,
! entry, scope);
}
*************** tree_loop_optimizer_finalize (struct loo
*** 5066,5069 ****
--- 5076,5089 ----
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
+ }
+
+ /* Assigns a scope to variables defined in bind_expr SCOPE. */
+ static void
+ assign_vars_to_scope (tree scope)
+ {
+ tree var;
+
+ for (var = BIND_EXPR_VARS (scope); var; var = TREE_CHAIN (var))
+ get_var_ann (var)->scope = scope;
}
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.101
diff -c -3 -p -r1.1.4.101 tree-flow.h
*** tree-flow.h 8 Aug 2003 00:27:10 -0000 1.1.4.101
--- tree-flow.h 14 Aug 2003 21:56:54 -0000
*************** struct var_ann_d GTY(())
*** 120,125 ****
--- 120,128 ----
/* Used by the root-var object in tree-ssa-live.[ch]. */
unsigned root_index;
+
+ /* The bind_expr in that the variable is declared. */
+ tree scope;
};
*************** struct stmt_ann_d GTY(())
*** 232,237 ****
--- 235,246 ----
/* Array of variables that have had their address taken in the statement. */
varray_type addresses_taken;
+
+ /* The binding block to that the statement belongs. */
+ tree scope;
+
+ /* For BIND_EXPRs, a level of the scope. */
+ int scope_level;
};
*************** void tree_ssa_dce (tree);
*** 489,495 ****
/* In tree-ssa-copyprop.c */
void tree_ssa_copyprop (tree);
! void propagate_copy (tree *, tree);
/* In tree-flow-inline.h */
--- 498,504 ----
/* In tree-ssa-copyprop.c */
void tree_ssa_copyprop (tree);
! void propagate_copy (tree *, tree, tree);
/* In tree-flow-inline.h */
Index: tree-ssa-copyprop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-copyprop.c,v
retrieving revision 1.1.2.11
diff -c -3 -p -r1.1.2.11 tree-ssa-copyprop.c
*** tree-ssa-copyprop.c 28 Jul 2003 17:16:20 -0000 1.1.2.11
--- tree-ssa-copyprop.c 14 Aug 2003 21:56:54 -0000
*************** static int dump_flags;
*** 45,50 ****
--- 45,51 ----
static void copyprop_stmt (tree);
static void copyprop_phi (tree);
static inline tree get_original (tree);
+ static void move_var_to_scope (tree, tree, tree);
/* Main entry point to the copy propagator. The algorithm is a simple
*************** copyprop_stmt (tree stmt)
*** 122,128 ****
fprintf (dump_file, "\n");
}
! propagate_copy (use_p, orig);
modified = true;
}
}
--- 123,129 ----
fprintf (dump_file, "\n");
}
! propagate_copy (use_p, orig, stmt_ann (stmt)->scope);
modified = true;
}
}
*************** get_original (tree var)
*** 204,214 ****
/* Replace the operand pointed to by OP_P with variable VAR. If *OP_P is a
pointer, copy the memory tag used originally by *OP_P into VAR. This is
! needed in cases where VAR had never been dereferenced in the program. */
void
! propagate_copy (tree *op_p, tree var)
{
#if defined ENABLE_CHECKING
if (!may_propagate_copy (*op_p, var))
abort ();
--- 205,219 ----
/* Replace the operand pointed to by OP_P with variable VAR. If *OP_P is a
pointer, copy the memory tag used originally by *OP_P into VAR. This is
! needed in cases where VAR had never been dereferenced in the program.
!
! SCOPE is the bind block in that the *OP_P occurs. */
void
! propagate_copy (tree *op_p, tree var, tree scope)
{
+ tree old_scope;
+
#if defined ENABLE_CHECKING
if (!may_propagate_copy (*op_p, var))
abort ();
*************** propagate_copy (tree *op_p, tree var)
*** 225,228 ****
--- 230,286 ----
}
*op_p = var;
+
+ old_scope = var_ann (SSA_NAME_VAR (var))->scope;
+ /* If there is no old_scope, it is a newly created temporary, i.e. it is
+ in the topmost bind_expr and we have nothing to do. */
+ if (old_scope)
+ {
+ if (!scope)
+ scope = DECL_SAVED_TREE (current_function_decl);
+ else
+ {
+ while (stmt_ann (scope)->scope_level
+ > stmt_ann (old_scope)->scope_level)
+ scope = stmt_ann (scope)->scope;
+ }
+ if (scope != old_scope)
+ move_var_to_scope (SSA_NAME_VAR (var), old_scope,
+ DECL_SAVED_TREE (current_function_decl));
+ }
+ }
+
+ /* Moves variable VAR from OLD_SCOPE to SCOPE. */
+ static void
+ move_var_to_scope (tree var, tree old_scope, tree scope)
+ {
+ tree avar, prev;
+ tree block = BIND_EXPR_BLOCK (old_scope);
+
+ prev = NULL_TREE;
+ for (avar = BIND_EXPR_VARS (old_scope);
+ avar;
+ prev = avar, avar = TREE_CHAIN (avar))
+ if (avar == var)
+ break;
+ if (!avar)
+ abort ();
+
+ if (block)
+ remove_decl (avar, block);
+ else
+ remove_decl (avar, DECL_INITIAL (current_function_decl));
+
+ if (prev)
+ TREE_CHAIN (prev) = TREE_CHAIN (avar);
+ else
+ BIND_EXPR_VARS (old_scope) = TREE_CHAIN (avar);
+
+ TREE_CHAIN (var) = BIND_EXPR_VARS (scope);
+ BIND_EXPR_VARS (scope) = var;
+ var_ann (var)->scope = scope;
+
+ /* Dwarf2out ices (in add_abstract_origin_attribute) when it encounters
+ variable that is not declared, but has DECL_ABSTRACT_ORIGIN set. */
+ DECL_ABSTRACT_ORIGIN (var) = NULL_TREE;
}
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.22
diff -c -3 -p -r1.1.2.22 tree-ssa-dom.c
*** tree-ssa-dom.c 14 Aug 2003 13:22:31 -0000 1.1.2.22
--- tree-ssa-dom.c 14 Aug 2003 21:56:55 -0000
*************** optimize_stmt (block_stmt_iterator si, v
*** 602,608 ****
addr_expr_propagated_p = true;
if (TREE_CODE (val) == SSA_NAME)
! propagate_copy (op_p, val);
else
*op_p = val;
--- 602,608 ----
addr_expr_propagated_p = true;
if (TREE_CODE (val) == SSA_NAME)
! propagate_copy (op_p, val, stmt_ann (stmt)->scope);
else
*op_p = val;
*************** optimize_stmt (block_stmt_iterator si, v
*** 664,670 ****
}
opt_stats.num_re++;
! *expr_p = cached_lhs;
ann->modified = 1;
}
}
--- 664,679 ----
}
opt_stats.num_re++;
! if (TREE_CODE (cached_lhs) == SSA_NAME)
! {
! *expr_p = cached_lhs;
! /* This takes care of moving the variable to the right scope.
! The assignment above is here so that it indeed looks like
! copy propagation. */
! propagate_copy (expr_p, cached_lhs, stmt_ann (stmt)->scope);
! }
! else
! *expr_p = cached_lhs;
ann->modified = 1;
}
}