Patchwork ping [PATCH] rewrite stack vectors]

login
register
mail settings
Submitter Trevor Saunders
Date Oct. 23, 2013, 3:05 p.m.
Message ID <20131023150554.GB15390@tsaunders-iceball.corp.tor1.mozilla.com>
Download mbox | patch
Permalink /patch/285687/
State New
Headers show

Comments

Trevor Saunders - Oct. 23, 2013, 3:05 p.m.
Hi,

ping ;)

Trev

----- Forwarded message from tsaunders@mozilla.com -----

Date: Thu, 10 Oct 2013 14:07:22 -0400
From: tsaunders@mozilla.com
To: dnovillo@google.com, gcc-patches@gcc.gnu.org
Cc: Trevor Saunders <tsaunders@mozilla.com>
Subject: [PATCH] rewrite stack vectors
X-Mailer: git-send-email 1.8.4.rc3

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

Patch

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