This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] rewrite stack vectors


On Fri, Oct 11, 2013 at 10:08:00AM +0200, Richard Biener wrote:
> On Thu, Oct 10, 2013 at 8:07 PM,  <tsaunders@mozilla.com> wrote:
> > From: Trevor Saunders <tsaunders@mozilla.com>
> >
> > Hi,
> >
> > This makes the implementation of stack vectors simpler and easier to use.  This                                                                                                                                                    works by making the size of the on stack storage a template argument, so the
> > size is embedded in the type.  This allows you to implicitly convert a
> > stack_vec<T, N> to a vec<T, va_heap> *, and it will just work.
> 
> Any particular reason to not go with a
> 
>  vec<T, va_stack, N>
> 
> partial specialization?

One advantage of using a subclass is that callies don't need to care if
the caller uses a stack vec or a heap one.

I'm also not sure if making one template specialization not POD makes
others not POD as well, which matters because stack_vec has ctors and
dtors.

> Btw, one reason against N being a template parameter is code bloat
> (so hopefully the implementation dispatches to a single vec<T, va_stack>
> set of template instantiations - I didn't look too closely at the patch yet).

the only things it doesn't defer to vec<T, va_heap, vl_ptr> is the ctor
and dtor.  The ctor should be a couple of moves which I would really
expect are smaller than the calls we used to have to alloca and record
the stack vector in the list of stack vectors.  The dtor just calls
release so presumably  the template stuff gets boiled away and there's
no more code than there used to be with the manual call to .release().

Trev

> 
> Richard.
> 
> >  Because there's
> > no need to support stack vectors in unions we can make them be a more normal
> > c++ class with a constructor and destructor that are nontrivial.
> >
> > Trev
> >
> > 2013-10-08  Trevor Saunders  <tsaunders@mozilla.com>
> >
> > ada/
> >         * gcc-interface/decl.c (components_to_record): Adjust.
> >
> > gcc/
> >         * df-scan.c (df_collection_rec): Adjust.
> >         (copy_defs): New constant.
> >         (copy_uses): Likewise.
> >         (copy_eq_uses): Likewise.
> >         (copy_mw): Likewise.
> >         (copy_all): Likewise.
> >         (df_insn_rescan): Adjust.
> >         (df_notes_rescan): Likewise.
> >         (df_swap_refs): Likewise.
> >         (df_sort_and_compress_refs): Likewise.
> >         (df_sort_and_compress_mws): Likewise.
> >         (df_install_refs): Likewise.
> >         (df_install_mws): Likewise.
> >         (df_refs_add_to_chains): Add flags parameter controlling which vectors
> >         are coppied.
> >         (df_bb_refs_record): Adjust.
> >         (df_record_entry_block_defs): Likewise.
> >         (df_record_exit_block_defs): Likewise.
> >         (df_refs_verify): Likewise.
> >         (df_mws_verify): Likewise.
> >         (df_insn_refs_verify): Likewise.
> >         (df_bb_verify): Likewise.
> >         * ipa-pure-const.c (finish_state): Remove.
> >         (propagate): Adjust.
> >         * tree-data-ref.c tree-ssa-alias.c tree-ssa-loop-ivcanon.c
> >         tree-ssa-threadedge.c tree-vect-loop-manip.c tree-vect-slp.c var-tracking.c
> >         Adjust.
> >         * vec.c (stack_vecs): Remove.
> >         (register_stack_vec): Likewise.
> >         (stack_vec_register_index): Likewise.
> >         (unregister_stack_vec): Likewise.
> >         * vec.h (struct va_stack): Remove.
> >         (struct vec<T, A, vl_ptr>): Specialize as
> >         struct vec<T, va_heap, vl_ptr> instead since va_heap is the only
> >         allocation strategy compatable with the vl_ptr layout.
> >         (struct vec<T, va_gc, vl_ptr>): Remove because it now gets an empty
> >         specialization anyway.
> >         (class stack_vec): New class.
> >         (vec_stack_alloc): Remove.
> >         (vec<T, va_heap, vl_ptr>::using_auto_storage): New method.
> >
> > diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
> > index 456d7ab..0debdae 100644
> > --- a/gcc/ada/gcc-interface/decl.c
> > +++ b/gcc/ada/gcc-interface/decl.c
> > @@ -6994,13 +6994,11 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
> >        tree gnu_union_type, gnu_union_name;
> >        tree this_first_free_pos, gnu_variant_list = NULL_TREE;
> >        bool union_field_needs_strict_alignment = false;
> > -      vec <vinfo_t, va_stack> variant_types;
> > +      stack_vec <vinfo_t, 16> variant_types;
> >        vinfo_t *gnu_variant;
> >        unsigned int variants_align = 0;
> >        unsigned int i;
> >
> > -      vec_stack_alloc (vinfo_t, variant_types, 16);
> > -
> >        if (TREE_CODE (gnu_name) == TYPE_DECL)
> >         gnu_name = DECL_NAME (gnu_name);
> >
> > @@ -7196,9 +7194,6 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
> >           gnu_variant_list = gnu_field;
> >         }
> >
> > -      /* We are done with the variants.  */
> > -      variant_types.release ();
> > -
> >        /* Only make the QUAL_UNION_TYPE if there are non-empty variants.  */
> >        if (gnu_variant_list)
> >         {
> > diff --git a/gcc/df-scan.c b/gcc/df-scan.c
> > index f2e8ab2..aace96d 100644
> > --- a/gcc/df-scan.c
> > +++ b/gcc/df-scan.c
> > @@ -86,10 +86,10 @@ static HARD_REG_SET elim_reg_set;
> >
> >  struct df_collection_rec
> >  {
> > -  vec<df_ref, va_stack> def_vec;
> > -  vec<df_ref, va_stack> use_vec;
> > -  vec<df_ref, va_stack> eq_use_vec;
> > -  vec<df_mw_hardreg_ptr, va_stack> mw_vec;
> > +  stack_vec<df_ref, 128> def_vec;
> > +  stack_vec<df_ref, 32> use_vec;
> > +  stack_vec<df_ref, 32> eq_use_vec;
> > +  stack_vec<df_mw_hardreg_ptr, 32> mw_vec;
> >  };
> >
> >  static df_ref df_null_ref_rec[1];
> > @@ -131,7 +131,7 @@ static void df_ref_chain_delete_du_chain (df_ref *);
> >  static void df_ref_chain_delete (df_ref *);
> >
> >  static void df_refs_add_to_chains (struct df_collection_rec *,
> > -                                  basic_block, rtx);
> > +                                  basic_block, rtx, unsigned int);
> >
> >  static bool df_insn_refs_verify (struct df_collection_rec *, basic_block, rtx, bool);
> >  static void df_entry_block_defs_collect (struct df_collection_rec *, bitmap);
> > @@ -153,6 +153,14 @@ static void df_insn_info_delete (unsigned int);
> >     and epilogue to save and restore registers as needed.  */
> >
> >  static bool regs_ever_live[FIRST_PSEUDO_REGISTER];
> > +
> > +/* Flags used to tell df_refs_add_to_chains() which vectors it should copy. */
> > +static const unsigned int copy_defs = 0x1;
> > +static const unsigned int copy_uses = 0x2;
> > +static const unsigned int copy_eq_uses = 0x4;
> > +static const unsigned int copy_mw = 0x8;
> > +static const unsigned int copy_all = copy_defs | copy_uses | copy_eq_uses
> > +| copy_mw;
> >
> >  /*----------------------------------------------------------------------------
> >     SCANNING DATAFLOW PROBLEM
> > @@ -1268,11 +1276,6 @@ df_insn_rescan (rtx insn)
> >        return false;
> >      }
> >
> > -  vec_stack_alloc (df_ref, collection_rec.def_vec, 128);
> > -  vec_stack_alloc (df_ref, collection_rec.use_vec, 32);
> > -  vec_stack_alloc (df_ref, collection_rec.eq_use_vec, 32);
> > -  vec_stack_alloc (df_mw_hardreg_ptr, collection_rec.mw_vec, 32);
> > -
> >    bitmap_clear_bit (&df->insns_to_delete, uid);
> >    bitmap_clear_bit (&df->insns_to_rescan, uid);
> >    bitmap_clear_bit (&df->insns_to_notes_rescan, uid);
> > @@ -1306,15 +1309,10 @@ df_insn_rescan (rtx insn)
> >         fprintf (dump_file, "scanning new insn with uid = %d.\n", uid);
> >      }
> >
> > -  df_refs_add_to_chains (&collection_rec, bb, insn);
> > +  df_refs_add_to_chains (&collection_rec, bb, insn, copy_all);
> >    if (!DEBUG_INSN_P (insn))
> >      df_set_bb_dirty (bb);
> >
> > -  collection_rec.def_vec.release ();
> > -  collection_rec.use_vec.release ();
> > -  collection_rec.eq_use_vec.release ();
> > -  collection_rec.mw_vec.release ();
> > -
> >    return true;
> >  }
> >
> > @@ -2221,10 +2219,6 @@ df_notes_rescan (rtx insn)
> >        unsigned int num_deleted;
> >        unsigned int mw_len;
> >
> > -      memset (&collection_rec, 0, sizeof (struct df_collection_rec));
> > -      vec_stack_alloc (df_ref, collection_rec.eq_use_vec, 32);
> > -      vec_stack_alloc (df_mw_hardreg_ptr, collection_rec.mw_vec, 32);
> > -
> >        num_deleted = df_mw_hardreg_chain_delete_eq_uses (insn_info);
> >        df_ref_chain_delete (insn_info->eq_uses);
> >        insn_info->eq_uses = NULL;
> > @@ -2287,11 +2281,7 @@ df_notes_rescan (rtx insn)
> >               insn_info->mw_hardregs[mw_len] = NULL;
> >             }
> >         }
> > -      /* Get rid of the mw_rec so that df_refs_add_to_chains will
> > -        ignore it.  */
> > -      collection_rec.mw_vec.release ();
> > -      df_refs_add_to_chains (&collection_rec, bb, insn);
> > -      collection_rec.eq_use_vec.release ();
> > +      df_refs_add_to_chains (&collection_rec, bb, insn, copy_eq_uses);
> >      }
> >    else
> >      df_insn_rescan (insn);
> > @@ -2391,7 +2381,7 @@ df_ref_compare (const void *r1, const void *r2)
> >  }
> >
> >  static void
> > -df_swap_refs (vec<df_ref, va_stack> *ref_vec, int i, int j)
> > +df_swap_refs (vec<df_ref, va_heap> *ref_vec, int i, int j)
> >  {
> >    df_ref tmp = (*ref_vec)[i];
> >    (*ref_vec)[i] = (*ref_vec)[j];
> > @@ -2401,7 +2391,7 @@ df_swap_refs (vec<df_ref, va_stack> *ref_vec, int i, int j)
> >  /* Sort and compress a set of refs.  */
> >
> >  static void
> > -df_sort_and_compress_refs (vec<df_ref, va_stack> *ref_vec)
> > +df_sort_and_compress_refs (vec<df_ref, va_heap> *ref_vec)
> >  {
> >    unsigned int count;
> >    unsigned int i;
> > @@ -2510,7 +2500,7 @@ df_mw_compare (const void *m1, const void *m2)
> >  /* Sort and compress a set of refs.  */
> >
> >  static void
> > -df_sort_and_compress_mws (vec<df_mw_hardreg_ptr, va_stack> *mw_vec)
> > +df_sort_and_compress_mws (vec<df_mw_hardreg_ptr, va_heap> *mw_vec)
> >  {
> >    unsigned int count;
> >    struct df_scan_problem_data *problem_data
> > @@ -2621,14 +2611,12 @@ df_install_ref (df_ref this_ref,
> >
> >  static df_ref *
> >  df_install_refs (basic_block bb,
> > -                vec<df_ref, va_stack> old_vec,
> > +                const vec<df_ref, va_heap> *old_vec,
> >                  struct df_reg_info **reg_info,
> >                  struct df_ref_info *ref_info,
> >                  bool is_notes)
> >  {
> > -  unsigned int count;
> > -
> > -  count = old_vec.length ();
> > +  unsigned int count = old_vec->length ();
> >    if (count)
> >      {
> >        df_ref *new_vec = XNEWVEC (df_ref, count + 1);
> > @@ -2659,7 +2647,7 @@ df_install_refs (basic_block bb,
> >        if (add_to_table && df->analyze_subset)
> >         add_to_table = bitmap_bit_p (df->blocks_to_analyze, bb->index);
> >
> > -      FOR_EACH_VEC_ELT (old_vec, ix, this_ref)
> > +      FOR_EACH_VEC_ELT (*old_vec, ix, this_ref)
> >         {
> >           new_vec[ix] = this_ref;
> >           df_install_ref (this_ref, reg_info[DF_REF_REGNO (this_ref)],
> > @@ -2678,16 +2666,14 @@ df_install_refs (basic_block bb,
> >     insn.  */
> >
> >  static struct df_mw_hardreg **
> > -df_install_mws (vec<df_mw_hardreg_ptr, va_stack> old_vec)
> > +df_install_mws (const vec<df_mw_hardreg_ptr, va_heap> *old_vec)
> >  {
> > -  unsigned int count;
> > -
> > -  count = old_vec.length ();
> > +  unsigned int count = old_vec->length ();
> >    if (count)
> >      {
> >        struct df_mw_hardreg **new_vec
> >         = XNEWVEC (struct df_mw_hardreg*, count + 1);
> > -      memcpy (new_vec, old_vec.address (),
> > +      memcpy (new_vec, old_vec->address (),
> >               sizeof (struct df_mw_hardreg*) * count);
> >        new_vec[count] = NULL;
> >        return new_vec;
> > @@ -2702,7 +2688,7 @@ df_install_mws (vec<df_mw_hardreg_ptr, va_stack> old_vec)
> >
> >  static void
> >  df_refs_add_to_chains (struct df_collection_rec *collection_rec,
> > -                      basic_block bb, rtx insn)
> > +                      basic_block bb, rtx insn, unsigned int flags)
> >  {
> >    if (insn)
> >      {
> > @@ -2710,35 +2696,35 @@ df_refs_add_to_chains (struct df_collection_rec *collection_rec,
> >        /* If there is a vector in the collection rec, add it to the
> >          insn.  A null rec is a signal that the caller will handle the
> >          chain specially.  */
> > -      if (collection_rec->def_vec.exists ())
> > +      if (flags & copy_defs)
> >         {
> >           df_scan_free_ref_vec (insn_rec->defs);
> >           insn_rec->defs
> > -           = df_install_refs (bb, collection_rec->def_vec,
> > +           = df_install_refs (bb, &collection_rec->def_vec,
> >                                df->def_regs,
> >                                &df->def_info, false);
> >         }
> > -      if (collection_rec->use_vec.exists ())
> > +      if (flags & copy_uses)
> >         {
> >           df_scan_free_ref_vec (insn_rec->uses);
> >           insn_rec->uses
> > -           = df_install_refs (bb, collection_rec->use_vec,
> > +           = df_install_refs (bb, &collection_rec->use_vec,
> >                                df->use_regs,
> >                                &df->use_info, false);
> >         }
> > -      if (collection_rec->eq_use_vec.exists ())
> > +      if (flags & copy_eq_uses)
> >         {
> >           df_scan_free_ref_vec (insn_rec->eq_uses);
> >           insn_rec->eq_uses
> > -           = df_install_refs (bb, collection_rec->eq_use_vec,
> > +           = df_install_refs (bb, &collection_rec->eq_use_vec,
> >                                df->eq_use_regs,
> >                                &df->use_info, true);
> >         }
> > -      if (collection_rec->mw_vec.exists ())
> > +      if (flags & copy_mw)
> >         {
> >           df_scan_free_mws_vec (insn_rec->mw_hardregs);
> >           insn_rec->mw_hardregs
> > -           = df_install_mws (collection_rec->mw_vec);
> > +           = df_install_mws (&collection_rec->mw_vec);
> >         }
> >      }
> >    else
> > @@ -2747,12 +2733,12 @@ df_refs_add_to_chains (struct df_collection_rec *collection_rec,
> >
> >        df_scan_free_ref_vec (bb_info->artificial_defs);
> >        bb_info->artificial_defs
> > -       = df_install_refs (bb, collection_rec->def_vec,
> > +       = df_install_refs (bb, &collection_rec->def_vec,
> >                            df->def_regs,
> >                            &df->def_info, false);
> >        df_scan_free_ref_vec (bb_info->artificial_uses);
> >        bb_info->artificial_uses
> > -       = df_install_refs (bb, collection_rec->use_vec,
> > +       = df_install_refs (bb, &collection_rec->use_vec,
> >                            df->use_regs,
> >                            &df->use_info, false);
> >      }
> > @@ -3633,17 +3619,12 @@ df_bb_refs_record (int bb_index, bool scan_insns)
> >    basic_block bb = BASIC_BLOCK (bb_index);
> >    rtx insn;
> >    int luid = 0;
> > -  struct df_collection_rec collection_rec;
> >
> >    if (!df)
> >      return;
> >
> > +  df_collection_rec collection_rec;
> >    df_grow_bb_info (df_scan);
> > -  vec_stack_alloc (df_ref, collection_rec.def_vec, 128);
> > -  vec_stack_alloc (df_ref, collection_rec.use_vec, 32);
> > -  vec_stack_alloc (df_ref, collection_rec.eq_use_vec, 32);
> > -  vec_stack_alloc (df_mw_hardreg_ptr, collection_rec.mw_vec, 32);
> > -
> >    if (scan_insns)
> >      /* Scan the block an insn at a time from beginning to end.  */
> >      FOR_BB_INSNS (bb, insn)
> > @@ -3657,19 +3638,14 @@ df_bb_refs_record (int bb_index, bool scan_insns)
> >             /* Record refs within INSN.  */
> >             DF_INSN_INFO_LUID (insn_info) = luid++;
> >             df_insn_refs_collect (&collection_rec, bb, DF_INSN_INFO_GET (insn));
> > -           df_refs_add_to_chains (&collection_rec, bb, insn);
> > +           df_refs_add_to_chains (&collection_rec, bb, insn, copy_all);
> >           }
> >         DF_INSN_INFO_LUID (insn_info) = luid;
> >        }
> >
> >    /* Other block level artificial refs */
> >    df_bb_refs_collect (&collection_rec, bb);
> > -  df_refs_add_to_chains (&collection_rec, bb, NULL);
> > -
> > -  collection_rec.def_vec.release ();
> > -  collection_rec.use_vec.release ();
> > -  collection_rec.eq_use_vec.release ();
> > -  collection_rec.mw_vec.release ();
> > +  df_refs_add_to_chains (&collection_rec, bb, NULL, copy_all);
> >
> >    /* Now that the block has been processed, set the block as dirty so
> >       LR and LIVE will get it processed.  */
> > @@ -3911,13 +3887,11 @@ static void
> >  df_record_entry_block_defs (bitmap entry_block_defs)
> >  {
> >    struct df_collection_rec collection_rec;
> > -  memset (&collection_rec, 0, sizeof (struct df_collection_rec));
> > -  vec_stack_alloc (df_ref, collection_rec.def_vec, FIRST_PSEUDO_REGISTER);
> >    df_entry_block_defs_collect (&collection_rec, entry_block_defs);
> >
> >    /* Process bb_refs chain */
> > -  df_refs_add_to_chains (&collection_rec, BASIC_BLOCK (ENTRY_BLOCK), NULL);
> > -  collection_rec.def_vec.release ();
> > +  df_refs_add_to_chains (&collection_rec, BASIC_BLOCK (ENTRY_BLOCK), NULL,
> > +                        copy_defs);
> >  }
> >
> >
> > @@ -4084,13 +4058,11 @@ static void
> >  df_record_exit_block_uses (bitmap exit_block_uses)
> >  {
> >    struct df_collection_rec collection_rec;
> > -  memset (&collection_rec, 0, sizeof (struct df_collection_rec));
> > -  vec_stack_alloc (df_ref, collection_rec.use_vec, FIRST_PSEUDO_REGISTER);
> >    df_exit_block_uses_collect (&collection_rec, exit_block_uses);
> >
> >    /* Process bb_refs chain */
> > -  df_refs_add_to_chains (&collection_rec, BASIC_BLOCK (EXIT_BLOCK), NULL);
> > -  collection_rec.use_vec.release ();
> > +  df_refs_add_to_chains (&collection_rec, BASIC_BLOCK (EXIT_BLOCK), NULL,
> > +                        copy_uses);
> >  }
> >
> >
> > @@ -4331,13 +4303,13 @@ df_reg_chain_verify_unmarked (df_ref refs)
> >  /* Verify that NEW_REC and OLD_REC have exactly the same members. */
> >
> >  static bool
> > -df_refs_verify (vec<df_ref, va_stack> new_rec, df_ref *old_rec,
> > +df_refs_verify (const vec<df_ref, va_heap> *new_rec, df_ref *old_rec,
> >                 bool abort_if_fail)
> >  {
> >    unsigned int ix;
> >    df_ref new_ref;
> >
> > -  FOR_EACH_VEC_ELT (new_rec, ix, new_ref)
> > +  FOR_EACH_VEC_ELT (*new_rec, ix, new_ref)
> >      {
> >        if (*old_rec == NULL || !df_ref_equal_p (new_ref, *old_rec))
> >         {
> > @@ -4369,14 +4341,14 @@ df_refs_verify (vec<df_ref, va_stack> new_rec, df_ref *old_rec,
> >  /* Verify that NEW_REC and OLD_REC have exactly the same members. */
> >
> >  static bool
> > -df_mws_verify (vec<df_mw_hardreg_ptr, va_stack> new_rec,
> > +df_mws_verify (const vec<df_mw_hardreg_ptr, va_heap> *new_rec,
> >                struct df_mw_hardreg **old_rec,
> >                bool abort_if_fail)
> >  {
> >    unsigned int ix;
> >    struct df_mw_hardreg *new_reg;
> >
> > -  FOR_EACH_VEC_ELT (new_rec, ix, new_reg)
> > +  FOR_EACH_VEC_ELT (*new_rec, ix, new_reg)
> >      {
> >        if (*old_rec == NULL || !df_mw_equal_p (new_reg, *old_rec))
> >         {
> > @@ -4430,13 +4402,13 @@ df_insn_refs_verify (struct df_collection_rec *collection_rec,
> >
> >    /* Unfortunately we cannot opt out early if one of these is not
> >       right because the marks will not get cleared.  */
> > -  ret1 = df_refs_verify (collection_rec->def_vec, DF_INSN_UID_DEFS (uid),
> > +  ret1 = df_refs_verify (&collection_rec->def_vec, DF_INSN_UID_DEFS (uid),
> >                          abort_if_fail);
> > -  ret2 = df_refs_verify (collection_rec->use_vec, DF_INSN_UID_USES (uid),
> > +  ret2 = df_refs_verify (&collection_rec->use_vec, DF_INSN_UID_USES (uid),
> >                          abort_if_fail);
> > -  ret3 = df_refs_verify (collection_rec->eq_use_vec, DF_INSN_UID_EQ_USES (uid),
> > +  ret3 = df_refs_verify (&collection_rec->eq_use_vec, DF_INSN_UID_EQ_USES (uid),
> >                          abort_if_fail);
> > -  ret4 = df_mws_verify (collection_rec->mw_vec, DF_INSN_UID_MWS (uid),
> > +  ret4 = df_mws_verify (&collection_rec->mw_vec, DF_INSN_UID_MWS (uid),
> >                        abort_if_fail);
> >    return (ret1 && ret2 && ret3 && ret4);
> >  }
> > @@ -4453,12 +4425,6 @@ df_bb_verify (basic_block bb)
> >    struct df_scan_bb_info *bb_info = df_scan_get_bb_info (bb->index);
> >    struct df_collection_rec collection_rec;
> >
> > -  memset (&collection_rec, 0, sizeof (struct df_collection_rec));
> > -  vec_stack_alloc (df_ref, collection_rec.def_vec, 128);
> > -  vec_stack_alloc (df_ref, collection_rec.use_vec, 32);
> > -  vec_stack_alloc (df_ref, collection_rec.eq_use_vec, 32);
> > -  vec_stack_alloc (df_mw_hardreg_ptr, collection_rec.mw_vec, 32);
> > -
> >    gcc_assert (bb_info);
> >
> >    /* Scan the block, one insn at a time, from beginning to end.  */
> > @@ -4472,8 +4438,8 @@ df_bb_verify (basic_block bb)
> >
> >    /* Do the artificial defs and uses.  */
> >    df_bb_refs_collect (&collection_rec, bb);
> > -  df_refs_verify (collection_rec.def_vec, df_get_artificial_defs (bb->index), true);
> > -  df_refs_verify (collection_rec.use_vec, df_get_artificial_uses (bb->index), true);
> > +  df_refs_verify (&collection_rec.def_vec, df_get_artificial_defs (bb->index), true);
> > +  df_refs_verify (&collection_rec.use_vec, df_get_artificial_uses (bb->index), true);
> >    df_free_collection_rec (&collection_rec);
> >
> >    return true;
> > diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
> > index 85e5736..7e37b49 100644
> > --- a/gcc/ipa-pure-const.c
> > +++ b/gcc/ipa-pure-const.c
> > @@ -190,15 +190,6 @@ warn_function_noreturn (tree decl)
> >                            true, warned_about, "noreturn");
> >  }
> >
> > -/* Init the function state.  */
> > -
> > -static void
> > -finish_state (void)
> > -{
> > -  funct_state_vec.release ();
> > -}
> > -
> > -
> >  /* Return true if we have a function state for NODE.  */
> >
> >  static inline bool
> > @@ -1488,7 +1479,6 @@ propagate (void)
> >      if (has_function_state (node))
> >        free (get_function_state (node));
> >    funct_state_vec.release ();
> > -  finish_state ();
> >    return 0;
> >  }
> >
> > diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
> > index 9133df4..acdb689 100644
> > --- a/gcc/tree-data-ref.c
> > +++ b/gcc/tree-data-ref.c
> > @@ -4322,7 +4322,7 @@ typedef struct data_ref_loc_d
> >     true if STMT clobbers memory, false otherwise.  */
> >
> >  static bool
> > -get_references_in_stmt (gimple stmt, vec<data_ref_loc, va_stack> *references)
> > +get_references_in_stmt (gimple stmt, vec<data_ref_loc, va_heap> *references)
> >  {
> >    bool clobbers_memory = false;
> >    data_ref_loc ref;
> > @@ -4414,17 +4414,13 @@ find_data_references_in_stmt (struct loop *nest, gimple stmt,
> >                               vec<data_reference_p> *datarefs)
> >  {
> >    unsigned i;
> > -  vec<data_ref_loc, va_stack> references;
> > +  stack_vec<data_ref_loc, 2> references;
> >    data_ref_loc *ref;
> >    bool ret = true;
> >    data_reference_p dr;
> >
> > -  vec_stack_alloc (data_ref_loc, references, 2);
> >    if (get_references_in_stmt (stmt, &references))
> > -    {
> > -      references.release ();
> > -      return false;
> > -    }
> > +    return false;
> >
> >    FOR_EACH_VEC_ELT (references, i, ref)
> >      {
> > @@ -4448,17 +4444,13 @@ graphite_find_data_references_in_stmt (loop_p nest, loop_p loop, gimple stmt,
> >                                        vec<data_reference_p> *datarefs)
> >  {
> >    unsigned i;
> > -  vec<data_ref_loc, va_stack> references;
> > +  stack_vec<data_ref_loc, 2> references;
> >    data_ref_loc *ref;
> >    bool ret = true;
> >    data_reference_p dr;
> >
> > -  vec_stack_alloc (data_ref_loc, references, 2);
> >    if (get_references_in_stmt (stmt, &references))
> > -    {
> > -      references.release ();
> > -      return false;
> > -    }
> > +    return false;
> >
> >    FOR_EACH_VEC_ELT (references, i, ref)
> >      {
> > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > index 4aaa98b..04a0979 100644
> > --- a/gcc/tree-ssa-alias.c
> > +++ b/gcc/tree-ssa-alias.c
> > @@ -726,11 +726,8 @@ aliasing_component_refs_p (tree ref1,
> >  static bool
> >  nonoverlapping_component_refs_of_decl_p (tree ref1, tree ref2)
> >  {
> > -  vec<tree, va_stack> component_refs1;
> > -  vec<tree, va_stack> component_refs2;
> > -
> > -  vec_stack_alloc (tree, component_refs1, 16);
> > -  vec_stack_alloc (tree, component_refs2, 16);
> > +  stack_vec<tree, 16> component_refs1;
> > +  stack_vec<tree, 16> component_refs2;
> >
> >    /* Create the stack of handled components for REF1.  */
> >    while (handled_component_p (ref1))
> > diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
> > index 8db5b9e..fd3c892 100644
> > --- a/gcc/tree-ssa-loop-ivcanon.c
> > +++ b/gcc/tree-ssa-loop-ivcanon.c
> > @@ -1089,7 +1089,7 @@ propagate_constants_for_unrolling (basic_block bb)
> >
> >  static bool
> >  tree_unroll_loops_completely_1 (bool may_increase_size, bool unroll_outer,
> > -                               vec<loop_p, va_stack>& father_stack,
> > +                               vec<loop_p, va_heap>& father_stack,
> >                                 struct loop *loop)
> >  {
> >    struct loop *loop_father;
> > @@ -1153,12 +1153,11 @@ tree_unroll_loops_completely_1 (bool may_increase_size, bool unroll_outer,
> >  unsigned int
> >  tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
> >  {
> > -  vec<loop_p, va_stack> father_stack;
> > +  stack_vec<loop_p, 16> father_stack;
> >    bool changed;
> >    int iteration = 0;
> >    bool irred_invalidated = false;
> >
> > -  vec_stack_alloc (loop_p, father_stack, 16);
> >    do
> >      {
> >        changed = false;
> > diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
> > index c2dd015..4b32bb4 100644
> > --- a/gcc/tree-ssa-threadedge.c
> > +++ b/gcc/tree-ssa-threadedge.c
> > @@ -638,7 +638,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
> >        i++;
> >      }
> >
> > -  vec<tree, va_stack> fewvars = vNULL;
> > +  stack_vec<tree, alloc_count> fewvars;
> >    pointer_set_t *vars = NULL;
> >
> >    /* If we're already starting with 3/4 of alloc_count, go for a
> > @@ -646,8 +646,6 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
> >       VEC.  */
> >    if (i * 4 > alloc_count * 3)
> >      vars = pointer_set_create ();
> > -  else if (alloc_count)
> > -    vec_stack_alloc (tree, fewvars, alloc_count);
> >
> >    /* Now go through the initial debug stmts in DEST again, this time
> >       actually inserting in VARS or FEWVARS.  Don't bother checking for
> > diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
> > index 574446a..4a14607 100644
> > --- a/gcc/tree-vect-loop-manip.c
> > +++ b/gcc/tree-vect-loop-manip.c
> > @@ -107,7 +107,7 @@ typedef struct
> >     with a PHI DEF that would soon become non-dominant, and when we got
> >     to the suitable one, it wouldn't have anything to substitute any
> >     more.  */
> > -static vec<adjust_info, va_stack> adjust_vec;
> > +static vec<adjust_info, va_heap> adjust_vec;
> >
> >  /* Adjust any debug stmts that referenced AI->from values to use the
> >     loop-closed AI->to, if the references are dominated by AI->bb and
> > @@ -1125,7 +1125,7 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
> >    if (MAY_HAVE_DEBUG_STMTS)
> >      {
> >        gcc_assert (!adjust_vec.exists ());
> > -      vec_stack_alloc (adjust_info, adjust_vec, 32);
> > +      adjust_vec.create (32);
> >      }
> >
> >    if (e == exit_e)
> > diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
> > index b3b3abe..f6a99eb 100644
> > --- a/gcc/tree-vect-slp.c
> > +++ b/gcc/tree-vect-slp.c
> > @@ -1930,7 +1930,7 @@ vect_slp_analyze_operations (bb_vec_info bb_vinfo)
> >
> >  static unsigned
> >  vect_bb_slp_scalar_cost (basic_block bb,
> > -                        slp_tree node, vec<bool, va_stack> life)
> > +                        slp_tree node, vec<bool, va_heap> *life)
> >  {
> >    unsigned scalar_cost = 0;
> >    unsigned i;
> > @@ -1944,7 +1944,7 @@ vect_bb_slp_scalar_cost (basic_block bb,
> >        def_operand_p def_p;
> >        stmt_vec_info stmt_info;
> >
> > -      if (life[i])
> > +      if ((*life)[i])
> >         continue;
> >
> >        /* If there is a non-vectorized use of the defs then the scalar
> > @@ -1961,11 +1961,11 @@ vect_bb_slp_scalar_cost (basic_block bb,
> >                 || gimple_bb (use_stmt) != bb
> >                 || !STMT_VINFO_VECTORIZABLE (vinfo_for_stmt (use_stmt)))
> >               {
> > -               life[i] = true;
> > +               (*life)[i] = true;
> >                 BREAK_FROM_IMM_USE_STMT (use_iter);
> >               }
> >         }
> > -      if (life[i])
> > +      if ((*life)[i])
> >         continue;
> >
> >        stmt_info = vinfo_for_stmt (stmt);
> > @@ -2019,13 +2019,11 @@ vect_bb_vectorization_profitable_p (bb_vec_info bb_vinfo)
> >    /* Calculate scalar cost.  */
> >    FOR_EACH_VEC_ELT (slp_instances, i, instance)
> >      {
> > -      vec<bool, va_stack> life;
> > -      vec_stack_alloc (bool, life, SLP_INSTANCE_GROUP_SIZE (instance));
> > -      life.quick_grow_cleared (SLP_INSTANCE_GROUP_SIZE (instance));
> > +      stack_vec<bool, 20> life;
> > +      life.safe_grow_cleared (SLP_INSTANCE_GROUP_SIZE (instance));
> >        scalar_cost += vect_bb_slp_scalar_cost (BB_VINFO_BB (bb_vinfo),
> >                                               SLP_INSTANCE_TREE (instance),
> > -                                             life);
> > -      life.release ();
> > +                                             &life);
> >      }
> >
> >    /* Complete the target-specific cost calculation.  */
> > diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
> > index 24c61cc..e908de1 100644
> > --- a/gcc/var-tracking.c
> > +++ b/gcc/var-tracking.c
> > @@ -7905,7 +7905,7 @@ struct expand_loc_callback_data
> >
> >    /* Stack of values and debug_exprs under expansion, and their
> >       children.  */
> > -  vec<rtx, va_stack> expanding;
> > +  stack_vec<rtx, 4> expanding;
> >
> >    /* Stack of values and debug_exprs whose expansion hit recursion
> >       cycles.  They will have VALUE_RECURSED_INTO marked when added to
> > @@ -7913,7 +7913,7 @@ struct expand_loc_callback_data
> >       resolves to a valid location.  So, if the flag remains set at the
> >       end of the search, we know no valid location for this one can
> >       possibly exist.  */
> > -  vec<rtx, va_stack> pending;
> > +  stack_vec<rtx, 4> pending;
> >
> >    /* The maximum depth among the sub-expressions under expansion.
> >       Zero indicates no expansion so far.  */
> > @@ -8415,11 +8415,11 @@ vt_expand_loc_callback (rtx x, bitmap regs,
> >     This function performs this finalization of NULL locations.  */
> >
> >  static void
> > -resolve_expansions_pending_recursion (vec<rtx, va_stack> pending)
> > +resolve_expansions_pending_recursion (vec<rtx, va_heap> *pending)
> >  {
> > -  while (!pending.is_empty ())
> > +  while (!pending->is_empty ())
> >      {
> > -      rtx x = pending.pop ();
> > +      rtx x = pending->pop ();
> >        decl_or_value dv;
> >
> >        if (!VALUE_RECURSED_INTO (x))
> > @@ -8439,8 +8439,6 @@ resolve_expansions_pending_recursion (vec<rtx, va_stack> pending)
> >    do                                                           \
> >      {                                                          \
> >        (d).vars = (v);                                          \
> > -      vec_stack_alloc (rtx, (d).expanding, 4);                 \
> > -      vec_stack_alloc (rtx, (d).pending, 4);                   \
> >        (d).depth.complexity = (d).depth.entryvals = 0;          \
> >      }                                                          \
> >    while (0)
> > @@ -8448,7 +8446,7 @@ resolve_expansions_pending_recursion (vec<rtx, va_stack> pending)
> >  #define FINI_ELCD(d, l)                                                \
> >    do                                                           \
> >      {                                                          \
> > -      resolve_expansions_pending_recursion ((d).pending);      \
> > +      resolve_expansions_pending_recursion (&(d).pending);     \
> >        (d).pending.release ();                                  \
> >        (d).expanding.release ();                                        \
> >                                                                 \
> > @@ -8742,7 +8740,7 @@ emit_note_insn_var_location (variable_def **varp, emit_note_data *data)
> >
> >  int
> >  var_track_values_to_stack (variable_def **slot,
> > -                          vec<rtx, va_stack> *changed_values_stack)
> > +                          vec<rtx, va_heap> *changed_values_stack)
> >  {
> >    variable var = *slot;
> >
> > @@ -8777,7 +8775,7 @@ remove_value_from_changed_variables (rtx val)
> >
> >  static void
> >  notify_dependents_of_changed_value (rtx val, variable_table_type htab,
> > -                                   vec<rtx, va_stack> *changed_values_stack)
> > +                                   vec<rtx, va_heap> *changed_values_stack)
> >  {
> >    variable_def **slot;
> >    variable var;
> > @@ -8862,13 +8860,11 @@ process_changed_values (variable_table_type htab)
> >  {
> >    int i, n;
> >    rtx val;
> > -  vec<rtx, va_stack> changed_values_stack;
> > -
> > -  vec_stack_alloc (rtx, changed_values_stack, 20);
> > +  stack_vec<rtx, 20> changed_values_stack;
> >
> >    /* Move values from changed_variables to changed_values_stack.  */
> >    changed_variables
> > -    .traverse <vec<rtx, va_stack>*, var_track_values_to_stack>
> > +    .traverse <vec<rtx, va_heap>*, var_track_values_to_stack>
> >        (&changed_values_stack);
> >
> >    /* Back-propagate change notifications in values while popping
> > @@ -8889,8 +8885,6 @@ process_changed_values (variable_table_type htab)
> >           n--;
> >         }
> >      }
> > -
> > -  changed_values_stack.release ();
> >  }
> >
> >  /* Emit NOTE_INSN_VAR_LOCATION note for each variable from a chain
> > diff --git a/gcc/vec.c b/gcc/vec.c
> > index 1303d53..f3c3315 100644
> > --- a/gcc/vec.c
> > +++ b/gcc/vec.c
> > @@ -217,49 +217,6 @@ vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve,
> >  }
> >
> >
> > -/* Stack vectors are a little different.  VEC_alloc turns into a call
> > -   to vec<T, A>::stack_reserve and passes in space allocated via a
> > -   call to alloca.  We record that pointer so that we know that we
> > -   shouldn't free it.  If the vector is resized, we resize it on the
> > -   heap.  We record the pointers in a vector and search it in LIFO
> > -   order--i.e., we look for the newest stack vectors first.  We don't
> > -   expect too many stack vectors at any one level, and searching from
> > -   the end should normally be efficient even if they are used in a
> > -   recursive function.  */
> > -
> > -static vec<void *> stack_vecs;
> > -
> > -/* Add a stack vector to STACK_VECS.  */
> > -
> > -void
> > -register_stack_vec (void *vec)
> > -{
> > -  stack_vecs.safe_push (vec);
> > -}
> > -
> > -
> > -/* If VEC is registered in STACK_VECS, return its index.
> > -   Otherwise, return -1.  */
> > -
> > -int
> > -stack_vec_register_index (void *vec)
> > -{
> > -  for (unsigned ix = stack_vecs.length (); ix > 0; --ix)
> > -    if (stack_vecs[ix - 1] == vec)
> > -      return static_cast<int> (ix - 1);
> > -  return -1;
> > -}
> > -
> > -
> > -/* Remove vector at slot IX from the list of registered stack vectors.  */
> > -
> > -void
> > -unregister_stack_vec (unsigned ix)
> > -{
> > -  stack_vecs.unordered_remove (ix);
> > -}
> > -
> > -
> >  /* Helper for qsort; sort descriptors by amount of memory consumed.  */
> >
> >  static int
> > diff --git a/gcc/vec.h b/gcc/vec.h
> > index 60b77ec..f97e022 100644
> > --- a/gcc/vec.h
> > +++ b/gcc/vec.h
> > @@ -101,8 +101,6 @@ along with GCC; see the file COPYING3.  If not see
> >         - Heap: allocation is done using malloc/free.  This is the
> >           default allocation strategy.
> >
> > -       - Stack: allocation is done using alloca.
> > -
> >         - GC: allocation is done using ggc_alloc/ggc_free.
> >
> >         - GC atomic: same as GC with the exception that the elements
> > @@ -233,9 +231,9 @@ struct vec_prefix
> >    friend struct va_gc;
> >    friend struct va_gc_atomic;
> >    friend struct va_heap;
> > -  friend struct va_stack;
> >
> > -  unsigned m_alloc;
> > +  unsigned m_alloc : 31;
> > +  unsigned m_has_auto_buf : 1;
> >    unsigned m_num;
> >  };
> >
> > @@ -255,8 +253,7 @@ struct vl_ptr { };
> >     va_heap     - Allocation uses malloc/free.
> >     va_gc       - Allocation uses ggc_alloc.
> >     va_gc_atomic        - Same as GC, but individual elements of the array
> > -                 do not need to be marked during collection.
> > -   va_stack    - Allocation uses alloca.  */
> > +                 do not need to be marked during collection.  */
> >
> >  /* Allocator type for heap vectors.  */
> >  struct va_heap
> > @@ -401,107 +398,6 @@ struct va_gc_atomic : va_gc
> >  };
> >
> >
> > -/* Allocator type for stack vectors.  */
> > -struct va_stack
> > -{
> > -  /* Use vl_ptr as the default layout for stack vectors.  */
> > -  typedef vl_ptr default_layout;
> > -
> > -  template<typename T>
> > -  static void alloc (vec<T, va_stack, vl_ptr>&, unsigned,
> > -                    vec<T, va_stack, vl_embed> *);
> > -
> > -  template <typename T>
> > -  static void reserve (vec<T, va_stack, vl_embed> *&, unsigned, bool
> > -                      CXX_MEM_STAT_INFO);
> > -
> > -  template <typename T>
> > -  static void release (vec<T, va_stack, vl_embed> *&);
> > -};
> > -
> > -/* Helper functions to keep track of vectors allocated on the stack.  */
> > -void register_stack_vec (void *);
> > -int stack_vec_register_index (void *);
> > -void unregister_stack_vec (unsigned);
> > -
> > -/* Allocate a vector V which uses alloca for the initial allocation.
> > -   SPACE is space allocated using alloca.  NELEMS is the number of
> > -   entries allocated.  */
> > -
> > -template<typename T>
> > -void
> > -va_stack::alloc (vec<T, va_stack, vl_ptr> &v, unsigned nelems,
> > -                vec<T, va_stack, vl_embed> *space)
> > -{
> > -  v.m_vec = space;
> > -  register_stack_vec (static_cast<void *> (v.m_vec));
> > -  v.m_vec->embedded_init (nelems, 0);
> > -}
> > -
> > -
> > -/* Reserve NELEMS slots for a vector initially allocated on the stack.
> > -   When this happens, we switch back to heap allocation.  We remove
> > -   the vector from stack_vecs, if it is there, since we no longer need
> > -   to avoid freeing it.  If EXACT is true, grow exactly, otherwise
> > -   grow exponentially.  */
> > -
> > -template<typename T>
> > -void
> > -va_stack::reserve (vec<T, va_stack, vl_embed> *&v, unsigned nelems, bool exact
> > -                  MEM_STAT_DECL)
> > -{
> > -  int ix = stack_vec_register_index (static_cast<void *> (v));
> > -  if (ix >= 0)
> > -    unregister_stack_vec (ix);
> > -  else
> > -    {
> > -      /* V is already on the heap.  */
> > -      va_heap::reserve (reinterpret_cast<vec<T, va_heap, vl_embed> *&> (v),
> > -                       nelems, exact PASS_MEM_STAT);
> > -      return;
> > -    }
> > -
> > -  /* Move VEC_ to the heap.  */
> > -  nelems += v->m_vecpfx.m_num;
> > -  vec<T, va_stack, vl_embed> *oldvec = v;
> > -  v = NULL;
> > -  va_heap::reserve (reinterpret_cast<vec<T, va_heap, vl_embed> *&>(v), nelems,
> > -                   exact PASS_MEM_STAT);
> > -  if (v && oldvec)
> > -    {
> > -      v->m_vecpfx.m_num = oldvec->length ();
> > -      memcpy (v->m_vecdata,
> > -             oldvec->m_vecdata,
> > -             oldvec->length () * sizeof (T));
> > -    }
> > -}
> > -
> > -
> > -/* Free a vector allocated on the stack.  Don't actually free it if we
> > -   find it in the hash table.  */
> > -
> > -template<typename T>
> > -void
> > -va_stack::release (vec<T, va_stack, vl_embed> *&v)
> > -{
> > -  if (v == NULL)
> > -    return;
> > -
> > -  int ix = stack_vec_register_index (static_cast<void *> (v));
> > -  if (ix >= 0)
> > -    {
> > -      unregister_stack_vec (ix);
> > -      v = NULL;
> > -    }
> > -  else
> > -    {
> > -      /* The vector was not on the list of vectors allocated on the stack, so it
> > -        must be allocated on the heap.  */
> > -      va_heap::release (reinterpret_cast<vec<T, va_heap, vl_embed> *&> (v));
> > -    }
> > -}
> > -
> > -
> >  /* Generic vector template.  Default values for A and L indicate the
> >     most commonly used strategies.
> >
> > @@ -597,7 +493,6 @@ public:
> >    friend struct va_gc;
> >    friend struct va_gc_atomic;
> >    friend struct va_heap;
> > -  friend struct va_stack;
> >
> >    /* FIXME - These fields should be private, but we need to cater to
> >              compilers that have stricter notions of PODness for types.  */
> > @@ -1112,6 +1007,7 @@ inline void
> >  vec<T, A, vl_embed>::embedded_init (unsigned alloc, unsigned num)
> >  {
> >    m_vecpfx.m_alloc = alloc;
> > +  m_vecpfx.m_has_auto_buf = 0;
> >    m_vecpfx.m_num = num;
> >  }
> >
> > @@ -1218,8 +1114,8 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
> >     As long as we use C++03, we cannot have constructors nor
> >     destructors in classes that are stored in unions.  */
> >
> > -template<typename T, typename A>
> > -struct vec<T, A, vl_ptr>
> > +template<typename T>
> > +struct vec<T, va_heap, vl_ptr>
> >  {
> >  public:
> >    /* Memory allocation and deallocation for the embedded vector.
> > @@ -1284,23 +1180,39 @@ public:
> >    void qsort (int (*) (const void *, const void *));
> >    unsigned lower_bound (T, bool (*)(const T &, const T &)) const;
> >
> > -  template<typename T1>
> > -  friend void va_stack::alloc (vec<T1, va_stack, vl_ptr>&, unsigned,
> > -                              vec<T1, va_stack, vl_embed> *);
> > +  bool using_auto_storage () const;
> >
> >    /* FIXME - This field should be private, but we need to cater to
> >              compilers that have stricter notions of PODness for types.  */
> > -  vec<T, A, vl_embed> *m_vec;
> > +  vec<T, va_heap, vl_embed> *m_vec;
> >  };
> >
> >
> > -/* Empty specialization for GC allocation.  This will prevent GC
> > -   vectors from using the vl_ptr layout.  FIXME: This is needed to
> > -   circumvent limitations in the GTY machinery.  */
> > -
> > -template<typename T>
> > -struct vec<T, va_gc, vl_ptr>
> > +/* stack_vec is a subclass of vec containing N elements of internal storage.
> > +  You probably only want to allocate this on the stack because if the array
> > +  ends up being larger or much smaller than N it will be wasting space. */
> > +template<typename T, size_t N>
> > +class stack_vec : public vec<T, va_heap>
> >  {
> > +public:
> > +  stack_vec ()
> > +  {
> > +    m_header.m_alloc = N;
> > +    m_header.m_has_auto_buf = 1;
> > +    m_header.m_num = 0;
> > +    this->m_vec = reinterpret_cast<vec<T, va_heap, vl_embed> *> (&m_header);
> > +  }
> > +
> > +  ~stack_vec ()
> > +  {
> > +    this->release ();
> > +  }
> > +
> > +private:
> > +  friend class vec<T, va_heap, vl_ptr>;
> > +
> > +  vec_prefix m_header;
> > +  T m_data[N];
> >  };
> >
> >
> > @@ -1343,45 +1255,6 @@ vec_free (vec<T> *&v)
> >  }
> >
> >
> > -/* Allocate a new stack vector with space for exactly NELEMS objects.
> > -   If NELEMS is zero, NO vector is created.
> > -
> > -   For the stack allocator, no memory is really allocated.  The vector
> > -   is initialized to be at address SPACE and contain NELEMS slots.
> > -   Memory allocation actually occurs in the expansion of VEC_alloc.
> > -
> > -   Usage notes:
> > -
> > -   * This does not allocate an instance of vec<T, A>.  It allocates the
> > -     actual vector of elements (i.e., vec<T, A, vl_embed>) inside a
> > -     vec<T, A> instance.
> > -
> > -   * This allocator must always be a macro:
> > -
> > -     We support a vector which starts out with space on the stack and
> > -     switches to heap space when forced to reallocate.  This works a
> > -     little differently.  In the case of stack vectors, vec_alloc will
> > -     expand to a call to vec_alloc_1 that calls XALLOCAVAR to request
> > -     the initial allocation.  This uses alloca to get the initial
> > -     space. Since alloca can not be usefully called in an inline
> > -     function, vec_alloc must always be a macro.
> > -
> > -     Important limitations of stack vectors:
> > -
> > -     - Only the initial allocation will be made using alloca, so pass
> > -       a reasonable estimate that doesn't use too much stack space;
> > -       don't pass zero.
> > -
> > -     - Don't return a stack-allocated vector from the function which
> > -       allocated it.  */
> > -
> > -#define vec_stack_alloc(T,V,N)                                         \
> > -  do {                                                                 \
> > -    typedef vec<T, va_stack, vl_embed> stackv;                         \
> > -    va_stack::alloc (V, N, XALLOCAVAR (stackv, stackv::embedded_size (N)));\
> > -  } while (0)
> > -
> > -
> >  /* Return iteration condition and update PTR to point to the IX'th
> >     element of this vector.  Use this to iterate over the elements of a
> >     vector as follows,
> > @@ -1389,9 +1262,9 @@ vec_free (vec<T> *&v)
> >       for (ix = 0; v.iterate (ix, &ptr); ix++)
> >         continue;  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline bool
> > -vec<T, A, vl_ptr>::iterate (unsigned ix, T *ptr) const
> > +vec<T, va_heap, vl_ptr>::iterate (unsigned ix, T *ptr) const
> >  {
> >    if (m_vec)
> >      return m_vec->iterate (ix, ptr);
> > @@ -1412,9 +1285,9 @@ vec<T, A, vl_ptr>::iterate (unsigned ix, T *ptr) const
> >
> >     This variant is for vectors of objects.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline bool
> > -vec<T, A, vl_ptr>::iterate (unsigned ix, T **ptr) const
> > +vec<T, va_heap, vl_ptr>::iterate (unsigned ix, T **ptr) const
> >  {
> >    if (m_vec)
> >      return m_vec->iterate (ix, ptr);
> > @@ -1451,11 +1324,11 @@ vec<T, A, vl_ptr>::iterate (unsigned ix, T **ptr) const
> >
> >  /* Return a copy of this vector.  */
> >
> > -template<typename T, typename A>
> > -inline vec<T, A, vl_ptr>
> > -vec<T, A, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
> > +template<typename T>
> > +inline vec<T, va_heap, vl_ptr>
> > +vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
> >  {
> > -  vec<T, A, vl_ptr> new_vec = vNULL;
> > +  vec<T, va_heap, vl_ptr> new_vec = vNULL;
> >    if (length ())
> >      new_vec.m_vec = m_vec->copy ();
> >    return new_vec;
> > @@ -1471,14 +1344,34 @@ vec<T, A, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
> >     Note that this can cause the embedded vector to be reallocated.
> >     Returns true iff reallocation actually occurred.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline bool
> > -vec<T, A, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL)
> > -{
> > -  bool extend = nelems ? !space (nelems) : false;
> > -  if (extend)
> > -    A::reserve (m_vec, nelems, exact PASS_MEM_STAT);
> > -  return extend;
> > +vec<T, va_heap, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL)
> > +{
> > +  if (!nelems || space (nelems))
> > +    return false;
> > +
> > +  /* For now play a game with va_heap::reserve to hide our auto storage if any,
> > +     this is necessary because it doesn't have enough information to know the
> > +     embedded vector is in auto storage, and so should not be freed.  */
> > +  vec<T, va_heap, vl_embed> *oldvec = m_vec;
> > +  unsigned int oldsize = 0;
> > +  bool handle_auto_vec = m_vec && using_auto_storage ();
> > +  if (handle_auto_vec)
> > +    {
> > +      m_vec = NULL;
> > +      oldsize = oldvec->length ();
> > +      nelems += oldsize;
> > +    }
> > +
> > +  va_heap::reserve (m_vec, nelems, exact PASS_MEM_STAT);
> > +  if (handle_auto_vec)
> > +    {
> > +      memcpy (m_vec->address (), oldvec->address (), sizeof (T) * oldsize);
> > +      m_vec->m_vecpfx.m_num = oldsize;
> > +    }
> > +
> > +  return true;
> >  }
> >
> >
> > @@ -1487,9 +1380,9 @@ vec<T, A, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL)
> >     embedded vector to be reallocated.  Returns true iff reallocation
> >     actually occurred.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline bool
> > -vec<T, A, vl_ptr>::reserve_exact (unsigned nelems MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::reserve_exact (unsigned nelems MEM_STAT_DECL)
> >  {
> >    return reserve (nelems, true PASS_MEM_STAT);
> >  }
> > @@ -1500,9 +1393,9 @@ vec<T, A, vl_ptr>::reserve_exact (unsigned nelems MEM_STAT_DECL)
> >     unconditionally allocated from scratch.  The old one, if it
> >     existed, is lost.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::create (unsigned nelems MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::create (unsigned nelems MEM_STAT_DECL)
> >  {
> >    m_vec = NULL;
> >    if (nelems > 0)
> > @@ -1512,23 +1405,30 @@ vec<T, A, vl_ptr>::create (unsigned nelems MEM_STAT_DECL)
> >
> >  /* Free the memory occupied by the embedded vector.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::release (void)
> > +vec<T, va_heap, vl_ptr>::release (void)
> >  {
> > -  if (m_vec)
> > -    A::release (m_vec);
> > -}
> > +  if (!m_vec)
> > +    return;
> >
> > +  if (using_auto_storage ())
> > +    {
> > +      static_cast<stack_vec<T, 1> *> (this)->m_header.m_num = 0;
> > +      return;
> > +    }
> > +
> > +  va_heap::release (m_vec);
> > +}
> >
> >  /* Copy the elements from SRC to the end of this vector as if by memcpy.
> >     SRC and this vector must be allocated with the same memory
> >     allocation mechanism. This vector is assumed to have sufficient
> >     headroom available.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::splice (vec<T, A, vl_ptr> &src)
> > +vec<T, va_heap, vl_ptr>::splice (vec<T, va_heap, vl_ptr> &src)
> >  {
> >    if (src.m_vec)
> >      m_vec->splice (*(src.m_vec));
> > @@ -1540,9 +1440,10 @@ vec<T, A, vl_ptr>::splice (vec<T, A, vl_ptr> &src)
> >     If there is not enough headroom in this vector, it will be reallocated
> >     as needed.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::safe_splice (vec<T, A, vl_ptr> &src MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::safe_splice (vec<T, va_heap, vl_ptr> &src
> > +                                     MEM_STAT_DECL)
> >  {
> >    if (src.length ())
> >      {
> > @@ -1556,9 +1457,9 @@ vec<T, A, vl_ptr>::safe_splice (vec<T, A, vl_ptr> &src MEM_STAT_DECL)
> >     sufficient space in the vector.  Return a pointer to the slot
> >     where OBJ was inserted.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline T *
> > -vec<T, A, vl_ptr>::quick_push (const T &obj)
> > +vec<T, va_heap, vl_ptr>::quick_push (const T &obj)
> >  {
> >    return m_vec->quick_push (obj);
> >  }
> > @@ -1568,9 +1469,9 @@ vec<T, A, vl_ptr>::quick_push (const T &obj)
> >     the embedded vector, if needed.  Return a pointer to the slot where
> >     OBJ was inserted.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline T *
> > -vec<T, A, vl_ptr>::safe_push (const T &obj MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::safe_push (const T &obj MEM_STAT_DECL)
> >  {
> >    reserve (1, false PASS_MEM_STAT);
> >    return quick_push (obj);
> > @@ -1579,9 +1480,9 @@ vec<T, A, vl_ptr>::safe_push (const T &obj MEM_STAT_DECL)
> >
> >  /* Pop and return the last element off the end of the vector.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline T &
> > -vec<T, A, vl_ptr>::pop (void)
> > +vec<T, va_heap, vl_ptr>::pop (void)
> >  {
> >    return m_vec->pop ();
> >  }
> > @@ -1590,9 +1491,9 @@ vec<T, A, vl_ptr>::pop (void)
> >  /* Set the length of the vector to LEN.  The new length must be less
> >     than or equal to the current length.  This is an O(1) operation.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::truncate (unsigned size)
> > +vec<T, va_heap, vl_ptr>::truncate (unsigned size)
> >  {
> >    if (m_vec)
> >      m_vec->truncate (size);
> > @@ -1605,9 +1506,9 @@ vec<T, A, vl_ptr>::truncate (unsigned size)
> >     longer than the current length.  The new elements are
> >     uninitialized.  Reallocate the internal vector, if needed.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::safe_grow (unsigned len MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::safe_grow (unsigned len MEM_STAT_DECL)
> >  {
> >    unsigned oldlen = length ();
> >    gcc_checking_assert (oldlen <= len);
> > @@ -1620,9 +1521,9 @@ vec<T, A, vl_ptr>::safe_grow (unsigned len MEM_STAT_DECL)
> >     long or longer than the current length.  The new elements are
> >     initialized to zero.  Reallocate the internal vector, if needed.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::safe_grow_cleared (unsigned len MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::safe_grow_cleared (unsigned len MEM_STAT_DECL)
> >  {
> >    unsigned oldlen = length ();
> >    safe_grow (len PASS_MEM_STAT);
> > @@ -1633,9 +1534,9 @@ vec<T, A, vl_ptr>::safe_grow_cleared (unsigned len MEM_STAT_DECL)
> >  /* Same as vec::safe_grow but without reallocation of the internal vector.
> >     If the vector cannot be extended, a runtime assertion will be triggered.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::quick_grow (unsigned len)
> > +vec<T, va_heap, vl_ptr>::quick_grow (unsigned len)
> >  {
> >    gcc_checking_assert (m_vec);
> >    m_vec->quick_grow (len);
> > @@ -1646,9 +1547,9 @@ vec<T, A, vl_ptr>::quick_grow (unsigned len)
> >     internal vector. If the vector cannot be extended, a runtime
> >     assertion will be triggered.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::quick_grow_cleared (unsigned len)
> > +vec<T, va_heap, vl_ptr>::quick_grow_cleared (unsigned len)
> >  {
> >    gcc_checking_assert (m_vec);
> >    m_vec->quick_grow_cleared (len);
> > @@ -1658,9 +1559,9 @@ vec<T, A, vl_ptr>::quick_grow_cleared (unsigned len)
> >  /* Insert an element, OBJ, at the IXth position of this vector.  There
> >     must be sufficient space.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::quick_insert (unsigned ix, const T &obj)
> > +vec<T, va_heap, vl_ptr>::quick_insert (unsigned ix, const T &obj)
> >  {
> >    m_vec->quick_insert (ix, obj);
> >  }
> > @@ -1669,9 +1570,9 @@ vec<T, A, vl_ptr>::quick_insert (unsigned ix, const T &obj)
> >  /* Insert an element, OBJ, at the IXth position of the vector.
> >     Reallocate the embedded vector, if necessary.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::safe_insert (unsigned ix, const T &obj MEM_STAT_DECL)
> > +vec<T, va_heap, vl_ptr>::safe_insert (unsigned ix, const T &obj MEM_STAT_DECL)
> >  {
> >    reserve (1, false PASS_MEM_STAT);
> >    quick_insert (ix, obj);
> > @@ -1682,9 +1583,9 @@ vec<T, A, vl_ptr>::safe_insert (unsigned ix, const T &obj MEM_STAT_DECL)
> >     remaining elements is preserved.  This is an O(N) operation due to
> >     a memmove.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::ordered_remove (unsigned ix)
> > +vec<T, va_heap, vl_ptr>::ordered_remove (unsigned ix)
> >  {
> >    m_vec->ordered_remove (ix);
> >  }
> > @@ -1693,9 +1594,9 @@ vec<T, A, vl_ptr>::ordered_remove (unsigned ix)
> >  /* Remove an element from the IXth position of this vector.  Ordering
> >     of remaining elements is destroyed.  This is an O(1) operation.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::unordered_remove (unsigned ix)
> > +vec<T, va_heap, vl_ptr>::unordered_remove (unsigned ix)
> >  {
> >    m_vec->unordered_remove (ix);
> >  }
> > @@ -1704,9 +1605,9 @@ vec<T, A, vl_ptr>::unordered_remove (unsigned ix)
> >  /* Remove LEN elements starting at the IXth.  Ordering is retained.
> >     This is an O(N) operation due to memmove.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::block_remove (unsigned ix, unsigned len)
> > +vec<T, va_heap, vl_ptr>::block_remove (unsigned ix, unsigned len)
> >  {
> >    m_vec->block_remove (ix, len);
> >  }
> > @@ -1715,9 +1616,9 @@ vec<T, A, vl_ptr>::block_remove (unsigned ix, unsigned len)
> >  /* Sort the contents of this vector with qsort.  CMP is the comparison
> >     function to pass to qsort.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline void
> > -vec<T, A, vl_ptr>::qsort (int (*cmp) (const void *, const void *))
> > +vec<T, va_heap, vl_ptr>::qsort (int (*cmp) (const void *, const void *))
> >  {
> >    if (m_vec)
> >      m_vec->qsort (cmp);
> > @@ -1729,14 +1630,27 @@ vec<T, A, vl_ptr>::qsort (int (*cmp) (const void *, const void *))
> >     function that returns true if the first argument is strictly less
> >     than the second.  */
> >
> > -template<typename T, typename A>
> > +template<typename T>
> >  inline unsigned
> > -vec<T, A, vl_ptr>::lower_bound (T obj, bool (*lessthan)(const T &, const T &))
> > +vec<T, va_heap, vl_ptr>::lower_bound (T obj,
> > +                                     bool (*lessthan)(const T &, const T &))
> >      const
> >  {
> >    return m_vec ? m_vec->lower_bound (obj, lessthan) : 0;
> >  }
> >
> > +template<typename T>
> > +inline bool
> > +vec<T, va_heap, vl_ptr>::using_auto_storage () const
> > +{
> > +  if (!m_vec->m_vecpfx.m_has_auto_buf)
> > +    return false;
> > +
> > +  const vec_prefix *auto_header
> > +    = &static_cast<const stack_vec<T, 1> *> (this)->m_header;
> > +  return reinterpret_cast<vec_prefix *> (m_vec) == auto_header;
> > +}
> > +
> >  #if (GCC_VERSION >= 3000)
> >  # pragma GCC poison m_vec m_vecpfx m_vecdata
> >  #endif
> > --
> > 1.8.4.rc3
> >


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]