diff mbox

Remove def operands cache

Message ID alpine.LNX.2.00.1209111646060.9940@wotan.suse.de
State New
Headers show

Commit Message

Michael Matz Sept. 11, 2012, 2:53 p.m. UTC
Hi,

the operands cache is ugly.  This patch removes it at least for the def 
operands, saving three pointers for roughly each normal statement (the 
pointer in gsbase, and two pointers from def_optype_d).  This is 
relatively easy to do, because all statements except ASMs have at most one 
def (and one vdef), which themself aren't pointed to by something else, 
unlike the use operands which have more structure for the SSA web.

Performance wise the patch is a slight improvement (1% for some C++ 
testcases, but relatively noisy, but at least not slower), bootstrap time 
is unaffected.  As the iterator is a bit larger code size increases by 1 
promille.

The patch is regstrapped on x86_64-linux.  If it's approved I'll adjust 
the WORD count markers in gimple.h, I left it out in this submission as 
it's just verbose noise in comments.

Okay for trunk?


Ciao,
Michael.
	* tree-ssa-operands.h (struct def_optype_d, def_optype_p): Remove.
	(ssa_operands.free_defs): Remove.
	(DEF_OP_PTR, DEF_OP): Remove.
	(struct ssa_operand_iterator_d): Remove 'defs', add 'flags', 'def_i'
	members, rename 'phi_stmt' to 'stmt'.
	* gimple.h (gimple_statement_with_ops.def_ops): Remove.
	(gimple_def_ops, gimple_set_def_ops): Remove.
	(gimple_vdef_op): Don't take const gimple, adjust.
	* tree-ssa-operands.c (build_defs): Remove.
	(init_ssa_operands): Don't initialize it.
	(fini_ssa_operands): Don't free it.
	(cleanup_build_arrays): Don't truncate it.
	(finalize_ssa_stmt_operands): Don't assert on it.
	(alloc_def, add_def_op, append_def): Remove.
	(finalize_ssa_defs): Remove building of def_ops list.
	(finalize_ssa_uses): Don't mark for SSA renaming here, ...
	(add_stmt_operand): ... but here, don't call append_def.
	(get_indirect_ref_operands): Remove recurse_on_base argument.
	(get_expr_operands): Adjust call to get_indirect_ref_operands.
	(verify_ssa_operands): Don't check def operands.
	(free_stmt_operands): Don't free def operands.
	* gimple.c (gimple_copy): Don't clear def operands.
	* tree-flow-inline.h (op_iter_next_use): Adjust to explicitely
	handle def operand.
	(op_iter_next_tree): Ditto.
	(clear_and_done_ssa_iter): Clear new fields.
	(op_iter_init): Adjust to setup new iterator structure.
	(op_iter_init_phiuse): Adjust.

Comments

Andrew MacLeod Sept. 28, 2012, 5:18 p.m. UTC | #1
On 09/11/2012 10:53 AM, Michael Matz wrote:
> Hi,
>
> the operands cache is ugly.  This patch removes it at least for the def
> operands, saving three pointers for roughly each normal statement (the
> pointer in gsbase, and two pointers from def_optype_d).  This is
> relatively easy to do, because all statements except ASMs have at most one
> def (and one vdef), which themself aren't pointed to by something else,
> unlike the use operands which have more structure for the SSA web.
Yeah, a bit has changed since the original implementation. There is only 
ever one vdef, and not much else in the way of multiple def's ever 
arrived,  So I think this makes sense.

Note that when I introduce gimple_atomic (delayed until next year :-P), 
there will be at least one more statement with 2 results.. the 
__atomic_cmpxchg node. so the iterator code will grow a little bit more.

Andrew
diff mbox

Patch

Index: tree-ssa-operands.h
===================================================================
--- tree-ssa-operands.h.orig	2012-09-06 16:14:30.000000000 +0200
+++ tree-ssa-operands.h	2012-09-06 16:18:33.000000000 +0200
@@ -34,14 +34,6 @@  typedef ssa_use_operand_t *use_operand_p
 #define NULL_USE_OPERAND_P 		((use_operand_p)NULL)
 #define NULL_DEF_OPERAND_P 		((def_operand_p)NULL)
 
-/* This represents the DEF operands of a stmt.  */
-struct def_optype_d
-{
-  struct def_optype_d *next;
-  tree *def_ptr;
-};
-typedef struct def_optype_d *def_optype_p;
-
 /* This represents the USE operands of a stmt.  */
 struct use_optype_d
 {
@@ -68,7 +60,6 @@  struct GTY(()) ssa_operands {
 
    bool ops_active;
 
-   struct def_optype_d * GTY ((skip (""))) free_defs;
    struct use_optype_d * GTY ((skip (""))) free_uses;
 };
 
@@ -82,9 +73,6 @@  struct GTY(()) ssa_operands {
 #define USE_OP_PTR(OP)		(&((OP)->use_ptr))
 #define USE_OP(OP)		(USE_FROM_PTR (USE_OP_PTR (OP)))
 
-#define DEF_OP_PTR(OP)		((OP)->def_ptr)
-#define DEF_OP(OP)		(DEF_FROM_PTR (DEF_OP_PTR (OP)))
-
 #define PHI_RESULT_PTR(PHI)	gimple_phi_result_ptr (PHI)
 #define PHI_RESULT(PHI)		DEF_FROM_PTR (PHI_RESULT_PTR (PHI))
 #define SET_PHI_RESULT(PHI, V)	SET_DEF (PHI_RESULT_PTR (PHI), (V))
@@ -135,11 +123,12 @@  typedef struct ssa_operand_iterator_d
 {
   bool done;
   enum ssa_op_iter_type iter_type;
-  def_optype_p defs;
+  int flags;
+  unsigned def_i;
   use_optype_p uses;
   int phi_i;
   int num_phi;
-  gimple phi_stmt;
+  gimple stmt;
 } ssa_op_iter;
 
 /* These flags are used to determine which operands are returned during
Index: gimple.h
===================================================================
--- gimple.h.orig	2012-09-06 16:14:30.000000000 +0200
+++ gimple.h	2012-09-07 16:01:27.000000000 +0200
@@ -224,12 +226,12 @@  struct GTY(()) gimple_statement_with_ops
   /* [ WORD 1-6 ]  */
   struct gimple_statement_base gsbase;
 
+  /* XXX adjust word count */
   /* [ WORD 7-8 ]
      SSA operand vectors.  NOTE: It should be possible to
      amalgamate these vectors with the operand vector OP.  However,
      the SSA operand vectors are organized differently and contain
      more information (like immediate use chaining).  */
-  struct def_optype_d GTY((skip (""))) *def_ops;
   struct use_optype_d GTY((skip (""))) *use_ops;
 };
 
@@ -1374,27 +1376,6 @@  gimple_has_mem_ops (const_gimple g)
 }
 
 
-/* Return the set of DEF operands for statement G.  */
-
-static inline struct def_optype_d *
-gimple_def_ops (const_gimple g)
-{
-  if (!gimple_has_ops (g))
-    return NULL;
-  return g->gsops.opbase.def_ops;
-}
-
-
-/* Set DEF to be the set of DEF operands for statement G.  */
-
-static inline void
-gimple_set_def_ops (gimple g, struct def_optype_d *def)
-{
-  gcc_gimple_checking_assert (gimple_has_ops (g));
-  g->gsops.opbase.def_ops = def;
-}
-
-
 /* Return the set of USE operands for statement G.  */
 
 static inline struct use_optype_d *
@@ -1434,15 +1415,12 @@  gimple_vuse_op (const_gimple g)
 /* Return the set of VDEF operand for statement G.  */
 
 static inline def_operand_p
-gimple_vdef_op (const_gimple g)
+gimple_vdef_op (gimple g)
 {
-  struct def_optype_d *ops;
   if (!gimple_has_mem_ops (g))
     return NULL_DEF_OPERAND_P;
-  ops = g->gsops.opbase.def_ops;
-  if (ops
-      && DEF_OP_PTR (ops) == &g->gsmembase.vdef)
-    return DEF_OP_PTR (ops);
+  if (g->gsmembase.vdef)
+    return &g->gsmembase.vdef;
   return NULL_DEF_OPERAND_P;
 }
 
Index: tree-flow-inline.h
===================================================================
--- tree-flow-inline.h.orig	2012-09-06 16:14:30.000000000 +0200
+++ tree-flow-inline.h	2012-09-10 17:48:02.000000000 +0200
@@ -582,7 +582,7 @@  op_iter_next_use (ssa_op_iter *ptr)
     }
   if (ptr->phi_i < ptr->num_phi)
     {
-      return PHI_ARG_DEF_PTR (ptr->phi_stmt, (ptr->phi_i)++);
+      return PHI_ARG_DEF_PTR (ptr->stmt, (ptr->phi_i)++);
     }
   ptr->done = true;
   return NULL_USE_OPERAND_P;
@@ -592,13 +592,37 @@  op_iter_next_use (ssa_op_iter *ptr)
 static inline def_operand_p
 op_iter_next_def (ssa_op_iter *ptr)
 {
-  def_operand_p def_p;
   gcc_checking_assert (ptr->iter_type == ssa_op_iter_def);
-  if (ptr->defs)
+  if (ptr->flags & SSA_OP_VDEF)
     {
-      def_p = DEF_OP_PTR (ptr->defs);
-      ptr->defs = ptr->defs->next;
-      return def_p;
+      tree *p;
+      ptr->flags &= ~SSA_OP_VDEF;
+      p = gimple_vdef_ptr (ptr->stmt);
+      if (p && *p)
+	return p;
+    }
+  if (ptr->flags & SSA_OP_DEF)
+    {
+      if (gimple_code (ptr->stmt) != GIMPLE_ASM)
+	{
+	  tree *val;
+	  ptr->flags &= ~SSA_OP_DEF;
+	  val = gimple_op_ptr (ptr->stmt, 0);
+	  if (is_gimple_assign (ptr->stmt) || *val)
+	    {
+	      if (TREE_CODE (*val) == SSA_NAME
+		  || is_gimple_reg (*val))
+		return val;
+	    }
+	}
+      else while (ptr->def_i < gimple_asm_noutputs (ptr->stmt))
+	{
+	  tree link = gimple_asm_output_op (ptr->stmt, ptr->def_i);
+	  ptr->def_i++;
+	  if (TREE_CODE (TREE_VALUE (link)) == SSA_NAME
+	      || is_gimple_reg (TREE_VALUE (link)))
+	    return &TREE_VALUE (link);
+	}
     }
   ptr->done = true;
   return NULL_DEF_OPERAND_P;
@@ -616,16 +640,37 @@  op_iter_next_tree (ssa_op_iter *ptr)
       ptr->uses = ptr->uses->next;
       return val;
     }
-  if (ptr->defs)
+  if (ptr->flags & SSA_OP_VDEF)
     {
-      val = DEF_OP (ptr->defs);
-      ptr->defs = ptr->defs->next;
-      return val;
+      ptr->flags &= ~SSA_OP_VDEF;
+      if ((val = gimple_vdef (ptr->stmt)))
+	return val;
+    }
+  if (ptr->flags & SSA_OP_DEF)
+    {
+      if (gimple_code (ptr->stmt) != GIMPLE_ASM)
+	{
+	  ptr->flags &= ~SSA_OP_DEF;
+	  val = gimple_op (ptr->stmt, 0);
+	  if (is_gimple_assign (ptr->stmt) || val)
+	    {
+	      if (TREE_CODE (val) == SSA_NAME
+		  || is_gimple_reg (val))
+		return val;
+	    }
+	}
+      else while (ptr->def_i < gimple_asm_noutputs (ptr->stmt))
+	{
+	  tree link = gimple_asm_output_op (ptr->stmt, ptr->def_i);
+	  ptr->def_i++;
+	  if (TREE_CODE (TREE_VALUE (link)) == SSA_NAME
+	      || is_gimple_reg (TREE_VALUE (link)))
+	    return TREE_VALUE (link);
+	}
     }
 
   ptr->done = true;
   return NULL_TREE;
-
 }
 
 
@@ -636,13 +681,14 @@  op_iter_next_tree (ssa_op_iter *ptr)
 static inline void
 clear_and_done_ssa_iter (ssa_op_iter *ptr)
 {
-  ptr->defs = NULL;
+  ptr->def_i = 0;
   ptr->uses = NULL;
   ptr->iter_type = ssa_op_iter_none;
   ptr->phi_i = 0;
   ptr->num_phi = 0;
-  ptr->phi_stmt = NULL;
+  ptr->stmt = NULL;
   ptr->done = true;
+  ptr->flags = 0;
 }
 
 /* Initialize the iterator PTR to the virtual defs in STMT.  */
@@ -655,21 +701,34 @@  op_iter_init (ssa_op_iter *ptr, gimple s
   gcc_checking_assert (gimple_code (stmt) != GIMPLE_PHI
 		       && (!(flags & SSA_OP_VDEF) || (flags & SSA_OP_DEF))
 		       && (!(flags & SSA_OP_VUSE) || (flags & SSA_OP_USE)));
-  ptr->defs = (flags & (SSA_OP_DEF|SSA_OP_VDEF)) ? gimple_def_ops (stmt) : NULL;
-  if (!(flags & SSA_OP_VDEF)
-      && ptr->defs
-      && gimple_vdef (stmt) != NULL_TREE)
-    ptr->defs = ptr->defs->next;
+  if (flags & (SSA_OP_DEF | SSA_OP_VDEF))
+    {
+      switch (gimple_code (stmt))
+	{
+	  case GIMPLE_ASSIGN:
+	  case GIMPLE_ASM:
+	  case GIMPLE_CALL:
+	    break;
+	  default:
+	    flags &= ~(SSA_OP_DEF | SSA_OP_VDEF);
+	    break;
+	}
+    }
   ptr->uses = (flags & (SSA_OP_USE|SSA_OP_VUSE)) ? gimple_use_ops (stmt) : NULL;
   if (!(flags & SSA_OP_VUSE)
       && ptr->uses
       && gimple_vuse (stmt) != NULL_TREE)
     ptr->uses = ptr->uses->next;
   ptr->done = false;
+  /* We would have to initialize this only in the GIMPLE_ASM case above,
+     but GCC isn't clever enough to figure out that the uses of this field
+     in the iterator stepper are then not maybe uninitialized.  */
+  ptr->def_i = 0;
 
   ptr->phi_i = 0;
   ptr->num_phi = 0;
-  ptr->phi_stmt = NULL;
+  ptr->stmt = stmt;
+  ptr->flags = flags;
 }
 
 /* Initialize iterator PTR to the use operands in STMT based on FLAGS. Return
@@ -839,9 +898,10 @@  op_iter_init_phiuse (ssa_op_iter *ptr, g
       return NULL_USE_OPERAND_P;
     }
 
-  ptr->phi_stmt = phi;
+  ptr->stmt = phi;
   ptr->num_phi = gimple_phi_num_args (phi);
   ptr->iter_type = ssa_op_iter_use;
+  ptr->flags = flags;
   return op_iter_next_use (ptr);
 }
 
Index: tree-ssa-operands.c
===================================================================
--- tree-ssa-operands.c.orig	2012-09-06 16:14:30.000000000 +0200
+++ tree-ssa-operands.c	2012-09-06 16:18:33.000000000 +0200
@@ -105,9 +105,6 @@  along with GCC; see the file COPYING3.
 /* Operand is in a place where opf_non_addressable does not apply.  */
 #define opf_not_non_addressable (1 << 4)
 
-/* Array for building all the def operands.  */
-static VEC(tree,heap) *build_defs;
-
 /* Array for building all the use operands.  */
 static VEC(tree,heap) *build_uses;
 
@@ -184,7 +181,6 @@  init_ssa_operands (struct function *fn)
 {
   if (!n_initialized++)
     {
-      build_defs = VEC_alloc (tree, heap, 5);
       build_uses = VEC_alloc (tree, heap, 10);
       build_vuse = NULL_TREE;
       build_vdef = NULL_TREE;
@@ -209,13 +205,11 @@  fini_ssa_operands (void)
 
   if (!--n_initialized)
     {
-      VEC_free (tree, heap, build_defs);
       VEC_free (tree, heap, build_uses);
       build_vdef = NULL_TREE;
       build_vuse = NULL_TREE;
     }
 
-  gimple_ssa_operands (cfun)->free_defs = NULL;
   gimple_ssa_operands (cfun)->free_uses = NULL;
 
   while ((ptr = gimple_ssa_operands (cfun)->operand_memory) != NULL)
@@ -241,8 +235,7 @@  ssa_operand_alloc (unsigned size)
 {
   char *ptr;
 
-  gcc_assert (size == sizeof (struct use_optype_d)
-	      || size == sizeof (struct def_optype_d));
+  gcc_assert (size == sizeof (struct use_optype_d));
 
   if (gimple_ssa_operands (cfun)->operand_memory_index + size
       >= gimple_ssa_operands (cfun)->ssa_operand_mem_size)
@@ -281,25 +274,6 @@  ssa_operand_alloc (unsigned size)
 }
 
 
-/* Allocate a DEF operand.  */
-
-static inline struct def_optype_d *
-alloc_def (void)
-{
-  struct def_optype_d *ret;
-  if (gimple_ssa_operands (cfun)->free_defs)
-    {
-      ret = gimple_ssa_operands (cfun)->free_defs;
-      gimple_ssa_operands (cfun)->free_defs
-	= gimple_ssa_operands (cfun)->free_defs->next;
-    }
-  else
-    ret = (struct def_optype_d *)
-	  ssa_operand_alloc (sizeof (struct def_optype_d));
-  return ret;
-}
-
-
 /* Allocate a USE operand.  */
 
 static inline struct use_optype_d *
@@ -319,21 +293,6 @@  alloc_use (void)
 }
 
 
-/* Adds OP to the list of defs after LAST.  */
-
-static inline def_optype_p
-add_def_op (tree *op, def_optype_p last)
-{
-  def_optype_p new_def;
-
-  new_def = alloc_def ();
-  DEF_OP_PTR (new_def) = op;
-  last->next = new_def;
-  new_def->next = NULL;
-  return new_def;
-}
-
-
 /* Adds OP to the list of uses of statement STMT after LAST.  */
 
 static inline use_optype_p
@@ -357,14 +316,6 @@  add_use_op (gimple stmt, tree *op, use_o
 static inline void
 finalize_ssa_defs (gimple stmt)
 {
-  unsigned new_i;
-  struct def_optype_d new_list;
-  def_optype_p old_ops, last;
-  unsigned int num = VEC_length (tree, build_defs);
-
-  /* There should only be a single real definition per assignment.  */
-  gcc_assert ((stmt && gimple_code (stmt) != GIMPLE_ASSIGN) || num <= 1);
-
   /* Pre-pend the vdef we may have built.  */
   if (build_vdef != NULL_TREE)
     {
@@ -374,17 +325,8 @@  finalize_ssa_defs (gimple stmt)
 	oldvdef = SSA_NAME_VAR (oldvdef);
       if (oldvdef != build_vdef)
 	gimple_set_vdef (stmt, build_vdef);
-      VEC_safe_insert (tree, heap, build_defs, 0, (tree)gimple_vdef_ptr (stmt));
-      ++num;
     }
 
-  new_list.next = NULL;
-  last = &new_list;
-
-  old_ops = gimple_def_ops (stmt);
-
-  new_i = 0;
-
   /* Clear and unlink a no longer necessary VDEF.  */
   if (build_vdef == NULL_TREE
       && gimple_vdef (stmt) != NULL_TREE)
@@ -404,30 +346,6 @@  finalize_ssa_defs (gimple stmt)
       cfun->gimple_df->rename_vops = 1;
       cfun->gimple_df->ssa_renaming_needed = 1;
     }
-
-  /* Check for the common case of 1 def that hasn't changed.  */
-  if (old_ops && old_ops->next == NULL && num == 1
-      && (tree *) VEC_index (tree, build_defs, 0) == DEF_OP_PTR (old_ops))
-    return;
-
-  /* If there is anything in the old list, free it.  */
-  if (old_ops)
-    {
-      old_ops->next = gimple_ssa_operands (cfun)->free_defs;
-      gimple_ssa_operands (cfun)->free_defs = old_ops;
-    }
-
-  /* If there is anything remaining in the build_defs list, simply emit it.  */
-  for ( ; new_i < num; new_i++)
-    {
-      tree *op = (tree *) VEC_index (tree, build_defs, new_i);
-      if (DECL_P (*op))
-	cfun->gimple_df->ssa_renaming_needed = 1;
-      last = add_def_op (op, last);
-    }
-
-  /* Now set the stmt's operands.  */
-  gimple_set_def_ops (stmt, new_list.next);
 }
 
 
@@ -487,8 +405,6 @@  finalize_ssa_uses (gimple stmt)
   for (new_i = 0; new_i < VEC_length (tree, build_uses); new_i++)
     {
       tree *op = (tree *) VEC_index (tree, build_uses, new_i);
-      if (DECL_P (*op))
-	cfun->gimple_df->ssa_renaming_needed = 1;
       last = add_use_op (stmt, op, last);
     }
 
@@ -505,7 +421,6 @@  cleanup_build_arrays (void)
 {
   build_vdef = NULL_TREE;
   build_vuse = NULL_TREE;
-  VEC_truncate (tree, build_defs, 0);
   VEC_truncate (tree, build_uses, 0);
 }
 
@@ -526,22 +441,12 @@  finalize_ssa_stmt_operands (gimple stmt)
 static inline void
 start_ssa_stmt_operands (void)
 {
-  gcc_assert (VEC_length (tree, build_defs) == 0);
   gcc_assert (VEC_length (tree, build_uses) == 0);
   gcc_assert (build_vuse == NULL_TREE);
   gcc_assert (build_vdef == NULL_TREE);
 }
 
 
-/* Add DEF_P to the list of pointers to operands.  */
-
-static inline void
-append_def (tree *def_p)
-{
-  VEC_safe_push (tree, heap, build_defs, (tree) def_p);
-}
-
-
 /* Add USE_P to the list of pointers to operands.  */
 
 static inline void
@@ -619,9 +524,11 @@  add_stmt_operand (tree *var_p, gimple st
     {
       /* The variable is a GIMPLE register.  Add it to real operands.  */
       if (flags & opf_def)
-	append_def (var_p);
+	;
       else
 	append_use (var_p);
+      if (DECL_P (*var_p))
+	cfun->gimple_df->ssa_renaming_needed = 1;
     }
   else
     {
@@ -668,15 +575,10 @@  mark_address_taken (tree ref)
    STMT is the statement being processed, EXPR is the MEM_REF
       that got us here.
 
-   FLAGS is as in get_expr_operands.
-
-   RECURSE_ON_BASE should be set to true if we want to continue
-      calling get_expr_operands on the base pointer, and false if
-      something else will do it for us.  */
+   FLAGS is as in get_expr_operands.  */
 
 static void
-get_indirect_ref_operands (gimple stmt, tree expr, int flags,
-			   bool recurse_on_base)
+get_indirect_ref_operands (gimple stmt, tree expr, int flags)
 {
   tree *pptr = &TREE_OPERAND (expr, 0);
 
@@ -688,10 +590,9 @@  get_indirect_ref_operands (gimple stmt,
   add_virtual_operand (stmt, flags);
 
   /* If requested, add a USE operand for the base pointer.  */
-  if (recurse_on_base)
-    get_expr_operands (stmt, pptr,
-		       opf_non_addressable | opf_use
-		       | (flags & (opf_no_vops|opf_not_non_addressable)));
+  get_expr_operands (stmt, pptr,
+		     opf_non_addressable | opf_use
+		     | (flags & (opf_no_vops|opf_not_non_addressable)));
 }
 
 
@@ -855,7 +756,7 @@  get_expr_operands (gimple stmt, tree *ex
       return;
 
     case MEM_REF:
-      get_indirect_ref_operands (stmt, expr, flags, true);
+      get_indirect_ref_operands (stmt, expr, flags);
       return;
 
     case TARGET_MEM_REF:
@@ -1128,31 +1029,6 @@  verify_ssa_operands (gimple stmt)
 	return true;
       }
 
-  FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF)
-    {
-      FOR_EACH_VEC_ELT (tree, build_defs, i, def)
-	{
-	  if (def_p == (tree *)def)
-	    {
-	      VEC_replace (tree, build_defs, i, NULL_TREE);
-	      break;
-	    }
-	}
-      if (i == VEC_length (tree, build_defs))
-	{
-	  error ("excess def operand for stmt");
-	  debug_generic_expr (DEF_FROM_PTR (def_p));
-	  return true;
-	}
-    }
-  FOR_EACH_VEC_ELT (tree, build_defs, i, def)
-    if (def != NULL_TREE)
-      {
-	error ("def operand missing for stmt");
-	debug_generic_expr (*(tree *)def);
-	return true;
-      }
-
   if (gimple_has_volatile_ops (stmt) != volatile_p)
     {
       error ("stmt volatile flag not up-to-date");
@@ -1170,18 +1046,8 @@  verify_ssa_operands (gimple stmt)
 void
 free_stmt_operands (gimple stmt)
 {
-  def_optype_p defs = gimple_def_ops (stmt), last_def;
   use_optype_p uses = gimple_use_ops (stmt), last_use;
 
-  if (defs)
-    {
-      for (last_def = defs; last_def->next; last_def = last_def->next)
-	continue;
-      last_def->next = gimple_ssa_operands (cfun)->free_defs;
-      gimple_ssa_operands (cfun)->free_defs = defs;
-      gimple_set_def_ops (stmt, NULL);
-    }
-
   if (uses)
     {
       for (last_use = uses; last_use->next; last_use = last_use->next)
Index: gimple.c
===================================================================
--- gimple.c.orig	2012-09-06 16:14:30.000000000 +0200
+++ gimple.c	2012-09-06 16:18:33.000000000 +0200
@@ -2370,10 +2370,7 @@  gimple_copy (gimple stmt)
 
       /* Clear out SSA operand vectors on COPY.  */
       if (gimple_has_ops (stmt))
-	{
-	  gimple_set_def_ops (copy, NULL);
-	  gimple_set_use_ops (copy, NULL);
-	}
+	gimple_set_use_ops (copy, NULL);
 
       if (gimple_has_mem_ops (stmt))
 	{