diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a179d15064c..fd052fbe3a5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2008-03-05 Aldy Hernandez + + * cfg.c: Include tree-flow.h. + (remove_edge_raw): Call redirect_edge_var_map_clear. + (redirect_edge_succ_nodup): Call redirect_edge_var_map_dup. + * tree-flow-inline.h (redirect_edge_var_map_def): New. + (redirect_edge_var_map_result): New. + * tree-cfgcleanup.c (remove_forwarder_block_with_phi): Replace + PENDING_STMT use with redirect_edge_var_map_*. + * tree-ssa.c (edge_var_maps): New definition. + (redirect_edge_var_map_add): New. + (redirect_edge_var_map_clear): New. + (redirect_edge_var_map_dup): New. + (redirect_edge_var_map_vector): New. + (redirect_edge_var_map_destroy): New. + (ssa_redirect_edge): Replace PENDING_STMT use with + redirect_edge_var_map_*. + (flush_pending_stmts): Same. + (delete_tree_ssa): Destroy edge var map. + * tree-flow.h (struct _edge_var_map): New. + Define edge_var_map vector type. + Declare redirect_edge_var_map_* prototypes. + * Makefile.in (cfg.o): Depend on TREE_FLOW_H. + * tree-cfg.c (reinstall_phi_args): Replace + PENDING_STMT use with redirect_edge_var_map_*. + 2008-03-05 Richard Guenther PR tree-optimization/35472 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6b8aab3ea80..4522e1dffbf 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2643,7 +2643,7 @@ auto-inc-dec.o : auto-inc-dec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \ $(REGS_H) hard-reg-set.h output.h toplev.h $(FUNCTION_H) except.h $(GGC_H) \ $(TM_P_H) $(TIMEVAR_H) $(OBSTACK_H) $(TREE_H) alloc-pool.h \ - $(HASHTAB_H) $(DF_H) $(CFGLOOP_H) + $(HASHTAB_H) $(DF_H) $(CFGLOOP_H) $(TREE_FLOW_H) cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TIMEVAR_H) toplev.h $(CFGLOOP_H) cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ diff --git a/gcc/cfg.c b/gcc/cfg.c index 8a83137aaa5..fe8dba984cf 100644 --- a/gcc/cfg.c +++ b/gcc/cfg.c @@ -67,6 +67,7 @@ along with GCC; see the file COPYING3. If not see #include "alloc-pool.h" #include "df.h" #include "cfgloop.h" +#include "tree-flow.h" /* The obstack on which the flow graph components are allocated. */ @@ -359,6 +360,9 @@ remove_edge_raw (edge e) disconnect_src (e); disconnect_dest (e); + /* This is probably not needed, but it doesn't hurt. */ + redirect_edge_var_map_clear (e); + free_edge (e); } @@ -395,6 +399,7 @@ redirect_edge_succ_nodup (edge e, basic_block new_succ) s->probability = REG_BR_PROB_BASE; s->count += e->count; remove_edge (e); + redirect_edge_var_map_dup (s, e); e = s; } else diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index abc1672fffb..71a6c9ad667 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -3031,24 +3031,28 @@ bsi_insert_on_edge_immediate (edge e, tree stmt) static void reinstall_phi_args (edge new_edge, edge old_edge) { - tree var, phi; + tree phi; + edge_var_map_vector v; + edge_var_map *vm; + int i; - if (!PENDING_STMT (old_edge)) + v = redirect_edge_var_map_vector (old_edge); + if (!v) return; - for (var = PENDING_STMT (old_edge), phi = phi_nodes (new_edge->dest); - var && phi; - var = TREE_CHAIN (var), phi = PHI_CHAIN (phi)) + for (i = 0, phi = phi_nodes (new_edge->dest); + VEC_iterate (edge_var_map, v, i, vm) && phi; + i++, phi = PHI_CHAIN (phi)) { - tree result = TREE_PURPOSE (var); - tree arg = TREE_VALUE (var); + tree result = redirect_edge_var_map_result (vm); + tree arg = redirect_edge_var_map_def (vm); gcc_assert (result == PHI_RESULT (phi)); add_phi_arg (phi, arg, new_edge); } - PENDING_STMT (old_edge) = NULL; + redirect_edge_var_map_clear (old_edge); } /* Returns the basic block after which the new basic block created diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index bcae4488dc1..aaaacd9fb33 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -748,7 +748,7 @@ remove_forwarder_block_with_phi (basic_block bb) if (phi_alternatives_equal (dest, s, succ)) { e = redirect_edge_and_branch (e, dest); - PENDING_STMT (e) = NULL_TREE; + redirect_edge_var_map_clear (e); continue; } @@ -771,15 +771,18 @@ remove_forwarder_block_with_phi (basic_block bb) if (TREE_CODE (def) == SSA_NAME) { - tree var; + edge_var_map_vector head; + edge_var_map *vm; + size_t i; /* If DEF is one of the results of PHI nodes removed during redirection, replace it with the PHI argument that used to be on E. */ - for (var = PENDING_STMT (e); var; var = TREE_CHAIN (var)) + head = redirect_edge_var_map_vector (e); + for (i = 0; VEC_iterate (edge_var_map, head, i, vm); ++i) { - tree old_arg = TREE_PURPOSE (var); - tree new_arg = TREE_VALUE (var); + tree old_arg = redirect_edge_var_map_result (vm); + tree new_arg = redirect_edge_var_map_def (vm); if (def == old_arg) { @@ -792,7 +795,7 @@ remove_forwarder_block_with_phi (basic_block bb) add_phi_arg (phi, def, s); } - PENDING_STMT (e) = NULL; + redirect_edge_var_map_clear (e); } /* Update the dominators. */ diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 79071a90bea..7bc21b8bd3d 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -1842,4 +1842,20 @@ gimple_mem_ref_stats (const struct function *fn) { return &fn->gimple_df->mem_ref_stats; } + +/* Given an edge_var_map V, return the PHI arg definition. */ + +static inline tree +redirect_edge_var_map_def (edge_var_map *v) +{ + return v->def; +} + +/* Given an edge_var_map V, return the PHI result. */ + +static inline tree +redirect_edge_var_map_result (edge_var_map *v) +{ + return v->result; +} #endif /* _TREE_FLOW_INLINE_H */ diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 555d3a32a57..1e3c92a91dc 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -879,7 +879,30 @@ typedef bool (*walk_use_def_chains_fn) (tree, tree, void *); /* In tree-ssa-alias-warnings.c */ extern void strict_aliasing_warning_backend (void); + /* In tree-ssa.c */ + +/* Mapping for redirected edges. */ +struct _edge_var_map GTY(()) +{ + tree result; /* PHI result. */ + tree def; /* PHI arg definition. */ +}; +typedef struct _edge_var_map edge_var_map; + +DEF_VEC_O(edge_var_map); +DEF_VEC_ALLOC_O(edge_var_map, heap); + +/* A vector of var maps. */ +typedef VEC(edge_var_map, heap) *edge_var_map_vector; + +extern void redirect_edge_var_map_add (edge, tree, tree); +extern void redirect_edge_var_map_clear (edge); +extern void redirect_edge_var_map_dup (edge, edge); +extern edge_var_map_vector redirect_edge_var_map_vector (edge); +extern void redirect_edge_var_map_destroy (void); + + extern void init_tree_ssa (void); extern edge ssa_redirect_edge (edge, basic_block); extern void flush_pending_stmts (edge); @@ -892,6 +915,7 @@ extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool); extern bool stmt_references_memory_p (tree); extern bool ssa_undefined_value_p (tree); + /* In tree-into-ssa.c */ void update_ssa (unsigned); void delete_update_ssa (void); diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 6c06df094b1..a036346dee2 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -45,32 +45,147 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "toplev.h" +/* Pointer map of variable mappings, keyed by edge. */ +static struct pointer_map_t *edge_var_maps; + + +/* Add a mapping with PHI RESULT and PHI DEF associated with edge E. */ + +void +redirect_edge_var_map_add (edge e, tree result, tree def) +{ + void **slot; + edge_var_map_vector old_head, head; + edge_var_map new_node; + + if (edge_var_maps == NULL) + edge_var_maps = pointer_map_create (); + + slot = pointer_map_insert (edge_var_maps, e); + old_head = head = *slot; + if (!head) + { + head = VEC_alloc (edge_var_map, heap, 5); + *slot = head; + } + new_node.def = def; + new_node.result = result; + + VEC_safe_push (edge_var_map, heap, head, &new_node); + if (old_head != head) + { + /* The push did some reallocation. Update the pointer map. */ + *slot = head; + } +} + + +/* Clear the var mappings in edge E. */ + +void +redirect_edge_var_map_clear (edge e) +{ + void **slot; + edge_var_map_vector head; + + if (!edge_var_maps) + return; + + slot = pointer_map_contains (edge_var_maps, e); + + if (slot) + { + head = *slot; + VEC_free (edge_var_map, heap, head); + *slot = NULL; + } +} + + +/* Duplicate the redirected var mappings in OLDE in NEWE. + + Since we can't remove a mapping, let's just duplicate it. This assumes a + pointer_map can have multiple edges mapping to the same var_map (many to + one mapping), since we don't remove the previous mappings. */ + +void +redirect_edge_var_map_dup (edge newe, edge olde) +{ + void **new_slot, **old_slot; edge_var_map_vector head; + + if (!edge_var_maps) + return; + + new_slot = pointer_map_insert (edge_var_maps, newe); + old_slot = pointer_map_contains (edge_var_maps, olde); + if (!old_slot) + return; + head = *old_slot; + + if (head) + *new_slot = VEC_copy (edge_var_map, heap, head); + else + *new_slot = VEC_alloc (edge_var_map, heap, 5); +} + + +/* Return the varable mappings for a given edge. If there is none, return + NULL. */ + +edge_var_map_vector +redirect_edge_var_map_vector (edge e) +{ + void **slot; + + /* Hey, what kind of idiot would... you'd be surprised. */ + if (!edge_var_maps) + return NULL; + + slot = pointer_map_contains (edge_var_maps, e); + if (!slot) + return NULL; + + return (edge_var_map_vector) *slot; +} + + +/* Clear the edge variable mappings. */ + +void +redirect_edge_var_map_destroy (void) +{ + if (edge_var_maps) + { + pointer_map_destroy (edge_var_maps); + edge_var_maps = NULL; + } +} + + /* Remove the corresponding arguments from the PHI nodes in E's destination block and redirect it to DEST. Return redirected edge. - The list of removed arguments is stored in PENDING_STMT (e). */ + The list of removed arguments is stored in a vector accessed + through edge_var_maps. */ edge ssa_redirect_edge (edge e, basic_block dest) { tree phi; - tree list = NULL, *last = &list; - tree src, dst, node; + + redirect_edge_var_map_clear (e); /* Remove the appropriate PHI arguments in E's destination block. */ for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi)) { - if (PHI_ARG_DEF (phi, e->dest_idx) == NULL_TREE) + tree def = PHI_ARG_DEF (phi, e->dest_idx); + + if (def == NULL_TREE) continue; - src = PHI_ARG_DEF (phi, e->dest_idx); - dst = PHI_RESULT (phi); - node = build_tree_list (dst, src); - *last = node; - last = &TREE_CHAIN (node); + redirect_edge_var_map_add (e, PHI_RESULT (phi), def); } e = redirect_edge_succ_nodup (e, dest); - PENDING_STMT (e) = list; return e; } @@ -81,20 +196,24 @@ ssa_redirect_edge (edge e, basic_block dest) void flush_pending_stmts (edge e) { - tree phi, arg; + tree phi; + edge_var_map_vector v; + edge_var_map *vm; + int i; - if (!PENDING_STMT (e)) + v = redirect_edge_var_map_vector (e); + if (!v) return; - for (phi = phi_nodes (e->dest), arg = PENDING_STMT (e); - phi; - phi = PHI_CHAIN (phi), arg = TREE_CHAIN (arg)) + for (phi = phi_nodes (e->dest), i = 0; + phi && VEC_iterate (edge_var_map, v, i, vm); + phi = PHI_CHAIN (phi), i++) { - tree def = TREE_VALUE (arg); + tree def = redirect_edge_var_map_def (vm); add_phi_arg (phi, def, e); } - PENDING_STMT (e) = NULL; + redirect_edge_var_map_clear (e); } /* Return true if SSA_NAME is malformed and mark it visited. @@ -920,6 +1039,9 @@ delete_tree_ssa (void) delete_mem_ref_stats (cfun); cfun->gimple_df = NULL; + + /* We no longer need the edge variable maps. */ + redirect_edge_var_map_destroy (); } /* Helper function for useless_type_conversion_p. */