This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] rewrite stack vectors
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: tsaunders at mozilla dot com
- Cc: Diego Novillo <dnovillo at google dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 11 Oct 2013 10:08:00 +0200
- Subject: Re: [PATCH] rewrite stack vectors
- Authentication-results: sourceware.org; auth=none
- References: <1381428442-13572-1-git-send-email-tsaunders at mozilla dot com>
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?
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).
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
>