diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3151fe0789..e867fbe56ee 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2004-11-23 Kazu Hirata + + * tree-cfg.c (tree_execute_on_growing_pred): New. + (tree_cfg_hooks): Add tree_execute_on_growing_pred. + * tree-flow.h: Add a prototype for + reserve_phi_args_for_new_edge. + * tree-phinodes.c (reserve_phi_args_for_new_edge): New. + (add_phi_arg): Don't resize a PHI array. + 2004-11-23 Ralf Corsepius * config.gcc: Add avr-*-rtems*. diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index e9c58d418c7..1f934cb7ec5 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -5339,6 +5339,18 @@ tree_purge_all_dead_eh_edges (bitmap blocks) return changed; } +/* This function is called whenever a new edge is created or + redirected. */ + +static void +tree_execute_on_growing_pred (edge e) +{ + basic_block bb = e->dest; + + if (phi_nodes (bb)) + reserve_phi_args_for_new_edge (bb); +} + /* This function is called immediately before edge E is removed from the edge vector E->dest->preds. */ @@ -5371,7 +5383,7 @@ struct cfg_hooks tree_cfg_hooks = { tree_block_ends_with_call_p, /* block_ends_with_call_p */ tree_block_ends_with_condjump_p, /* block_ends_with_condjump_p */ tree_flow_call_edges_add, /* flow_call_edges_add */ - NULL, /* execute_on_growing_pred */ + tree_execute_on_growing_pred, /* execute_on_growing_pred */ tree_execute_on_shrinking_pred, /* execute_on_shrinking_pred */ }; diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 45e2096f03b..96e368dc355 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -508,6 +508,7 @@ extern void dump_generic_bb (FILE *, basic_block, int, int); extern var_ann_t create_var_ann (tree); extern stmt_ann_t create_stmt_ann (tree); extern tree_ann_t create_tree_ann (tree); +extern void reserve_phi_args_for_new_edge (basic_block); extern tree create_phi_node (tree, basic_block); extern void add_phi_arg (tree *, tree, edge); extern void remove_phi_args (edge); diff --git a/gcc/tree-phinodes.c b/gcc/tree-phinodes.c index a6be8383855..031a606d0c6 100644 --- a/gcc/tree-phinodes.c +++ b/gcc/tree-phinodes.c @@ -269,6 +269,33 @@ resize_phi_node (tree *phi, int len) *phi = new_phi; } +/* Reserve PHI arguments for a new edge to basic block BB. */ + +void +reserve_phi_args_for_new_edge (basic_block bb) +{ + tree *loc; + int len = EDGE_COUNT (bb->preds); + int cap = ideal_phi_node_len (len + 4); + + for (loc = &(bb_ann (bb)->phi_nodes); + *loc; + loc = &PHI_CHAIN (*loc)) + { + if (len > PHI_ARG_CAPACITY (*loc)) + { + tree old_phi = *loc; + + resize_phi_node (loc, cap); + + /* The result of the phi is defined by this phi node. */ + SSA_NAME_DEF_STMT (PHI_RESULT (*loc)) = *loc; + + release_phi_node (old_phi); + } + } +} + /* Create a new PHI node for variable VAR at basic block BB. */ tree @@ -302,38 +329,9 @@ add_phi_arg (tree *phi, tree def, edge e) gcc_assert (bb == bb_for_stmt (*phi)); - if (i >= PHI_ARG_CAPACITY (*phi)) - { - tree old_phi = *phi; - - /* Resize the phi. Unfortunately, this will relocate it. */ - resize_phi_node (phi, ideal_phi_node_len (i + 4)); - - /* resize_phi_node will necessarily relocate the phi. */ - gcc_assert (*phi != old_phi); - - /* The result of the phi is defined by this phi node. */ - SSA_NAME_DEF_STMT (PHI_RESULT (*phi)) = *phi; - - release_phi_node (old_phi); - - /* Update the list head if replacing the first listed phi. */ - if (phi_nodes (bb) == old_phi) - bb_ann (bb)->phi_nodes = *phi; - else - { - /* Traverse the list looking for the phi node to chain to. */ - tree p; - - for (p = phi_nodes (bb); - p && PHI_CHAIN (p) != old_phi; - p = PHI_CHAIN (p)) - ; - - gcc_assert (p); - PHI_CHAIN (p) = *phi; - } - } + /* We resize PHI nodes upon edge creation. We should always have + enough room at this point. */ + gcc_assert (PHI_NUM_ARGS (*phi) < PHI_ARG_CAPACITY (*phi)); /* Copy propagation needs to know what object occur in abnormal PHI nodes. This is a convenient place to record such information. */