Patchwork Remove def operands cache, try 2

login
register
mail settings
Submitter Michael Matz
Date Oct. 22, 2012, 2:12 p.m.
Message ID <alpine.LNX.2.00.1210221608470.21868@wotan.suse.de>
Download mbox | patch
Permalink /patch/193161/
State New
Headers show

Comments

Michael Matz - Oct. 22, 2012, 2:12 p.m.
Hi,

On Tue, 11 Sep 2012, Michael Matz wrote:

> 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.

So, 2nd try after some internal feedback.  This version changes the 
operand order of asms to also have the defs at the beginning, which makes 
the iterators slightly nicer, and joins some more fields of the iterator, 
though not all that we could merge.

Again, if approved I'll adjust the word count markers.  Regstrapping on 
x86_64-linux in progress, speed similar as before.  Okay for trunk?


Ciao,
Michael.
Richard Guenther - Oct. 23, 2012, 10:08 a.m.
On Mon, Oct 22, 2012 at 4:12 PM, Michael Matz <matz@suse.de> wrote:
> Hi,
>
> On Tue, 11 Sep 2012, Michael Matz wrote:
>
>> 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.
>
> So, 2nd try after some internal feedback.  This version changes the
> operand order of asms to also have the defs at the beginning, which makes
> the iterators slightly nicer, and joins some more fields of the iterator,
> though not all that we could merge.
>
> Again, if approved I'll adjust the word count markers.  Regstrapping on
> x86_64-linux in progress, speed similar as before.  Okay for trunk?

Ok.

Thanks,
Richard.

>
> 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'
>         members, rename 'phi_stmt' to 'stmt', 'phi_i' to 'i' and 'num_phi'
>         to 'numops'.
>         * 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.
>         (gimple_asm_input_op, gimple_asm_input_op_ptr,
>         gimple_asm_set_input_op, gimple_asm_output_op,
>         gimple_asm_output_op_ptr, gimple_asm_set_output_op): Adjust asserts,
>         and rewrite to move def operands to front.
>         (gimple_asm_clobber_op, gimple_asm_set_clobber_op,
>         gimple_asm_label_op, gimple_asm_set_label_op): Correct asserts.
>         * 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, op_iter_next_def): Ditto.
>         (clear_and_done_ssa_iter): Clear new fields.
>         (op_iter_init): Adjust to setup new iterator structure.
>         (op_iter_init_phiuse): Adjust.
>
> Index: tree-ssa-operands.h
> ===================================================================
> --- tree-ssa-operands.h.orig    2012-09-24 15:24:52.000000000 +0200
> +++ tree-ssa-operands.h 2012-10-22 15:12:30.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))
> @@ -133,13 +121,13 @@ enum ssa_op_iter_type {
>
>  typedef struct ssa_operand_iterator_d
>  {
> -  bool done;
>    enum ssa_op_iter_type iter_type;
> -  def_optype_p defs;
> +  bool done;
> +  int flags;
> +  unsigned i;
> +  unsigned numops;
>    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-10-19 15:03:43.000000000 +0200
> +++ gimple.h    2012-10-22 15:12:30.000000000 +0200
> @@ -220,12 +222,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;
>  };
>
> @@ -1372,27 +1374,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 *
> @@ -1432,15 +1413,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;
>  }
>
> @@ -2941,8 +2919,8 @@ static inline tree
>  gimple_asm_input_op (const_gimple gs, unsigned index)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.ni);
> -  return gimple_op (gs, index);
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.ni);
> +  return gimple_op (gs, index + gs->gimple_asm.no);
>  }
>
>  /* Return a pointer to input operand INDEX of GIMPLE_ASM GS.  */
> @@ -2951,8 +2929,8 @@ static inline tree *
>  gimple_asm_input_op_ptr (const_gimple gs, unsigned index)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.ni);
> -  return gimple_op_ptr (gs, index);
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.ni);
> +  return gimple_op_ptr (gs, index + gs->gimple_asm.no);
>  }
>
>
> @@ -2962,9 +2940,9 @@ static inline void
>  gimple_asm_set_input_op (gimple gs, unsigned index, tree in_op)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.ni
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.ni
>                               && TREE_CODE (in_op) == TREE_LIST);
> -  gimple_set_op (gs, index, in_op);
> +  gimple_set_op (gs, index + gs->gimple_asm.no, in_op);
>  }
>
>
> @@ -2974,8 +2952,8 @@ static inline tree
>  gimple_asm_output_op (const_gimple gs, unsigned index)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.no);
> -  return gimple_op (gs, index + gs->gimple_asm.ni);
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.no);
> +  return gimple_op (gs, index);
>  }
>
>  /* Return a pointer to output operand INDEX of GIMPLE_ASM GS.  */
> @@ -2984,8 +2962,8 @@ static inline tree *
>  gimple_asm_output_op_ptr (const_gimple gs, unsigned index)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.no);
> -  return gimple_op_ptr (gs, index + gs->gimple_asm.ni);
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.no);
> +  return gimple_op_ptr (gs, index);
>  }
>
>
> @@ -2995,9 +2973,9 @@ static inline void
>  gimple_asm_set_output_op (gimple gs, unsigned index, tree out_op)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.no
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.no
>                               && TREE_CODE (out_op) == TREE_LIST);
> -  gimple_set_op (gs, index + gs->gimple_asm.ni, out_op);
> +  gimple_set_op (gs, index, out_op);
>  }
>
>
> @@ -3007,7 +2985,7 @@ static inline tree
>  gimple_asm_clobber_op (const_gimple gs, unsigned index)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.nc);
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.nc);
>    return gimple_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.no);
>  }
>
> @@ -3018,7 +2996,7 @@ static inline void
>  gimple_asm_set_clobber_op (gimple gs, unsigned index, tree clobber_op)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.nc
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.nc
>                               && TREE_CODE (clobber_op) == TREE_LIST);
>    gimple_set_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.no, clobber_op);
>  }
> @@ -3029,7 +3007,7 @@ static inline tree
>  gimple_asm_label_op (const_gimple gs, unsigned index)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.nl);
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.nl);
>    return gimple_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.nc);
>  }
>
> @@ -3039,7 +3017,7 @@ static inline void
>  gimple_asm_set_label_op (gimple gs, unsigned index, tree label_op)
>  {
>    GIMPLE_CHECK (gs, GIMPLE_ASM);
> -  gcc_gimple_checking_assert (index <= gs->gimple_asm.nl
> +  gcc_gimple_checking_assert (index < gs->gimple_asm.nl
>                               && TREE_CODE (label_op) == TREE_LIST);
>    gimple_set_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.nc, label_op);
>  }
> Index: tree-flow-inline.h
> ===================================================================
> --- tree-flow-inline.h.orig     2012-09-24 15:26:16.000000000 +0200
> +++ tree-flow-inline.h  2012-10-22 15:27:36.000000000 +0200
> @@ -580,9 +580,9 @@ op_iter_next_use (ssa_op_iter *ptr)
>        ptr->uses = ptr->uses->next;
>        return use_p;
>      }
> -  if (ptr->phi_i < ptr->num_phi)
> +  if (ptr->i < ptr->numops)
>      {
> -      return PHI_ARG_DEF_PTR (ptr->phi_stmt, (ptr->phi_i)++);
> +      return PHI_ARG_DEF_PTR (ptr->stmt, (ptr->i)++);
>      }
>    ptr->done = true;
>    return NULL_USE_OPERAND_P;
> @@ -592,14 +592,33 @@ 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)
> +    {
> +      while (ptr->i < ptr->numops)
> +       {
> +         tree *val = gimple_op_ptr (ptr->stmt, ptr->i);
> +         ptr->i++;
> +         if (*val)
> +           {
> +             if (TREE_CODE (*val) == TREE_LIST)
> +               val = &TREE_VALUE (*val);
> +             if (TREE_CODE (*val) == SSA_NAME
> +                 || is_gimple_reg (*val))
> +               return val;
> +           }
> +       }
> +      ptr->flags &= ~SSA_OP_DEF;
> +    }
> +
>    ptr->done = true;
>    return NULL_DEF_OPERAND_P;
>  }
> @@ -616,16 +635,32 @@ 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)
> +    {
> +      while (ptr->i < ptr->numops)
> +       {
> +         val = gimple_op (ptr->stmt, ptr->i);
> +         ptr->i++;
> +         if (val)
> +           {
> +             if (TREE_CODE (val) == TREE_LIST)
> +               val = TREE_VALUE (val);
> +             if (TREE_CODE (val) == SSA_NAME
> +                 || is_gimple_reg (val))
> +               return val;
> +           }
> +       }
> +      ptr->flags &= ~SSA_OP_DEF;
>      }
>
>    ptr->done = true;
>    return NULL_TREE;
> -
>  }
>
>
> @@ -636,13 +671,13 @@ op_iter_next_tree (ssa_op_iter *ptr)
>  static inline void
>  clear_and_done_ssa_iter (ssa_op_iter *ptr)
>  {
> -  ptr->defs = NULL;
> +  ptr->i = 0;
> +  ptr->numops = 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 +690,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;
> +  ptr->numops = 0;
> +  if (flags & (SSA_OP_DEF | SSA_OP_VDEF))
> +    {
> +      switch (gimple_code (stmt))
> +       {
> +         case GIMPLE_ASSIGN:
> +         case GIMPLE_CALL:
> +           ptr->numops = 1;
> +           break;
> +         case GIMPLE_ASM:
> +           ptr->numops = gimple_asm_noutputs (stmt);
> +           break;
> +         default:
> +           ptr->numops = 0;
> +           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;
> +  ptr->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 +887,10 @@ op_iter_init_phiuse (ssa_op_iter *ptr, g
>        return NULL_USE_OPERAND_P;
>      }
>
> -  ptr->phi_stmt = phi;
> -  ptr->num_phi = gimple_phi_num_args (phi);
> +  ptr->stmt = phi;
> +  ptr->numops = 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-24 15:26:38.000000000 +0200
> +++ tree-ssa-operands.c 2012-10-22 15:12:30.000000000 +0200
> @@ -106,9 +106,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;
>
> @@ -185,7 +182,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;
> @@ -210,13 +206,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)
> @@ -242,8 +236,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)
> @@ -282,25 +275,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 *
> @@ -320,21 +294,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
> @@ -358,14 +317,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)
>      {
> @@ -375,17 +326,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)
> @@ -405,30 +347,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);
>  }
>
>
> @@ -488,8 +406,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);
>      }
>
> @@ -506,7 +422,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);
>  }
>
> @@ -527,22 +442,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
> @@ -620,9 +525,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
>      {
> @@ -669,15 +576,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);
>
> @@ -689,10 +591,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)));
>  }
>
>
> @@ -853,7 +754,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:
> @@ -1126,31 +1027,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");
> @@ -1168,18 +1044,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-24 15:26:19.000000000 +0200
> +++ gimple.c    2012-10-22 15:13:10.000000000 +0200
> @@ -2345,7 +2345,6 @@ 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);
>
>        /* SSA operands need to be updated.  */

Patch

Index: tree-ssa-operands.h
===================================================================
--- tree-ssa-operands.h.orig	2012-09-24 15:24:52.000000000 +0200
+++ tree-ssa-operands.h	2012-10-22 15:12:30.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))
@@ -133,13 +121,13 @@  enum ssa_op_iter_type {
 
 typedef struct ssa_operand_iterator_d
 {
-  bool done;
   enum ssa_op_iter_type iter_type;
-  def_optype_p defs;
+  bool done;
+  int flags;
+  unsigned i;
+  unsigned numops;
   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-10-19 15:03:43.000000000 +0200
+++ gimple.h	2012-10-22 15:12:30.000000000 +0200
@@ -220,12 +222,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;
 };
 
@@ -1372,27 +1374,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 *
@@ -1432,15 +1413,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;
 }
 
@@ -2941,8 +2919,8 @@  static inline tree
 gimple_asm_input_op (const_gimple gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.ni);
-  return gimple_op (gs, index);
+  gcc_gimple_checking_assert (index < gs->gimple_asm.ni);
+  return gimple_op (gs, index + gs->gimple_asm.no);
 }
 
 /* Return a pointer to input operand INDEX of GIMPLE_ASM GS.  */
@@ -2951,8 +2929,8 @@  static inline tree *
 gimple_asm_input_op_ptr (const_gimple gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.ni);
-  return gimple_op_ptr (gs, index);
+  gcc_gimple_checking_assert (index < gs->gimple_asm.ni);
+  return gimple_op_ptr (gs, index + gs->gimple_asm.no);
 }
 
 
@@ -2962,9 +2940,9 @@  static inline void
 gimple_asm_set_input_op (gimple gs, unsigned index, tree in_op)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.ni
+  gcc_gimple_checking_assert (index < gs->gimple_asm.ni
 			      && TREE_CODE (in_op) == TREE_LIST);
-  gimple_set_op (gs, index, in_op);
+  gimple_set_op (gs, index + gs->gimple_asm.no, in_op);
 }
 
 
@@ -2974,8 +2952,8 @@  static inline tree
 gimple_asm_output_op (const_gimple gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.no);
-  return gimple_op (gs, index + gs->gimple_asm.ni);
+  gcc_gimple_checking_assert (index < gs->gimple_asm.no);
+  return gimple_op (gs, index);
 }
 
 /* Return a pointer to output operand INDEX of GIMPLE_ASM GS.  */
@@ -2984,8 +2962,8 @@  static inline tree *
 gimple_asm_output_op_ptr (const_gimple gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.no);
-  return gimple_op_ptr (gs, index + gs->gimple_asm.ni);
+  gcc_gimple_checking_assert (index < gs->gimple_asm.no);
+  return gimple_op_ptr (gs, index);
 }
 
 
@@ -2995,9 +2973,9 @@  static inline void
 gimple_asm_set_output_op (gimple gs, unsigned index, tree out_op)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.no
+  gcc_gimple_checking_assert (index < gs->gimple_asm.no
 			      && TREE_CODE (out_op) == TREE_LIST);
-  gimple_set_op (gs, index + gs->gimple_asm.ni, out_op);
+  gimple_set_op (gs, index, out_op);
 }
 
 
@@ -3007,7 +2985,7 @@  static inline tree
 gimple_asm_clobber_op (const_gimple gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.nc);
+  gcc_gimple_checking_assert (index < gs->gimple_asm.nc);
   return gimple_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.no);
 }
 
@@ -3018,7 +2996,7 @@  static inline void
 gimple_asm_set_clobber_op (gimple gs, unsigned index, tree clobber_op)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.nc
+  gcc_gimple_checking_assert (index < gs->gimple_asm.nc
 			      && TREE_CODE (clobber_op) == TREE_LIST);
   gimple_set_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.no, clobber_op);
 }
@@ -3029,7 +3007,7 @@  static inline tree
 gimple_asm_label_op (const_gimple gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.nl);
+  gcc_gimple_checking_assert (index < gs->gimple_asm.nl);
   return gimple_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.nc);
 }
 
@@ -3039,7 +3017,7 @@  static inline void
 gimple_asm_set_label_op (gimple gs, unsigned index, tree label_op)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASM);
-  gcc_gimple_checking_assert (index <= gs->gimple_asm.nl
+  gcc_gimple_checking_assert (index < gs->gimple_asm.nl
 			      && TREE_CODE (label_op) == TREE_LIST);
   gimple_set_op (gs, index + gs->gimple_asm.ni + gs->gimple_asm.nc, label_op);
 }
Index: tree-flow-inline.h
===================================================================
--- tree-flow-inline.h.orig	2012-09-24 15:26:16.000000000 +0200
+++ tree-flow-inline.h	2012-10-22 15:27:36.000000000 +0200
@@ -580,9 +580,9 @@  op_iter_next_use (ssa_op_iter *ptr)
       ptr->uses = ptr->uses->next;
       return use_p;
     }
-  if (ptr->phi_i < ptr->num_phi)
+  if (ptr->i < ptr->numops)
     {
-      return PHI_ARG_DEF_PTR (ptr->phi_stmt, (ptr->phi_i)++);
+      return PHI_ARG_DEF_PTR (ptr->stmt, (ptr->i)++);
     }
   ptr->done = true;
   return NULL_USE_OPERAND_P;
@@ -592,14 +592,33 @@  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)
+    {
+      while (ptr->i < ptr->numops)
+	{
+	  tree *val = gimple_op_ptr (ptr->stmt, ptr->i);
+	  ptr->i++;
+	  if (*val)
+	    {
+	      if (TREE_CODE (*val) == TREE_LIST)
+		val = &TREE_VALUE (*val);
+	      if (TREE_CODE (*val) == SSA_NAME
+		  || is_gimple_reg (*val))
+		return val;
+	    }
+	}
+      ptr->flags &= ~SSA_OP_DEF;
+    }
+
   ptr->done = true;
   return NULL_DEF_OPERAND_P;
 }
@@ -616,16 +635,32 @@  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)
+    {
+      while (ptr->i < ptr->numops)
+	{
+	  val = gimple_op (ptr->stmt, ptr->i);
+	  ptr->i++;
+	  if (val)
+	    {
+	      if (TREE_CODE (val) == TREE_LIST)
+		val = TREE_VALUE (val);
+	      if (TREE_CODE (val) == SSA_NAME
+		  || is_gimple_reg (val))
+		return val;
+	    }
+	}
+      ptr->flags &= ~SSA_OP_DEF;
     }
 
   ptr->done = true;
   return NULL_TREE;
-
 }
 
 
@@ -636,13 +671,13 @@  op_iter_next_tree (ssa_op_iter *ptr)
 static inline void
 clear_and_done_ssa_iter (ssa_op_iter *ptr)
 {
-  ptr->defs = NULL;
+  ptr->i = 0;
+  ptr->numops = 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 +690,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;
+  ptr->numops = 0;
+  if (flags & (SSA_OP_DEF | SSA_OP_VDEF))
+    {
+      switch (gimple_code (stmt))
+	{
+	  case GIMPLE_ASSIGN:
+	  case GIMPLE_CALL:
+	    ptr->numops = 1;
+	    break;
+	  case GIMPLE_ASM:
+	    ptr->numops = gimple_asm_noutputs (stmt);
+	    break;
+	  default:
+	    ptr->numops = 0;
+	    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;
+  ptr->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 +887,10 @@  op_iter_init_phiuse (ssa_op_iter *ptr, g
       return NULL_USE_OPERAND_P;
     }
 
-  ptr->phi_stmt = phi;
-  ptr->num_phi = gimple_phi_num_args (phi);
+  ptr->stmt = phi;
+  ptr->numops = 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-24 15:26:38.000000000 +0200
+++ tree-ssa-operands.c	2012-10-22 15:12:30.000000000 +0200
@@ -106,9 +106,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;
 
@@ -185,7 +182,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;
@@ -210,13 +206,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)
@@ -242,8 +236,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)
@@ -282,25 +275,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 *
@@ -320,21 +294,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
@@ -358,14 +317,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)
     {
@@ -375,17 +326,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)
@@ -405,30 +347,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);
 }
 
 
@@ -488,8 +406,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);
     }
 
@@ -506,7 +422,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);
 }
 
@@ -527,22 +442,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
@@ -620,9 +525,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
     {
@@ -669,15 +576,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);
 
@@ -689,10 +591,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)));
 }
 
 
@@ -853,7 +754,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:
@@ -1126,31 +1027,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");
@@ -1168,18 +1044,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-24 15:26:19.000000000 +0200
+++ gimple.c	2012-10-22 15:13:10.000000000 +0200
@@ -2345,7 +2345,6 @@  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);
 
       /* SSA operands need to be updated.  */