[patch] Avoid ssa update in cfg cleanup

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Fri Feb 3 22:04:00 GMT 2006


Hello,

this is the first of several patches that should avoid the need to call
update_ssa on most places where it is currently used.  As such, it also
brings in some machinery needed for that.

First the basic idea.  CFG cleanup performs a simple copy
propagation in order to get rid of phi nodes between the blocks that are
merged.  This may cause virtual operands of a statement to be changed;
for example, if p = &a is copy propagated to *p, we know it only aliases
a, and nothing else, whereas before we might also believe it to alias
other variables.  Or, if a constant is propagated for i to a[i], we may
now know the exact SFT.  So far, we just run mark_new_vars_to_rename on
such a statement, and if the vops are changed, update_ssa is required.

The key observation is that no new vops should ever appear in this way,
only the old ones may disappear.  If new vops appear, it means that we
either had incorrect alias information before (very bad), or that by
making the copy propagation, we are losing information (not good,
either).  However, when old vops disappear, it is not necessary to
update the ssa form the hard way; it is enough to copy propagate the
assignment.  For example, if v_1 = VDEF (v_2) disappears, it is enough
to simply substitute v_2 for all uses of v_1.

So far the easy part.  Of course, there are some complications that
needed to be addressed, in particular:

1) V_MAY_DEF may become V_MUST_DEF after copy propagation.  In this
   case, we would lose the old ssa names in update_stmt, which would force
   us to use update_ssa.  The tree-ssa-operands changes ensure that
   V_MUST_DEF operands may inherit the ssa names of old V_MAY_DEF operands.

2) Sometimes, we allowed to lose information by copy propagation.
   may_propagate_copy got this right when dealing with TMT's, but
   contained almost no checks for NMT's.  The change to
   may_propagate_copy prevents us from losing the flow sensitive alias
   information stored at ssa names.

3) Order of todo execution needed to be changed in execute_todo -- it
   makes more sense to first update ssa form, and run cfgcleanup over
   a consistent program, in order for block merging (that only handles
   phi node elimination if ssa form does not need to be updated) to be
   efficient.  However, ssa updating needs dominance information, which
   is somewhat problematic in case there are unreachable basic blocks.
   So an additional call to delete_unreachable_blocks is needed before
   update_ssa.

Bootstrapped & regtested on i686 and ppc.  I am not quite sure how much
the numbers can be trusted, since both testers are loaded machines, but
I have measured 1.6% compile time speedup on ppc and 1.2% on i686,
on preprocessed gcc sources.

Zdenek

	* tree-ssa-operands.h (struct maydef_optype_d,
	struct mustdef_optype_d): Replaced with ...
	(struct vdef_optype_d): ... common type.
	(struct stmt_operands_d): Change types of fields to vdef_optype_d.
	(MUSTDEF_KILL): Handle vdef_optype_d operand.
	* tree-ssa-loop-manip.c (rewrite_into_loop_closed_ssa): Do not call
	update_ssa if update_flag == 0.
	* tree-ssa-opfinalize.h (FINALIZE_FUNC): Allow mustdef operands inherit
	ssa names of maydef ones.
	* tree-dfa.c (update_virtual_ops): New function.
	* tree-cfgcleanup.c (cleanup_tree_cfg_loop): Do not pass TODO_update_ssa
	to rewrite_into_loop_closed_ssa.
	* tree-ssa-copy.c (may_propagate_copy): Do not allow losing information
	from NMTs.  Make copy propagation of virtual operands always possible.
	* tree-flow.h (update_virtual_ops): Declare.
	* tree-cfg.c (replace_uses_by): Use update_virtual_ops.  Do not update
	statements when virtual operands are propagated.
	* passes.c (execute_todo): Run TODO_update_ssa before TODO_cleanup_cfg.
	* tree-ssa-operands.c (old_vdef_ops): New variable.
	(free_maydefs, free_mustdefs): Replaced by ...
	(free_vdefs): ... common free-list.
	(fini_ssa_operands): Clean up free_vdefs.
	(FINALIZE_OLD_OPS, FINALIZE_PRESERVE_OLD_OPS): Initialize for the
	appropriate operand types.
	(merge_vdef_lists, free_vdef_list): New functions.
	(build_ssa_operands): Handle vdef lists.

Index: tree-ssa-operands.h
===================================================================
*** tree-ssa-operands.h	(revision 110542)
--- tree-ssa-operands.h	(working copy)
*************** struct use_optype_d 
*** 50,65 ****
  };
  typedef struct use_optype_d *use_optype_p;
  
- /* This represents the MAY_DEFS for a stmt.  */
- struct maydef_optype_d
- {
-   struct maydef_optype_d *next;
-   tree def_var;
-   tree use_var;
-   struct ssa_use_operand_d use_ptr;
- };
- typedef struct maydef_optype_d *maydef_optype_p;
- 
  /* This represents the VUSEs for a stmt.  */
  struct vuse_optype_d
  {
--- 50,55 ----
*************** struct vuse_optype_d
*** 69,83 ****
  };
  typedef struct vuse_optype_d *vuse_optype_p;
                                                                                
! /* This represents the V_MUST_DEFS for a stmt.  */
! struct mustdef_optype_d
  {
!   struct mustdef_optype_d *next;
    tree def_var;
!   tree kill_var;
    struct ssa_use_operand_d use_ptr;
  };
! typedef struct mustdef_optype_d *mustdef_optype_p;
  
  
  #define SSA_OPERAND_MEMORY_SIZE		(2048 - sizeof (void *))
--- 59,74 ----
  };
  typedef struct vuse_optype_d *vuse_optype_p;
                                                                                
! /* This represents the VDEFS for a stmt.  */
! struct vdef_optype_d
  {
!   struct vdef_optype_d *next;
    tree def_var;
!   tree use_var;
    struct ssa_use_operand_d use_ptr;
  };
! typedef struct vdef_optype_d *maydef_optype_p;
! typedef struct vdef_optype_d *mustdef_optype_p;
  
  
  #define SSA_OPERAND_MEMORY_SIZE		(2048 - sizeof (void *))
*************** struct ssa_operand_memory_d GTY((chain_n
*** 93,105 ****
  struct stmt_operands_d
  {
    /* Statement operands.  */
!   struct def_optype_d * def_ops;
!   struct use_optype_d * use_ops;
                                                                                
    /* Virtual operands (V_MAY_DEF, VUSE, and V_MUST_DEF).  */
!   struct maydef_optype_d * maydef_ops;
!   struct vuse_optype_d * vuse_ops;
!   struct mustdef_optype_d * mustdef_ops;
  };
                                                                                
  typedef struct stmt_operands_d *stmt_operands_p;
--- 84,96 ----
  struct stmt_operands_d
  {
    /* Statement operands.  */
!   def_optype_p def_ops;
!   use_optype_p use_ops;
                                                                                
    /* Virtual operands (V_MAY_DEF, VUSE, and V_MUST_DEF).  */
!   maydef_optype_p maydef_ops;
!   vuse_optype_p vuse_ops;
!   mustdef_optype_p mustdef_ops;
  };
                                                                                
  typedef struct stmt_operands_d *stmt_operands_p;
*************** typedef struct stmt_operands_d *stmt_ope
*** 134,140 ****
  #define MUSTDEF_RESULT_PTR(OP)	(&((OP)->def_var))
  #define MUSTDEF_RESULT(OP)	((OP)->def_var)
  #define MUSTDEF_KILL_PTR(OP)	USE_OP_PTR (OP)
! #define MUSTDEF_KILL(OP)	((OP)->kill_var)
  
  #define PHI_RESULT_PTR(PHI)	get_phi_result_ptr (PHI)
  #define PHI_RESULT(PHI)		DEF_FROM_PTR (PHI_RESULT_PTR (PHI))
--- 125,131 ----
  #define MUSTDEF_RESULT_PTR(OP)	(&((OP)->def_var))
  #define MUSTDEF_RESULT(OP)	((OP)->def_var)
  #define MUSTDEF_KILL_PTR(OP)	USE_OP_PTR (OP)
! #define MUSTDEF_KILL(OP)	((OP)->use_var)
  
  #define PHI_RESULT_PTR(PHI)	get_phi_result_ptr (PHI)
  #define PHI_RESULT(PHI)		DEF_FROM_PTR (PHI_RESULT_PTR (PHI))
Index: tree-ssa-loop-manip.c
===================================================================
*** tree-ssa-loop-manip.c	(revision 110542)
--- tree-ssa-loop-manip.c	(working copy)
*************** rewrite_into_loop_closed_ssa (bitmap cha
*** 358,364 ****
  
    /* If the pass has caused the SSA form to be out-of-date, update it
       now.  */
!   update_ssa (update_flag);
  
    old_num_ssa_names = num_ssa_names;
    use_blocks = XCNEWVEC (bitmap, old_num_ssa_names);
--- 358,366 ----
  
    /* If the pass has caused the SSA form to be out-of-date, update it
       now.  */
!   if (update_flag)
!     update_ssa (update_flag);
!   gcc_assert (!need_ssa_update_p ());
  
    old_num_ssa_names = num_ssa_names;
    use_blocks = XCNEWVEC (bitmap, old_num_ssa_names);
Index: tree-ssa-opfinalize.h
===================================================================
*** tree-ssa-opfinalize.h	(revision 110542)
--- tree-ssa-opfinalize.h	(working copy)
*************** static inline void
*** 64,109 ****
  FINALIZE_FUNC (tree stmt)
  {
    unsigned new_i;
!   FINALIZE_TYPE *old_ops, *ptr, *last;
    FINALIZE_BASE_TYPE old_base;
    FINALIZE_TYPE new_list;
  
    new_list.next = NULL;
    last = &new_list;
  
!   old_ops = FINALIZE_OPS (stmt);
!   if (old_ops)
!     old_base = FINALIZE_BASE (FINALIZE_ELEM (old_ops));
    else
      old_base = FINALIZE_BASE_ZERO;
  
    new_i = 0;
!   while (old_ops && new_i < VEC_length (tree, FINALIZE_OPBUILD))
      {
        FINALIZE_BASE_TYPE new_base = FINALIZE_OPBUILD_BASE (new_i);
        if (old_base == new_base)
          {
  	  /* if variables are the same, reuse this node.  */
! 	  last->next = old_ops;
! 	  last = old_ops;
  #ifdef FINALIZE_CORRECT_USE
  	  FINALIZE_CORRECT_USE (FINALIZE_USE_PTR (last), stmt);
  #endif
! 	  old_ops = old_ops->next;
  	  new_i++;
  	}
        else
          if (old_base < new_base)
  	  {
  	    /* if old is less than new, old goes to the free list.  */
  #ifdef FINALIZE_USE_PTR
! 	    use_operand_p use_p = FINALIZE_USE_PTR (old_ops);
! 	    delink_imm_use (use_p);
  #endif
! 	    ptr = old_ops;
! 	    old_ops = old_ops->next;
! 	    ptr->next = FINALIZE_FREE;
! 	    FINALIZE_FREE = ptr;
  	  }
  	else
  	  {
--- 64,114 ----
  FINALIZE_FUNC (tree stmt)
  {
    unsigned new_i;
!   FINALIZE_TYPE **old_ops, *ptr, *last;
    FINALIZE_BASE_TYPE old_base;
    FINALIZE_TYPE new_list;
  
    new_list.next = NULL;
    last = &new_list;
  
!   old_ops = &FINALIZE_OLD_OPS (stmt);
!   if (*old_ops)
!     old_base = FINALIZE_BASE (FINALIZE_ELEM (*old_ops));
    else
      old_base = FINALIZE_BASE_ZERO;
  
    new_i = 0;
!   while (*old_ops && new_i < VEC_length (tree, FINALIZE_OPBUILD))
      {
        FINALIZE_BASE_TYPE new_base = FINALIZE_OPBUILD_BASE (new_i);
        if (old_base == new_base)
          {
  	  /* if variables are the same, reuse this node.  */
! 	  last->next = *old_ops;
! 	  last = *old_ops;
  #ifdef FINALIZE_CORRECT_USE
  	  FINALIZE_CORRECT_USE (FINALIZE_USE_PTR (last), stmt);
  #endif
! 	  *old_ops = (*old_ops)->next;
  	  new_i++;
  	}
        else
          if (old_base < new_base)
  	  {
  	    /* if old is less than new, old goes to the free list.  */
+ 	    if (FINALIZE_PRESERVE_OLD_OPS)
+ 	      old_ops = &(*old_ops)->next;
+ 	    else
+ 	      {
  #ifdef FINALIZE_USE_PTR
!     		use_operand_p use_p = FINALIZE_USE_PTR (*old_ops);
! 		delink_imm_use (use_p);
  #endif
! 		ptr = *old_ops;
! 		*old_ops = ptr->next;
! 		ptr->next = FINALIZE_FREE;
! 		FINALIZE_FREE = ptr;
! 	      }
  	  }
  	else
  	  {
*************** FINALIZE_FUNC (tree stmt)
*** 114,121 ****
  	    last = ptr;
  	    new_i++;
  	  }
!       if (old_ops)
!         old_base = FINALIZE_BASE (FINALIZE_ELEM (old_ops));
      }
  
    /* If there is anything remaining in the opbuild list, simply emit them.  */
--- 119,126 ----
  	    last = ptr;
  	    new_i++;
  	  }
!       if (*old_ops)
!         old_base = FINALIZE_BASE (FINALIZE_ELEM (*old_ops));
      }
  
    /* If there is anything remaining in the opbuild list, simply emit them.  */
*************** FINALIZE_FUNC (tree stmt)
*** 130,149 ****
    last->next = NULL;
  
    /* If there is anything in the old list, free them.  */
!   if (old_ops)
      {
  #ifdef FINALIZE_USE_PTR
!       for (ptr = old_ops; ptr; ptr = ptr->next)
  	{
  	  use_operand_p use_p = FINALIZE_USE_PTR (ptr);
  	  delink_imm_use (use_p);
  	}
  #endif
!       old_ops->next = FINALIZE_FREE;
!       FINALIZE_FREE = old_ops;
      }
  
!   /* NOw set the stmt's operands.  */
    FINALIZE_OPS (stmt) = new_list.next;
  
  #ifdef ENABLE_CHECKING
--- 135,156 ----
    last->next = NULL;
  
    /* If there is anything in the old list, free them.  */
!   if (!FINALIZE_PRESERVE_OLD_OPS && *old_ops)
      {
  #ifdef FINALIZE_USE_PTR
!       for (ptr = *old_ops; ptr; ptr = ptr->next)
  	{
  	  use_operand_p use_p = FINALIZE_USE_PTR (ptr);
  	  delink_imm_use (use_p);
  	}
  #endif
!       for (ptr = *old_ops; ptr->next; ptr = ptr->next)
! 	continue;
!       ptr->next = FINALIZE_FREE;
!       FINALIZE_FREE = *old_ops;
      }
  
!   /* Now set the stmt's operands.  */
    FINALIZE_OPS (stmt) = new_list.next;
  
  #ifdef ENABLE_CHECKING
*************** FINALIZE_FUNC (tree stmt)
*** 162,167 ****
--- 169,176 ----
  #undef FINALIZE_FREE
  #undef FINALIZE_TYPE
  #undef FINALIZE_OPS
+ #undef FINALIZE_OLD_OPS
+ #undef FINALIZE_PRESERVE_OLD_OPS
  #undef FINALIZE_USE_PTR
  #undef FINALIZE_INITIALIZE
  #undef FINALIZE_ELEM
Index: tree-dfa.c
===================================================================
*** tree-dfa.c	(revision 110542)
--- tree-dfa.c	(working copy)
*************** add_referenced_tmp_var (tree var)
*** 804,809 ****
--- 804,889 ----
  }
  
  
+ /* Copy-propagate all virtual ssa names that disappeared from the statement
+    STMT.  If NEW_MAY_APPEAR is true, non-SSA vops may appear in the statement --
+    mark those to be processed by update_ssa.  */
+ 
+ void
+ update_virtual_ops (tree stmt, bool new_may_appear)
+ {
+   ssa_op_iter iter;
+   tree def, use;
+   use_operand_p use_p;
+   def_operand_p def_p;
+   VEC (tree,heap) *old_defs;
+   VEC (tree,heap) *old_uses;
+   bitmap old_def_set;
+   unsigned i, n_defs;
+ 
+   if (TREE_CODE (stmt) == PHI_NODE)
+     return;
+ 
+   get_stmt_ann (stmt);
+   old_def_set = BITMAP_ALLOC (NULL);
+   n_defs = NUM_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF | SSA_OP_VMUSTDEF);
+   old_defs = VEC_alloc (tree, heap, n_defs);
+   old_uses = VEC_alloc (tree, heap, n_defs);
+ 
+   /* Record the virtual defs and corresponding uses, to be able to copy
+      propagate them if they disappear.  We do not care about VUSES that
+      disappear.  */
+   FOR_EACH_SSA_MUST_AND_MAY_DEF_OPERAND (def_p, use_p, stmt, iter)
+     {
+       def = DEF_FROM_PTR (def_p);
+       use = USE_FROM_PTR (use_p);
+       gcc_assert (TREE_CODE (def) == SSA_NAME);
+       gcc_assert (TREE_CODE (use) == SSA_NAME);
+ 
+       bitmap_set_bit (old_def_set, SSA_NAME_VERSION (def));
+       VEC_quick_push (tree, old_defs, def);
+       VEC_quick_push (tree, old_uses, use);
+     }
+ 
+   /* Now force an operand re-scan on the statement and mark any newly
+      exposed variables.  */
+   update_stmt (stmt);
+ 
+   FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_VUSE)
+     if (TREE_CODE (use) != SSA_NAME)
+       {
+ 	gcc_assert (new_may_appear);
+ 	mark_sym_for_renaming (use);
+       }
+   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_VMAYDEF | SSA_OP_VMUSTDEF)
+     {
+       if (DECL_P (def))
+ 	{
+ 	  gcc_assert (new_may_appear);
+ 	  mark_sym_for_renaming (def);
+ 	  continue;
+ 	}
+       bitmap_clear_bit (old_def_set, SSA_NAME_VERSION (def));
+     }
+ 
+   /* Copy propagate the vops that disappeared.  */
+   if (bitmap_empty_p (old_def_set))
+     goto end;
+ 
+   for (i = 0; VEC_iterate (tree, old_defs, i, def); i++)
+     {
+       if (!bitmap_bit_p (old_def_set, SSA_NAME_VERSION (def)))
+ 	continue;
+ 
+       use = VEC_index (tree, old_uses, i);
+       replace_uses_by (def, use);
+     }
+ 
+ end:
+   BITMAP_FREE (old_def_set);
+   VEC_free (tree, heap, old_defs);
+   VEC_free (tree, heap, old_uses);
+ }
+ 
  /* Mark all the non-SSA variables found in STMT's operands to be
     processed by update_ssa.  */
  
Index: tree-cfgcleanup.c
===================================================================
*** tree-cfgcleanup.c	(revision 110542)
--- tree-cfgcleanup.c	(working copy)
*************** cleanup_tree_cfg_loop (void)
*** 569,575 ****
    /* This usually does nothing.  But sometimes parts of cfg that originally
       were inside a loop get out of it due to edge removal (since they
       become unreachable by back edges from latch).  */
!   rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
  
    BITMAP_FREE (changed_bbs);
  
--- 569,575 ----
    /* This usually does nothing.  But sometimes parts of cfg that originally
       were inside a loop get out of it due to edge removal (since they
       become unreachable by back edges from latch).  */
!   rewrite_into_loop_closed_ssa (changed_bbs, 0);
  
    BITMAP_FREE (changed_bbs);
  
Index: tree-ssa-copy.c
===================================================================
*** tree-ssa-copy.c	(revision 110542)
--- tree-ssa-copy.c	(working copy)
*************** may_propagate_copy (tree dest, tree orig
*** 67,72 ****
--- 67,87 ----
    if (!tree_ssa_useless_type_conversion_1 (type_d, type_o))
      return false;
  
+   /* If the destination is a SSA_NAME for a virtual operand, then we have
+      some special cases to handle.  */
+   if (TREE_CODE (dest) == SSA_NAME && !is_gimple_reg (dest))
+     {
+       /* If both operands are SSA_NAMEs referring to virtual operands, then
+ 	 we can always propagate.  */
+       if (TREE_CODE (orig) == SSA_NAME
+ 	  && !is_gimple_reg (orig))
+ 	return true;
+ 
+       /* We have a "copy" from something like a constant into a virtual
+ 	 operand.  Reject these.  */
+       return false;
+     }
+ 
    /* FIXME.  GIMPLE is allowing pointer assignments and comparisons of
       pointers that have different alias sets.  This means that these
       pointers will have different memory tags associated to them.
*************** may_propagate_copy (tree dest, tree orig
*** 110,115 ****
--- 125,133 ----
      {
        tree mt_dest = var_ann (SSA_NAME_VAR (dest))->type_mem_tag;
        tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag;
+       struct ptr_info_def *dest_ptr_info = SSA_NAME_PTR_INFO (dest);
+       struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
+ 
        if (mt_dest && mt_orig && mt_dest != mt_orig)
  	return false;
        else if (!lang_hooks.types_compatible_p (type_d, type_o))
*************** may_propagate_copy (tree dest, tree orig
*** 117,137 ****
        else if (get_alias_set (TREE_TYPE (type_d)) != 
  	       get_alias_set (TREE_TYPE (type_o)))
  	return false;
-     }
  
!   /* If the destination is a SSA_NAME for a virtual operand, then we have
!      some special cases to handle.  */
!   if (TREE_CODE (dest) == SSA_NAME && !is_gimple_reg (dest))
!     {
!       /* If both operands are SSA_NAMEs referring to virtual operands, then
! 	 we can always propagate.  */
!       if (TREE_CODE (orig) == SSA_NAME
! 	  && !is_gimple_reg (orig))
! 	return true;
  
!       /* We have a "copy" from something like a constant into a virtual
! 	 operand.  Reject these.  */
!       return false;
      }
  
    /* If ORIG flows in from an abnormal edge, it cannot be propagated.  */
--- 135,149 ----
        else if (get_alias_set (TREE_TYPE (type_d)) != 
  	       get_alias_set (TREE_TYPE (type_o)))
  	return false;
  
!       /* The variables should have the same name mem tag, or we lose
! 	 information by performing the copy propagation.  */
!       if ((dest_ptr_info != NULL) != (orig_ptr_info != NULL))
! 	return false;
  
!       if (dest_ptr_info
! 	  && (dest_ptr_info->name_mem_tag != orig_ptr_info->name_mem_tag))
! 	return false;
      }
  
    /* If ORIG flows in from an abnormal edge, it cannot be propagated.  */
Index: tree-flow.h
===================================================================
*** tree-flow.h	(revision 110542)
--- tree-flow.h	(working copy)
*************** extern void debug_subvars_for (tree);
*** 566,571 ****
--- 566,572 ----
  extern tree get_virtual_var (tree);
  extern void add_referenced_tmp_var (tree);
  extern void mark_new_vars_to_rename (tree);
+ extern void update_virtual_ops (tree, bool);
  extern void find_new_referenced_vars (tree *);
  
  extern tree make_rename_temp (tree, const char *);
Index: tree-cfg.c
===================================================================
*** tree-cfg.c	(revision 110542)
--- tree-cfg.c	(working copy)
*************** replace_uses_by (tree name, tree val)
*** 1305,1315 ****
    tree stmt;
    edge e;
    unsigned i;
!   VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20);
  
    FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
      {
        stmt = USE_STMT (use);
        replace_exp (use, val);
  
        if (TREE_CODE (stmt) == PHI_NODE)
--- 1305,1319 ----
    tree stmt;
    edge e;
    unsigned i;
!   VEC(tree,heap) *stmts = NULL;
!  
!  if (is_gimple_reg (name))
!   stmts = VEC_alloc (tree, heap, 20);
  
    FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
      {
        stmt = USE_STMT (use);
+ 
        replace_exp (use, val);
  
        if (TREE_CODE (stmt) == PHI_NODE)
*************** replace_uses_by (tree name, tree val)
*** 1324,1333 ****
  	      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
  	    }
  	}
!       else
  	VEC_safe_push (tree, heap, stmts, stmt);
      }
!  
    /* We do not update the statements in the loop above.  Consider
       x = w * w;
  
--- 1328,1341 ----
  	      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
  	    }
  	}
!       else if (stmts)
  	VEC_safe_push (tree, heap, stmts, stmt);
      }
! 
!   /* If we replaced a virtual operand, we are done.  */ 
!   if (!stmts)
!     return;
! 
    /* We do not update the statements in the loop above.  Consider
       x = w * w;
  
*************** replace_uses_by (tree name, tree val)
*** 1349,1355 ****
        if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
  	tree_purge_dead_eh_edges (bb_for_stmt (stmt));
  
!       mark_new_vars_to_rename (stmt);
      }
  
    VEC_free (tree, heap, stmts);
--- 1357,1363 ----
        if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
  	tree_purge_dead_eh_edges (bb_for_stmt (stmt));
  
!       update_virtual_ops (stmt, false);
      }
  
    VEC_free (tree, heap, stmts);
Index: passes.c
===================================================================
*** passes.c	(revision 110542)
--- passes.c	(working copy)
*************** execute_todo (struct tree_opt_pass *pass
*** 715,742 ****
      gcc_assert (flags & TODO_update_ssa_any);
  #endif
  
!   /* Always cleanup the CFG before doing anything else.  */
    if (flags & TODO_cleanup_cfg)
      {
        if (current_loops)
  	cleanup_tree_cfg_loop ();
        else
  	cleanup_tree_cfg ();
- 
-       /* When cleanup_tree_cfg merges consecutive blocks, it may
- 	 perform some simplistic propagation when removing single
- 	 valued PHI nodes.  This propagation may, in turn, cause the
- 	 SSA form to become out-of-date (see PR 22037).  So, even
- 	 if the parent pass had not scheduled an SSA update, we may
- 	 still need to do one.  */
-       if (!(flags & TODO_update_ssa_any) && need_ssa_update_p ())
- 	flags |= TODO_update_ssa;
-     }
- 
-   if (flags & TODO_update_ssa_any)
-     {
-       unsigned update_flags = flags & TODO_update_ssa_any;
-       update_ssa (update_flags);
      }
  
    if (flags & TODO_remove_unused_locals)
--- 715,741 ----
      gcc_assert (flags & TODO_update_ssa_any);
  #endif
  
!   if ((flags & TODO_update_ssa_any)
!       && need_ssa_update_p ())
!     {
!       unsigned update_flags = flags & TODO_update_ssa_any;
! 
!       if (flags & TODO_cleanup_cfg)
! 	{
! 	  /* We cannot run cfg cleanup without correct ssa form.  However,
! 	     if there are unreachable blocks, we might run into problems
! 	     with dominance information.  */
! 	  delete_unreachable_blocks ();
! 	}
!       update_ssa (update_flags);
!     }
! 
    if (flags & TODO_cleanup_cfg)
      {
        if (current_loops)
  	cleanup_tree_cfg_loop ();
        else
  	cleanup_tree_cfg ();
      }
  
    if (flags & TODO_remove_unused_locals)
Index: tree-ssa-operands.c
===================================================================
*** tree-ssa-operands.c	(revision 110542)
--- tree-ssa-operands.c	(working copy)
*************** static VEC(tree,heap) *build_vuses;
*** 119,124 ****
--- 119,127 ----
  /* Array for building all the v_must_def operands.  */
  static VEC(tree,heap) *build_v_must_defs;
  
+ /* Old virtual may and must defs are stored here while the new operands
+    are build.  */
+ static struct vdef_optype_d *old_vdef_ops;
  
  /* These arrays are the cached operand vectors for call clobbered calls.  */
  static bool ops_active = false;
*************** static void build_ssa_operands (tree stm
*** 143,150 ****
  static def_optype_p free_defs = NULL;
  static use_optype_p free_uses = NULL;
  static vuse_optype_p free_vuses = NULL;
! static maydef_optype_p free_maydefs = NULL;
! static mustdef_optype_p free_mustdefs = NULL;
  
  
  /* Return the DECL_UID of the base variable of T.  */
--- 146,152 ----
  static def_optype_p free_defs = NULL;
  static use_optype_p free_uses = NULL;
  static vuse_optype_p free_vuses = NULL;
! static maydef_optype_p free_vdefs = NULL;
  
  
  /* Return the DECL_UID of the base variable of T.  */
*************** fini_ssa_operands (void)
*** 275,282 ****
    free_defs = NULL;
    free_uses = NULL;
    free_vuses = NULL;
!   free_maydefs = NULL;
!   free_mustdefs = NULL;
    while ((ptr = operand_memory) != NULL)
      {
        operand_memory = operand_memory->next;
--- 277,283 ----
    free_defs = NULL;
    free_uses = NULL;
    free_vuses = NULL;
!   free_vdefs = NULL;
    while ((ptr = operand_memory) != NULL)
      {
        operand_memory = operand_memory->next;
*************** set_virtual_use_link (use_operand_p ptr,
*** 383,388 ****
--- 384,391 ----
  #define FINALIZE_TYPE			struct def_optype_d
  #define FINALIZE_ELEM(PTR)		((PTR)->def_ptr)
  #define FINALIZE_OPS			DEF_OPS
+ #define FINALIZE_OLD_OPS		DEF_OPS
+ #define FINALIZE_PRESERVE_OLD_OPS	false
  #define FINALIZE_BASE(VAR)		VAR
  #define FINALIZE_BASE_TYPE		tree *
  #define FINALIZE_BASE_ZERO		NULL
*************** finalize_ssa_defs (tree stmt)
*** 417,422 ****
--- 420,427 ----
  #define FINALIZE_TYPE		struct use_optype_d
  #define FINALIZE_ELEM(PTR)	((PTR)->use_ptr.use)
  #define FINALIZE_OPS		USE_OPS
+ #define FINALIZE_OLD_OPS	USE_OPS
+ #define FINALIZE_PRESERVE_OLD_OPS	false
  #define FINALIZE_USE_PTR(PTR)	USE_OP_PTR (PTR)
  #define FINALIZE_CORRECT_USE	correct_use_link
  #define FINALIZE_BASE(VAR)	VAR
*************** finalize_ssa_uses (tree stmt)
*** 449,455 ****
    finalize_ssa_use_ops (stmt);
    VEC_truncate (tree, build_uses, 0);
  }
!                                                                               
                                                                                
  /* Return a new v_may_def operand vector for STMT, comparing to OLD_OPS_P.  */                                                                                
  #define FINALIZE_OPBUILD	build_v_may_defs
--- 454,505 ----
    finalize_ssa_use_ops (stmt);
    VEC_truncate (tree, build_uses, 0);
  }
! 
! /* Merge the lists L1 and L2 and return the merged list.  */
! 
! static struct vdef_optype_d *
! merge_vdef_lists (struct vdef_optype_d *l1, struct vdef_optype_d *l2)
! {
!   struct vdef_optype_d head, *last = &head;
! 
!   while (l1 && l2)
!     {
!       if (get_name_decl (l1->def_var) < get_name_decl (l2->def_var))
! 	{
! 	  last->next = l1;
! 	  l1 = l1->next;
! 	}
!       else
! 	{
! 	  last->next = l2;
! 	  l2 = l2->next;
! 	}
!       last = last->next;
!     }
!   last->next = l1 ? l1 : l2;
! 
!   return head.next;
! }
! 
! /* Frees the list L.  */
! 
! static void
! free_vdef_list (struct vdef_optype_d *l)
! {
!   struct vdef_optype_d *p, *pre = NULL;
!   if (!l)
!     return;
! 
!   for (p = l; p; p = p->next)
!     {
!       use_operand_p use_p = &p->use_ptr;
!       delink_imm_use (use_p);
!       pre = p;
!     }
! 
!   pre->next = free_vdefs;
!   free_vdefs = l;
! }
                                                                                
  /* Return a new v_may_def operand vector for STMT, comparing to OLD_OPS_P.  */                                                                                
  #define FINALIZE_OPBUILD	build_v_may_defs
*************** finalize_ssa_uses (tree stmt)
*** 458,467 ****
  							build_v_may_defs, (I)))
  #define FINALIZE_FUNC		finalize_ssa_v_may_def_ops
  #define FINALIZE_ALLOC		alloc_maydef
! #define FINALIZE_FREE		free_maydefs
! #define FINALIZE_TYPE		struct maydef_optype_d
  #define FINALIZE_ELEM(PTR)	MAYDEF_RESULT (PTR)
  #define FINALIZE_OPS		MAYDEF_OPS
  #define FINALIZE_USE_PTR(PTR)	MAYDEF_OP_PTR (PTR)
  #define FINALIZE_CORRECT_USE	set_virtual_use_link
  #define FINALIZE_BASE_ZERO	0
--- 508,519 ----
  							build_v_may_defs, (I)))
  #define FINALIZE_FUNC		finalize_ssa_v_may_def_ops
  #define FINALIZE_ALLOC		alloc_maydef
! #define FINALIZE_FREE		free_vdefs
! #define FINALIZE_TYPE		struct vdef_optype_d
  #define FINALIZE_ELEM(PTR)	MAYDEF_RESULT (PTR)
  #define FINALIZE_OPS		MAYDEF_OPS
+ #define FINALIZE_OLD_OPS(STMT)	old_vdef_ops
+ #define FINALIZE_PRESERVE_OLD_OPS	true
  #define FINALIZE_USE_PTR(PTR)	MAYDEF_OP_PTR (PTR)
  #define FINALIZE_CORRECT_USE	set_virtual_use_link
  #define FINALIZE_BASE_ZERO	0
*************** cleanup_v_may_defs (void)
*** 514,519 ****
--- 566,573 ----
  #define FINALIZE_TYPE		struct vuse_optype_d
  #define FINALIZE_ELEM(PTR)	VUSE_OP (PTR)
  #define FINALIZE_OPS		VUSE_OPS
+ #define FINALIZE_OLD_OPS	VUSE_OPS
+ #define FINALIZE_PRESERVE_OLD_OPS	false
  #define FINALIZE_USE_PTR(PTR)	VUSE_OP_PTR (PTR)
  #define FINALIZE_CORRECT_USE	set_virtual_use_link
  #define FINALIZE_BASE_ZERO	0
*************** finalize_ssa_vuses (tree stmt)
*** 600,618 ****
  							build_v_must_defs, (I)))
  #define FINALIZE_FUNC		finalize_ssa_v_must_def_ops
  #define FINALIZE_ALLOC		alloc_mustdef
! #define FINALIZE_FREE		free_mustdefs
! #define FINALIZE_TYPE		struct mustdef_optype_d
  #define FINALIZE_ELEM(PTR)	MUSTDEF_RESULT (PTR)
  #define FINALIZE_OPS		MUSTDEF_OPS
  #define FINALIZE_USE_PTR(PTR)	MUSTDEF_KILL_PTR (PTR)
  #define FINALIZE_CORRECT_USE	set_virtual_use_link
  #define FINALIZE_BASE_ZERO	0
  #define FINALIZE_BASE(VAR)	get_name_decl (VAR)
  #define FINALIZE_BASE_TYPE	unsigned
  #define FINALIZE_INITIALIZE(PTR, VAL, STMT)				\
  				(PTR)->def_var = (VAL);			\
! 				(PTR)->kill_var = (VAL);		\
! 				(PTR)->use_ptr.use = &((PTR)->kill_var);\
  				link_imm_use_stmt (&((PTR)->use_ptr),	\
  						   (VAL), (STMT))
  #include "tree-ssa-opfinalize.h"
--- 654,674 ----
  							build_v_must_defs, (I)))
  #define FINALIZE_FUNC		finalize_ssa_v_must_def_ops
  #define FINALIZE_ALLOC		alloc_mustdef
! #define FINALIZE_FREE		free_vdefs
! #define FINALIZE_TYPE		struct vdef_optype_d
  #define FINALIZE_ELEM(PTR)	MUSTDEF_RESULT (PTR)
  #define FINALIZE_OPS		MUSTDEF_OPS
  #define FINALIZE_USE_PTR(PTR)	MUSTDEF_KILL_PTR (PTR)
+ #define FINALIZE_OLD_OPS(STMT)	old_vdef_ops
+ #define FINALIZE_PRESERVE_OLD_OPS	true
  #define FINALIZE_CORRECT_USE	set_virtual_use_link
  #define FINALIZE_BASE_ZERO	0
  #define FINALIZE_BASE(VAR)	get_name_decl (VAR)
  #define FINALIZE_BASE_TYPE	unsigned
  #define FINALIZE_INITIALIZE(PTR, VAL, STMT)				\
  				(PTR)->def_var = (VAL);			\
! 				(PTR)->use_var = (VAL);		\
! 				(PTR)->use_ptr.use = &((PTR)->use_var);\
  				link_imm_use_stmt (&((PTR)->use_ptr),	\
  						   (VAL), (STMT))
  #include "tree-ssa-opfinalize.h"
*************** build_ssa_operands (tree stmt)
*** 833,839 ****
--- 889,903 ----
    operand_build_sort_virtual (build_v_may_defs);
    operand_build_sort_virtual (build_v_must_defs);
  
+   /* MAYDEFs may be turned into MUSTDEFs.  We do not want to lose SSA names
+      and immediate uses because of this, so we handle may and must defs
+      together.  */
+   old_vdef_ops = merge_vdef_lists (MAYDEF_OPS (stmt), MUSTDEF_OPS (stmt));
+   MAYDEF_OPS (stmt) = NULL;
+   MUSTDEF_OPS (stmt) = NULL;
+ 
    finalize_ssa_stmt_operands (stmt);
+   free_vdef_list (old_vdef_ops);
  }
  
  



More information about the Gcc-patches mailing list