diff mbox series

add move CTOR to auto_vec, use auto_vec for get_loop_exit_edges

Message ID nycvar.YFH.7.76.2008061457560.9963@zhemvz.fhfr.qr
State New
Headers show
Series add move CTOR to auto_vec, use auto_vec for get_loop_exit_edges | expand

Commit Message

Richard Biener Aug. 6, 2020, 12:58 p.m. UTC
This adds a move CTOR to auto_vec<T, 0> and makes use of a
auto_vec<edge> return value for get_loop_exit_edges denoting
that lifetime management of the vector is handed to the caller.

The move CTOR prompted the hash_table change because it appearantly
makes the copy CTOR implicitely deleted (good) and hash-table
expansion of the odr_enum_map which is
hash_map <nofree_string_hash, odr_enum> where odr_enum has an
auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
there's a latent bug there before this (I think we're not
invoking DTORs, but we're invoking copy-CTORs).

Bootstrap / regtest running on x86_64-unknown-linux-gnu.

Does this all look sensible and is it a good change
(the get_loop_exit_edges one)?

Thanks,
Richard.

2020-08-06  Richard Biener  <rguenther@suse.de>

	* vec.h (auto_vec<T, 0>::auto_vec<T, 0> (auto_vec<T, 0> &&):
	New move CTOR.
	* hash-table.h (): Use std::move when expanding.
	* cfgloop.h (get_loop_exit_edges): Return auto_vec<edge>.
	* cfgloop.c (get_loop_exit_edges): Adjust.
---
 gcc/cfgloop.c                |  4 ++--
 gcc/cfgloop.h                |  2 +-
 gcc/cfgloopmanip.c           |  3 +--
 gcc/hash-table.h             |  2 +-
 gcc/ipa-fnsummary.c          |  4 +---
 gcc/ira-build.c              | 12 +++---------
 gcc/ira-color.c              |  4 +---
 gcc/loop-unroll.c            |  3 +--
 gcc/predict.c                |  9 ++-------
 gcc/tree-predcom.c           |  3 +--
 gcc/tree-ssa-loop-ch.c       |  3 +--
 gcc/tree-ssa-loop-im.c       |  3 +--
 gcc/tree-ssa-loop-ivcanon.c  |  9 ++-------
 gcc/tree-ssa-loop-manip.c    |  3 +--
 gcc/tree-ssa-loop-niter.c    | 20 +++++---------------
 gcc/tree-ssa-loop-prefetch.c |  7 ++-----
 gcc/vec.h                    |  6 ++++++
 17 files changed, 32 insertions(+), 65 deletions(-)

Comments

Richard Biener Aug. 6, 2020, 2:15 p.m. UTC | #1
On Thu, 6 Aug 2020, Richard Biener wrote:

> This adds a move CTOR to auto_vec<T, 0> and makes use of a
> auto_vec<edge> return value for get_loop_exit_edges denoting
> that lifetime management of the vector is handed to the caller.
> 
> The move CTOR prompted the hash_table change because it appearantly
> makes the copy CTOR implicitely deleted (good) and hash-table
> expansion of the odr_enum_map which is
> hash_map <nofree_string_hash, odr_enum> where odr_enum has an
> auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
> there's a latent bug there before this (I think we're not
> invoking DTORs, but we're invoking copy-CTORs).
> 
> Bootstrap / regtest running on x86_64-unknown-linux-gnu.
> 
> Does this all look sensible and is it a good change
> (the get_loop_exit_edges one)?

Regtest went OK, here's an update with a complete ChangeLog
(how useful..) plus the move assign operator deleted, copy
assign wouldn't work as auto-generated and at the moment
there's no use of assigning.  I guess if we'd have functions
that take an auto_vec<> argument meaning they will destroy
the vector that will become useful and we can implement it.

OK for trunk?

Thanks,
Richard.


From d74c346e95ff967d930b7c83daabc26b0227aea3 Mon Sep 17 00:00:00 2001
From: Richard Biener <rguenther@suse.de>
Date: Thu, 6 Aug 2020 14:50:56 +0200
Subject: [PATCH] add move CTOR to auto_vec, use auto_vec for
 get_loop_exit_edges

This adds a move CTOR to auto_vec<T, 0> and makes use of a
auto_vec<edge> return value for get_loop_exit_edges denoting
that lifetime management of the vector is handed to the caller.

The move CTOR prompted the hash_table change because it appearantly
makes the copy CTOR implicitely deleted (good) and hash-table
expansion of the odr_enum_map which is
hash_map <nofree_string_hash, odr_enum> where odr_enum has an
auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
there's a latent bug there before this (I think we're not
invoking DTORs, but we're invoking copy-CTORs).

2020-08-06  Richard Biener  <rguenther@suse.de>

	* vec.h (auto_vec<T, 0>::auto_vec (auto_vec &&)): New move CTOR.
	(auto_vec<T, 0>::operator=(auto_vec &&)): Delete.
	* hash-table.h (hash_table::expand): Use std::move when expanding.
	* cfgloop.h (get_loop_exit_edges): Return auto_vec<edge>.
	* cfgloop.c (get_loop_exit_edges): Adjust.
	* cfgloopmanip.c (fix_loop_placement): Likewise.
	* ipa-fnsummary.c (analyze_function_body): Likewise.
	* ira-build.c (create_loop_tree_nodes): Likewise.
	(create_loop_tree_node_allocnos): Likewise.
	(loop_with_complex_edge_p): Likewise.
	* ira-color.c (ira_loop_edge_freq): Likewise.
	* loop-unroll.c (analyze_insns_in_loop): Likewise.
	* predict.c (predict_loops): Likewise.
	* tree-predcom.c (last_always_executed_block): Likewise.
	* tree-ssa-loop-ch.c (ch_base::copy_headers): Likewise.
	* tree-ssa-loop-im.c (store_motion_loop): Likewise.
	* tree-ssa-loop-ivcanon.c (loop_edge_to_cancel): Likewise.
	(canonicalize_loop_induction_variables): Likewise.
	* tree-ssa-loop-manip.c (get_loops_exits): Likewise.
	* tree-ssa-loop-niter.c (find_loop_niter): Likewise.
	(finite_loop_p): Likewise.
	(find_loop_niter_by_eval): Likewise.
	(estimate_numbers_of_iterations): Likewise.
	* tree-ssa-loop-prefetch.c (emit_mfence_after_loop): Likewise.
	(may_use_storent_in_loop_p): Likewise.
---
 gcc/cfgloop.c                |  4 ++--
 gcc/cfgloop.h                |  2 +-
 gcc/cfgloopmanip.c           |  3 +--
 gcc/hash-table.h             |  2 +-
 gcc/ipa-fnsummary.c          |  4 +---
 gcc/ira-build.c              | 12 +++---------
 gcc/ira-color.c              |  4 +---
 gcc/loop-unroll.c            |  3 +--
 gcc/predict.c                |  9 ++-------
 gcc/tree-predcom.c           |  3 +--
 gcc/tree-ssa-loop-ch.c       |  3 +--
 gcc/tree-ssa-loop-im.c       |  3 +--
 gcc/tree-ssa-loop-ivcanon.c  |  9 ++-------
 gcc/tree-ssa-loop-manip.c    |  3 +--
 gcc/tree-ssa-loop-niter.c    | 20 +++++---------------
 gcc/tree-ssa-loop-prefetch.c |  7 ++-----
 gcc/vec.h                    |  7 +++++++
 17 files changed, 33 insertions(+), 65 deletions(-)

diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 7720e6e5d2c..33a26cca6a4 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -1202,10 +1202,10 @@ release_recorded_exits (function *fn)
 
 /* Returns the list of the exit edges of a LOOP.  */
 
-vec<edge> 
+auto_vec<edge>
 get_loop_exit_edges (const class loop *loop, basic_block *body)
 {
-  vec<edge> edges = vNULL;
+  auto_vec<edge> edges;
   edge e;
   unsigned i;
   edge_iterator ei;
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 18b404e292f..f1687f37401 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -383,7 +383,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *,
 extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
 			       int (*) (const void *, const void *, void *));
 
-extern vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
+extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
 extern edge single_exit (const class loop *);
 extern edge single_likely_exit (class loop *loop, vec<edge>);
 extern unsigned num_loop_branches (const class loop *);
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index 73134a20e33..3c9e2a0a99c 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -126,7 +126,7 @@ fix_loop_placement (class loop *loop, bool *irred_invalidated)
 {
   unsigned i;
   edge e;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   class loop *father = current_loops->tree_root, *act;
   bool ret = false;
 
@@ -157,7 +157,6 @@ fix_loop_placement (class loop *loop, bool *irred_invalidated)
       ret = true;
     }
 
-  exits.release ();
   return ret;
 }
 
diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 32f3a634e1e..487003c3acf 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -819,7 +819,7 @@ hash_table<Descriptor, Lazy, Allocator>::expand ()
       if (!is_empty (x) && !is_deleted (x))
         {
           value_type *q = find_empty_slot_for_expand (Descriptor::hash (x));
-	  new ((void*) q) value_type (x);
+	  new ((void*) q) value_type (std::move (x));
         }
 
       p++;
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 59e52927151..f750ec1725c 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -2767,7 +2767,6 @@ analyze_function_body (struct cgraph_node *node, bool early)
       scev_initialize ();
       FOR_EACH_LOOP (loop, 0)
 	{
-	  vec<edge> exits;
 	  edge ex;
 	  unsigned int j;
 	  class tree_niter_desc niter_desc;
@@ -2776,7 +2775,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
 	  else
 	    bb_predicate = false;
 
-	  exits = get_loop_exit_edges (loop);
+	  auto_vec<edge> exits = get_loop_exit_edges (loop);
 	  FOR_EACH_VEC_ELT (exits, j, ex)
 	    if (number_of_iterations_exit (loop, ex, &niter_desc, false)
 		&& !is_gimple_min_invariant (niter_desc.niter))
@@ -2794,7 +2793,6 @@ analyze_function_body (struct cgraph_node *node, bool early)
 		   loop with independent predicate.  */
 		loop_iterations &= will_be_nonconstant;
 	    }
-	  exits.release ();
 	}
 
       /* To avoid quadratic behavior we analyze stride predicates only
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 0bbdb4d0c4b..9b35d0e83a9 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -128,7 +128,6 @@ create_loop_tree_nodes (void)
   bool skip_p;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
   loop_p loop;
 
   ira_bb_nodes
@@ -173,14 +172,13 @@ create_loop_tree_nodes (void)
 	      }
 	  if (skip_p)
 	    continue;
-	  edges = get_loop_exit_edges (loop);
+	  auto_vec<edge> edges = get_loop_exit_edges (loop);
 	  FOR_EACH_VEC_ELT (edges, j, e)
 	    if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
 	      {
 		skip_p = true;
 		break;
 	      }
-	  edges.release ();
 	  if (skip_p)
 	    continue;
 	}
@@ -1964,17 +1962,15 @@ create_loop_tree_node_allocnos (ira_loop_tree_node_t loop_node)
       int i;
       edge_iterator ei;
       edge e;
-      vec<edge> edges;
 
       ira_assert (current_loops != NULL);
       FOR_EACH_EDGE (e, ei, loop_node->loop->header->preds)
 	if (e->src != loop_node->loop->latch)
 	  create_loop_allocnos (e);
 
-      edges = get_loop_exit_edges (loop_node->loop);
+      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
       FOR_EACH_VEC_ELT (edges, i, e)
 	create_loop_allocnos (e);
-      edges.release ();
     }
 }
 
@@ -2167,13 +2163,12 @@ loop_with_complex_edge_p (class loop *loop)
   int i;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
   bool res;
 
   FOR_EACH_EDGE (e, ei, loop->header->preds)
     if (e->flags & EDGE_EH)
       return true;
-  edges = get_loop_exit_edges (loop);
+  auto_vec<edge> edges = get_loop_exit_edges (loop);
   res = false;
   FOR_EACH_VEC_ELT (edges, i, e)
     if (e->flags & EDGE_COMPLEX)
@@ -2181,7 +2176,6 @@ loop_with_complex_edge_p (class loop *loop)
 	res = true;
 	break;
       }
-  edges.release ();
   return res;
 }
 #endif
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index dbb3b7a2a51..d3f8e23faff 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -2539,7 +2539,6 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
   int freq, i;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
 
   ira_assert (current_loops != NULL && loop_node->loop != NULL
 	      && (regno < 0 || regno >= FIRST_PSEUDO_REGISTER));
@@ -2555,13 +2554,12 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
     }
   else
     {
-      edges = get_loop_exit_edges (loop_node->loop);
+      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
       FOR_EACH_VEC_ELT (edges, i, e)
 	if (regno < 0
 	    || (bitmap_bit_p (df_get_live_out (e->src), regno)
 		&& bitmap_bit_p (df_get_live_in (e->dest), regno)))
 	  freq += EDGE_FREQUENCY (e);
-      edges.release ();
     }
 
   return REG_FREQ_FROM_EDGE_FREQ (freq);
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 693c7768868..e1efe624361 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -1580,7 +1580,7 @@ analyze_insns_in_loop (class loop *loop)
   struct var_to_expand *ves = NULL;
   iv_to_split **slot1;
   var_to_expand **slot2;
-  vec<edge> edges = get_loop_exit_edges (loop);
+  auto_vec<edge> edges = get_loop_exit_edges (loop);
   edge exit;
   bool can_apply = false;
 
@@ -1656,7 +1656,6 @@ analyze_insns_in_loop (class loop *loop)
       }
     }
 
-  edges.release ();
   free (body);
   return opt_info;
 }
diff --git a/gcc/predict.c b/gcc/predict.c
index 0a317a7a4ac..a847b9b4045 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -1915,7 +1915,6 @@ predict_loops (void)
     {
       basic_block bb, *bbs;
       unsigned j, n_exits = 0;
-      vec<edge> exits;
       class tree_niter_desc niter_desc;
       edge ex;
       class nb_iter_bound *nb_iter;
@@ -1926,15 +1925,12 @@ predict_loops (void)
       gcond *stmt = NULL;
       bool recursion = with_recursion.contains (loop);
 
-      exits = get_loop_exit_edges (loop);
+      auto_vec<edge> exits = get_loop_exit_edges (loop);
       FOR_EACH_VEC_ELT (exits, j, ex)
 	if (!unlikely_executed_edge_p (ex) && !(ex->flags & EDGE_ABNORMAL_CALL))
 	  n_exits ++;
       if (!n_exits)
-	{
-          exits.release ();
-	  continue;
-	}
+	continue;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "Predicting loop %i%s with %i exits.\n",
@@ -2048,7 +2044,6 @@ predict_loops (void)
 	  probability = RDIV (REG_BR_PROB_BASE, nitercst);
 	  predict_edge (ex, predictor, probability);
 	}
-      exits.release ();
 
       /* Find information about loop bound variables.  */
       for (nb_iter = loop->bounds; nb_iter;
diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
index d2dcfe7f42d..93e6da1e2ab 100644
--- a/gcc/tree-predcom.c
+++ b/gcc/tree-predcom.c
@@ -737,13 +737,12 @@ static basic_block
 last_always_executed_block (class loop *loop)
 {
   unsigned i;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge ex;
   basic_block last = loop->latch;
 
   FOR_EACH_VEC_ELT (exits, i, ex)
     last = nearest_common_dominator (CDI_DOMINATORS, last, ex->src);
-  exits.release ();
 
   return last;
 }
diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c
index b9002d8e294..b86acf7c39d 100644
--- a/gcc/tree-ssa-loop-ch.c
+++ b/gcc/tree-ssa-loop-ch.c
@@ -504,14 +504,13 @@ ch_base::copy_headers (function *fun)
 	{
 	  edge entry = copied[i].first;
 	  loop_p loop = copied[i].second;
-	  vec<edge> exit_edges = get_loop_exit_edges (loop);
+	  auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
 	  bitmap exit_bbs = BITMAP_ALLOC (NULL);
 	  for (unsigned j = 0; j < exit_edges.length (); ++j)
 	    bitmap_set_bit (exit_bbs, exit_edges[j]->dest->index);
 	  bitmap_set_bit (exit_bbs, loop->header->index);
 	  do_rpo_vn (cfun, entry, exit_bbs);
 	  BITMAP_FREE (exit_bbs);
-	  exit_edges.release ();
 	}
     }
   free (bbs);
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 35da1fb26a6..8b7eb57514f 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -2866,7 +2866,7 @@ loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
 static void
 store_motion_loop (class loop *loop, bitmap sm_executed)
 {
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   class loop *subloop;
   bitmap sm_in_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
 
@@ -2876,7 +2876,6 @@ store_motion_loop (class loop *loop, bitmap sm_executed)
       if (!bitmap_empty_p (sm_in_loop))
 	hoist_memory_references (loop, sm_in_loop, exits);
     }
-  exits.release ();
 
   bitmap_ior_into (sm_executed, sm_in_loop);
   for (subloop = loop->inner; subloop != NULL; subloop = subloop->next)
diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
index 298ab215530..5bb781dc7fa 100644
--- a/gcc/tree-ssa-loop-ivcanon.c
+++ b/gcc/tree-ssa-loop-ivcanon.c
@@ -444,7 +444,6 @@ estimated_unrolled_size (struct loop_size *size,
 static edge
 loop_edge_to_cancel (class loop *loop)
 {
-  vec<edge> exits;
   unsigned i;
   edge edge_to_cancel;
   gimple_stmt_iterator gsi;
@@ -453,7 +452,7 @@ loop_edge_to_cancel (class loop *loop)
   if (EDGE_COUNT (loop->latch->preds) > 1)
     return NULL;
 
-  exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
 
   FOR_EACH_VEC_ELT (exits, i, edge_to_cancel)
     {
@@ -477,8 +476,6 @@ loop_edge_to_cancel (class loop *loop)
       if (edge_to_cancel->dest != loop->latch)
         continue;
 
-      exits.release ();
-
       /* Verify that the code in loop latch does nothing that may end program
          execution without really reaching the exit.  This may include
 	 non-pure/const function calls, EH statements, volatile ASMs etc.  */
@@ -487,7 +484,6 @@ loop_edge_to_cancel (class loop *loop)
 	   return NULL;
       return edge_to_cancel;
     }
-  exits.release ();
   return NULL;
 }
 
@@ -1222,10 +1218,9 @@ canonicalize_loop_induction_variables (class loop *loop,
      by find_loop_niter_by_eval.  Be sure to keep it for future.  */
   if (niter && TREE_CODE (niter) == INTEGER_CST)
     {
-      vec<edge> exits = get_loop_exit_edges  (loop);
+      auto_vec<edge> exits = get_loop_exit_edges  (loop);
       record_niter_bound (loop, wi::to_widest (niter),
 			  exit == single_likely_exit (loop, exits), true);
-      exits.release ();
     }
 
   /* Force re-computation of loop bounds so we can remove redundant exits.  */
diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
index a2717a411a3..cdd1ac76833 100644
--- a/gcc/tree-ssa-loop-manip.c
+++ b/gcc/tree-ssa-loop-manip.c
@@ -368,11 +368,10 @@ get_loops_exits (bitmap *loop_exits)
 
   FOR_EACH_LOOP (loop, 0)
     {
-      vec<edge> exit_edges = get_loop_exit_edges (loop);
+      auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
       loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
       FOR_EACH_VEC_ELT (exit_edges, j, e)
         bitmap_set_bit (loop_exits[loop->num], e->dest->index);
-      exit_edges.release ();
     }
 }
 
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 7d61ef080eb..8bb29c2470f 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -2752,7 +2752,7 @@ tree
 find_loop_niter (class loop *loop, edge *exit)
 {
   unsigned i;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge ex;
   tree niter = NULL_TREE, aniter;
   class tree_niter_desc desc;
@@ -2803,7 +2803,6 @@ find_loop_niter (class loop *loop, edge *exit)
 	  continue;
 	}
     }
-  exits.release ();
 
   return niter ? niter : chrec_dont_know;
 }
@@ -2837,21 +2836,18 @@ finite_loop_p (class loop *loop)
   if (loop->finite_p)
     {
       unsigned i;
-      vec<edge> exits = get_loop_exit_edges (loop);
+      auto_vec<edge> exits = get_loop_exit_edges (loop);
       edge ex;
 
       /* If the loop has a normal exit, we can assume it will terminate.  */
       FOR_EACH_VEC_ELT (exits, i, ex)
 	if (!(ex->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_FAKE)))
 	  {
-	    exits.release ();
 	    if (dump_file)
 	      fprintf (dump_file, "Assume loop %i to be finite: it has an exit "
 		       "and -ffinite-loops is on.\n", loop->num);
 	    return true;
 	  }
-
-      exits.release ();
     }
 
   return false;
@@ -3114,7 +3110,7 @@ tree
 find_loop_niter_by_eval (class loop *loop, edge *exit)
 {
   unsigned i;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge ex;
   tree niter = NULL_TREE, aniter;
 
@@ -3123,10 +3119,7 @@ find_loop_niter_by_eval (class loop *loop, edge *exit)
   /* Loops with multiple exits are expensive to handle and less important.  */
   if (!flag_expensive_optimizations
       && exits.length () > 1)
-    {
-      exits.release ();
-      return chrec_dont_know;
-    }
+    return chrec_dont_know;
 
   FOR_EACH_VEC_ELT (exits, i, ex)
     {
@@ -3144,7 +3137,6 @@ find_loop_niter_by_eval (class loop *loop, edge *exit)
       niter = aniter;
       *exit = ex;
     }
-  exits.release ();
 
   return niter ? niter : chrec_dont_know;
 }
@@ -4236,7 +4228,6 @@ get_upper_bound_based_on_builtin_expr_with_prob (gcond *cond)
 void
 estimate_numbers_of_iterations (class loop *loop)
 {
-  vec<edge> exits;
   tree niter, type;
   unsigned i;
   class tree_niter_desc niter_desc;
@@ -4275,7 +4266,7 @@ estimate_numbers_of_iterations (class loop *loop)
   number_of_latch_executions (loop);
 
   basic_block *body = get_loop_body (loop);
-  exits = get_loop_exit_edges (loop, body);
+  auto_vec<edge> exits = get_loop_exit_edges (loop, body);
   likely_exit = single_likely_exit (loop, exits);
   FOR_EACH_VEC_ELT (exits, i, ex)
     {
@@ -4311,7 +4302,6 @@ estimate_numbers_of_iterations (class loop *loop)
 		       true, ex == likely_exit, true);
       record_control_iv (loop, &niter_desc);
     }
-  exits.release ();
 
   if (flag_aggressive_loop_optimizations)
     infer_loop_bounds_from_undefined (loop, body);
diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c
index d19ece6410d..5e94a19c964 100644
--- a/gcc/tree-ssa-loop-prefetch.c
+++ b/gcc/tree-ssa-loop-prefetch.c
@@ -1289,7 +1289,7 @@ mark_nontemporal_store (struct mem_ref *ref)
 static void
 emit_mfence_after_loop (class loop *loop)
 {
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge exit;
   gcall *call;
   gimple_stmt_iterator bsi;
@@ -1309,7 +1309,6 @@ emit_mfence_after_loop (class loop *loop)
       gsi_insert_before (&bsi, call, GSI_NEW_STMT);
     }
 
-  exits.release ();
   update_ssa (TODO_update_ssa_only_virtuals);
 }
 
@@ -1327,7 +1326,7 @@ may_use_storent_in_loop_p (class loop *loop)
      is a suitable place for it at each of the loop exits.  */
   if (FENCE_FOLLOWING_MOVNT != NULL_TREE)
     {
-      vec<edge> exits = get_loop_exit_edges (loop);
+      auto_vec<edge> exits = get_loop_exit_edges (loop);
       unsigned i;
       edge exit;
 
@@ -1335,8 +1334,6 @@ may_use_storent_in_loop_p (class loop *loop)
 	if ((exit->flags & EDGE_ABNORMAL)
 	    && exit->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
 	  ret = false;
-
-      exits.release ();
     }
 
   return ret;
diff --git a/gcc/vec.h b/gcc/vec.h
index 3ad99b83690..4f18116e1b8 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1533,6 +1533,13 @@ public:
   auto_vec () { this->m_vec = NULL; }
   auto_vec (size_t n) { this->create (n); }
   ~auto_vec () { this->release (); }
+
+  auto_vec (auto_vec&& r)
+    {
+      this->m_vec = r.m_vec;
+      r.m_vec = NULL;
+    }
+  void operator= (auto_vec&&) = delete;
 };
Richard Biener Aug. 26, 2020, 12:33 p.m. UTC | #2
On Thu, 6 Aug 2020, Richard Biener wrote:

> On Thu, 6 Aug 2020, Richard Biener wrote:
> 
> > This adds a move CTOR to auto_vec<T, 0> and makes use of a
> > auto_vec<edge> return value for get_loop_exit_edges denoting
> > that lifetime management of the vector is handed to the caller.
> > 
> > The move CTOR prompted the hash_table change because it appearantly
> > makes the copy CTOR implicitely deleted (good) and hash-table
> > expansion of the odr_enum_map which is
> > hash_map <nofree_string_hash, odr_enum> where odr_enum has an
> > auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
> > there's a latent bug there before this (I think we're not
> > invoking DTORs, but we're invoking copy-CTORs).
> > 
> > Bootstrap / regtest running on x86_64-unknown-linux-gnu.
> > 
> > Does this all look sensible and is it a good change
> > (the get_loop_exit_edges one)?
> 
> Regtest went OK, here's an update with a complete ChangeLog
> (how useful..) plus the move assign operator deleted, copy
> assign wouldn't work as auto-generated and at the moment
> there's no use of assigning.  I guess if we'd have functions
> that take an auto_vec<> argument meaning they will destroy
> the vector that will become useful and we can implement it.
> 
> OK for trunk?

Ping.

> Thanks,
> Richard.
> 
> 
> From d74c346e95ff967d930b7c83daabc26b0227aea3 Mon Sep 17 00:00:00 2001
> From: Richard Biener <rguenther@suse.de>
> Date: Thu, 6 Aug 2020 14:50:56 +0200
> Subject: [PATCH] add move CTOR to auto_vec, use auto_vec for
>  get_loop_exit_edges
> 
> This adds a move CTOR to auto_vec<T, 0> and makes use of a
> auto_vec<edge> return value for get_loop_exit_edges denoting
> that lifetime management of the vector is handed to the caller.
> 
> The move CTOR prompted the hash_table change because it appearantly
> makes the copy CTOR implicitely deleted (good) and hash-table
> expansion of the odr_enum_map which is
> hash_map <nofree_string_hash, odr_enum> where odr_enum has an
> auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
> there's a latent bug there before this (I think we're not
> invoking DTORs, but we're invoking copy-CTORs).
> 
> 2020-08-06  Richard Biener  <rguenther@suse.de>
> 
> 	* vec.h (auto_vec<T, 0>::auto_vec (auto_vec &&)): New move CTOR.
> 	(auto_vec<T, 0>::operator=(auto_vec &&)): Delete.
> 	* hash-table.h (hash_table::expand): Use std::move when expanding.
> 	* cfgloop.h (get_loop_exit_edges): Return auto_vec<edge>.
> 	* cfgloop.c (get_loop_exit_edges): Adjust.
> 	* cfgloopmanip.c (fix_loop_placement): Likewise.
> 	* ipa-fnsummary.c (analyze_function_body): Likewise.
> 	* ira-build.c (create_loop_tree_nodes): Likewise.
> 	(create_loop_tree_node_allocnos): Likewise.
> 	(loop_with_complex_edge_p): Likewise.
> 	* ira-color.c (ira_loop_edge_freq): Likewise.
> 	* loop-unroll.c (analyze_insns_in_loop): Likewise.
> 	* predict.c (predict_loops): Likewise.
> 	* tree-predcom.c (last_always_executed_block): Likewise.
> 	* tree-ssa-loop-ch.c (ch_base::copy_headers): Likewise.
> 	* tree-ssa-loop-im.c (store_motion_loop): Likewise.
> 	* tree-ssa-loop-ivcanon.c (loop_edge_to_cancel): Likewise.
> 	(canonicalize_loop_induction_variables): Likewise.
> 	* tree-ssa-loop-manip.c (get_loops_exits): Likewise.
> 	* tree-ssa-loop-niter.c (find_loop_niter): Likewise.
> 	(finite_loop_p): Likewise.
> 	(find_loop_niter_by_eval): Likewise.
> 	(estimate_numbers_of_iterations): Likewise.
> 	* tree-ssa-loop-prefetch.c (emit_mfence_after_loop): Likewise.
> 	(may_use_storent_in_loop_p): Likewise.
> ---
>  gcc/cfgloop.c                |  4 ++--
>  gcc/cfgloop.h                |  2 +-
>  gcc/cfgloopmanip.c           |  3 +--
>  gcc/hash-table.h             |  2 +-
>  gcc/ipa-fnsummary.c          |  4 +---
>  gcc/ira-build.c              | 12 +++---------
>  gcc/ira-color.c              |  4 +---
>  gcc/loop-unroll.c            |  3 +--
>  gcc/predict.c                |  9 ++-------
>  gcc/tree-predcom.c           |  3 +--
>  gcc/tree-ssa-loop-ch.c       |  3 +--
>  gcc/tree-ssa-loop-im.c       |  3 +--
>  gcc/tree-ssa-loop-ivcanon.c  |  9 ++-------
>  gcc/tree-ssa-loop-manip.c    |  3 +--
>  gcc/tree-ssa-loop-niter.c    | 20 +++++---------------
>  gcc/tree-ssa-loop-prefetch.c |  7 ++-----
>  gcc/vec.h                    |  7 +++++++
>  17 files changed, 33 insertions(+), 65 deletions(-)
> 
> diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
> index 7720e6e5d2c..33a26cca6a4 100644
> --- a/gcc/cfgloop.c
> +++ b/gcc/cfgloop.c
> @@ -1202,10 +1202,10 @@ release_recorded_exits (function *fn)
>  
>  /* Returns the list of the exit edges of a LOOP.  */
>  
> -vec<edge> 
> +auto_vec<edge>
>  get_loop_exit_edges (const class loop *loop, basic_block *body)
>  {
> -  vec<edge> edges = vNULL;
> +  auto_vec<edge> edges;
>    edge e;
>    unsigned i;
>    edge_iterator ei;
> diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
> index 18b404e292f..f1687f37401 100644
> --- a/gcc/cfgloop.h
> +++ b/gcc/cfgloop.h
> @@ -383,7 +383,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *,
>  extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
>  			       int (*) (const void *, const void *, void *));
>  
> -extern vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
> +extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
>  extern edge single_exit (const class loop *);
>  extern edge single_likely_exit (class loop *loop, vec<edge>);
>  extern unsigned num_loop_branches (const class loop *);
> diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
> index 73134a20e33..3c9e2a0a99c 100644
> --- a/gcc/cfgloopmanip.c
> +++ b/gcc/cfgloopmanip.c
> @@ -126,7 +126,7 @@ fix_loop_placement (class loop *loop, bool *irred_invalidated)
>  {
>    unsigned i;
>    edge e;
> -  vec<edge> exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>    class loop *father = current_loops->tree_root, *act;
>    bool ret = false;
>  
> @@ -157,7 +157,6 @@ fix_loop_placement (class loop *loop, bool *irred_invalidated)
>        ret = true;
>      }
>  
> -  exits.release ();
>    return ret;
>  }
>  
> diff --git a/gcc/hash-table.h b/gcc/hash-table.h
> index 32f3a634e1e..487003c3acf 100644
> --- a/gcc/hash-table.h
> +++ b/gcc/hash-table.h
> @@ -819,7 +819,7 @@ hash_table<Descriptor, Lazy, Allocator>::expand ()
>        if (!is_empty (x) && !is_deleted (x))
>          {
>            value_type *q = find_empty_slot_for_expand (Descriptor::hash (x));
> -	  new ((void*) q) value_type (x);
> +	  new ((void*) q) value_type (std::move (x));
>          }
>  
>        p++;
> diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> index 59e52927151..f750ec1725c 100644
> --- a/gcc/ipa-fnsummary.c
> +++ b/gcc/ipa-fnsummary.c
> @@ -2767,7 +2767,6 @@ analyze_function_body (struct cgraph_node *node, bool early)
>        scev_initialize ();
>        FOR_EACH_LOOP (loop, 0)
>  	{
> -	  vec<edge> exits;
>  	  edge ex;
>  	  unsigned int j;
>  	  class tree_niter_desc niter_desc;
> @@ -2776,7 +2775,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
>  	  else
>  	    bb_predicate = false;
>  
> -	  exits = get_loop_exit_edges (loop);
> +	  auto_vec<edge> exits = get_loop_exit_edges (loop);
>  	  FOR_EACH_VEC_ELT (exits, j, ex)
>  	    if (number_of_iterations_exit (loop, ex, &niter_desc, false)
>  		&& !is_gimple_min_invariant (niter_desc.niter))
> @@ -2794,7 +2793,6 @@ analyze_function_body (struct cgraph_node *node, bool early)
>  		   loop with independent predicate.  */
>  		loop_iterations &= will_be_nonconstant;
>  	    }
> -	  exits.release ();
>  	}
>  
>        /* To avoid quadratic behavior we analyze stride predicates only
> diff --git a/gcc/ira-build.c b/gcc/ira-build.c
> index 0bbdb4d0c4b..9b35d0e83a9 100644
> --- a/gcc/ira-build.c
> +++ b/gcc/ira-build.c
> @@ -128,7 +128,6 @@ create_loop_tree_nodes (void)
>    bool skip_p;
>    edge_iterator ei;
>    edge e;
> -  vec<edge> edges;
>    loop_p loop;
>  
>    ira_bb_nodes
> @@ -173,14 +172,13 @@ create_loop_tree_nodes (void)
>  	      }
>  	  if (skip_p)
>  	    continue;
> -	  edges = get_loop_exit_edges (loop);
> +	  auto_vec<edge> edges = get_loop_exit_edges (loop);
>  	  FOR_EACH_VEC_ELT (edges, j, e)
>  	    if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
>  	      {
>  		skip_p = true;
>  		break;
>  	      }
> -	  edges.release ();
>  	  if (skip_p)
>  	    continue;
>  	}
> @@ -1964,17 +1962,15 @@ create_loop_tree_node_allocnos (ira_loop_tree_node_t loop_node)
>        int i;
>        edge_iterator ei;
>        edge e;
> -      vec<edge> edges;
>  
>        ira_assert (current_loops != NULL);
>        FOR_EACH_EDGE (e, ei, loop_node->loop->header->preds)
>  	if (e->src != loop_node->loop->latch)
>  	  create_loop_allocnos (e);
>  
> -      edges = get_loop_exit_edges (loop_node->loop);
> +      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
>        FOR_EACH_VEC_ELT (edges, i, e)
>  	create_loop_allocnos (e);
> -      edges.release ();
>      }
>  }
>  
> @@ -2167,13 +2163,12 @@ loop_with_complex_edge_p (class loop *loop)
>    int i;
>    edge_iterator ei;
>    edge e;
> -  vec<edge> edges;
>    bool res;
>  
>    FOR_EACH_EDGE (e, ei, loop->header->preds)
>      if (e->flags & EDGE_EH)
>        return true;
> -  edges = get_loop_exit_edges (loop);
> +  auto_vec<edge> edges = get_loop_exit_edges (loop);
>    res = false;
>    FOR_EACH_VEC_ELT (edges, i, e)
>      if (e->flags & EDGE_COMPLEX)
> @@ -2181,7 +2176,6 @@ loop_with_complex_edge_p (class loop *loop)
>  	res = true;
>  	break;
>        }
> -  edges.release ();
>    return res;
>  }
>  #endif
> diff --git a/gcc/ira-color.c b/gcc/ira-color.c
> index dbb3b7a2a51..d3f8e23faff 100644
> --- a/gcc/ira-color.c
> +++ b/gcc/ira-color.c
> @@ -2539,7 +2539,6 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
>    int freq, i;
>    edge_iterator ei;
>    edge e;
> -  vec<edge> edges;
>  
>    ira_assert (current_loops != NULL && loop_node->loop != NULL
>  	      && (regno < 0 || regno >= FIRST_PSEUDO_REGISTER));
> @@ -2555,13 +2554,12 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
>      }
>    else
>      {
> -      edges = get_loop_exit_edges (loop_node->loop);
> +      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
>        FOR_EACH_VEC_ELT (edges, i, e)
>  	if (regno < 0
>  	    || (bitmap_bit_p (df_get_live_out (e->src), regno)
>  		&& bitmap_bit_p (df_get_live_in (e->dest), regno)))
>  	  freq += EDGE_FREQUENCY (e);
> -      edges.release ();
>      }
>  
>    return REG_FREQ_FROM_EDGE_FREQ (freq);
> diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
> index 693c7768868..e1efe624361 100644
> --- a/gcc/loop-unroll.c
> +++ b/gcc/loop-unroll.c
> @@ -1580,7 +1580,7 @@ analyze_insns_in_loop (class loop *loop)
>    struct var_to_expand *ves = NULL;
>    iv_to_split **slot1;
>    var_to_expand **slot2;
> -  vec<edge> edges = get_loop_exit_edges (loop);
> +  auto_vec<edge> edges = get_loop_exit_edges (loop);
>    edge exit;
>    bool can_apply = false;
>  
> @@ -1656,7 +1656,6 @@ analyze_insns_in_loop (class loop *loop)
>        }
>      }
>  
> -  edges.release ();
>    free (body);
>    return opt_info;
>  }
> diff --git a/gcc/predict.c b/gcc/predict.c
> index 0a317a7a4ac..a847b9b4045 100644
> --- a/gcc/predict.c
> +++ b/gcc/predict.c
> @@ -1915,7 +1915,6 @@ predict_loops (void)
>      {
>        basic_block bb, *bbs;
>        unsigned j, n_exits = 0;
> -      vec<edge> exits;
>        class tree_niter_desc niter_desc;
>        edge ex;
>        class nb_iter_bound *nb_iter;
> @@ -1926,15 +1925,12 @@ predict_loops (void)
>        gcond *stmt = NULL;
>        bool recursion = with_recursion.contains (loop);
>  
> -      exits = get_loop_exit_edges (loop);
> +      auto_vec<edge> exits = get_loop_exit_edges (loop);
>        FOR_EACH_VEC_ELT (exits, j, ex)
>  	if (!unlikely_executed_edge_p (ex) && !(ex->flags & EDGE_ABNORMAL_CALL))
>  	  n_exits ++;
>        if (!n_exits)
> -	{
> -          exits.release ();
> -	  continue;
> -	}
> +	continue;
>  
>        if (dump_file && (dump_flags & TDF_DETAILS))
>  	fprintf (dump_file, "Predicting loop %i%s with %i exits.\n",
> @@ -2048,7 +2044,6 @@ predict_loops (void)
>  	  probability = RDIV (REG_BR_PROB_BASE, nitercst);
>  	  predict_edge (ex, predictor, probability);
>  	}
> -      exits.release ();
>  
>        /* Find information about loop bound variables.  */
>        for (nb_iter = loop->bounds; nb_iter;
> diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
> index d2dcfe7f42d..93e6da1e2ab 100644
> --- a/gcc/tree-predcom.c
> +++ b/gcc/tree-predcom.c
> @@ -737,13 +737,12 @@ static basic_block
>  last_always_executed_block (class loop *loop)
>  {
>    unsigned i;
> -  vec<edge> exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>    edge ex;
>    basic_block last = loop->latch;
>  
>    FOR_EACH_VEC_ELT (exits, i, ex)
>      last = nearest_common_dominator (CDI_DOMINATORS, last, ex->src);
> -  exits.release ();
>  
>    return last;
>  }
> diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c
> index b9002d8e294..b86acf7c39d 100644
> --- a/gcc/tree-ssa-loop-ch.c
> +++ b/gcc/tree-ssa-loop-ch.c
> @@ -504,14 +504,13 @@ ch_base::copy_headers (function *fun)
>  	{
>  	  edge entry = copied[i].first;
>  	  loop_p loop = copied[i].second;
> -	  vec<edge> exit_edges = get_loop_exit_edges (loop);
> +	  auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
>  	  bitmap exit_bbs = BITMAP_ALLOC (NULL);
>  	  for (unsigned j = 0; j < exit_edges.length (); ++j)
>  	    bitmap_set_bit (exit_bbs, exit_edges[j]->dest->index);
>  	  bitmap_set_bit (exit_bbs, loop->header->index);
>  	  do_rpo_vn (cfun, entry, exit_bbs);
>  	  BITMAP_FREE (exit_bbs);
> -	  exit_edges.release ();
>  	}
>      }
>    free (bbs);
> diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
> index 35da1fb26a6..8b7eb57514f 100644
> --- a/gcc/tree-ssa-loop-im.c
> +++ b/gcc/tree-ssa-loop-im.c
> @@ -2866,7 +2866,7 @@ loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
>  static void
>  store_motion_loop (class loop *loop, bitmap sm_executed)
>  {
> -  vec<edge> exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>    class loop *subloop;
>    bitmap sm_in_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
>  
> @@ -2876,7 +2876,6 @@ store_motion_loop (class loop *loop, bitmap sm_executed)
>        if (!bitmap_empty_p (sm_in_loop))
>  	hoist_memory_references (loop, sm_in_loop, exits);
>      }
> -  exits.release ();
>  
>    bitmap_ior_into (sm_executed, sm_in_loop);
>    for (subloop = loop->inner; subloop != NULL; subloop = subloop->next)
> diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
> index 298ab215530..5bb781dc7fa 100644
> --- a/gcc/tree-ssa-loop-ivcanon.c
> +++ b/gcc/tree-ssa-loop-ivcanon.c
> @@ -444,7 +444,6 @@ estimated_unrolled_size (struct loop_size *size,
>  static edge
>  loop_edge_to_cancel (class loop *loop)
>  {
> -  vec<edge> exits;
>    unsigned i;
>    edge edge_to_cancel;
>    gimple_stmt_iterator gsi;
> @@ -453,7 +452,7 @@ loop_edge_to_cancel (class loop *loop)
>    if (EDGE_COUNT (loop->latch->preds) > 1)
>      return NULL;
>  
> -  exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>  
>    FOR_EACH_VEC_ELT (exits, i, edge_to_cancel)
>      {
> @@ -477,8 +476,6 @@ loop_edge_to_cancel (class loop *loop)
>        if (edge_to_cancel->dest != loop->latch)
>          continue;
>  
> -      exits.release ();
> -
>        /* Verify that the code in loop latch does nothing that may end program
>           execution without really reaching the exit.  This may include
>  	 non-pure/const function calls, EH statements, volatile ASMs etc.  */
> @@ -487,7 +484,6 @@ loop_edge_to_cancel (class loop *loop)
>  	   return NULL;
>        return edge_to_cancel;
>      }
> -  exits.release ();
>    return NULL;
>  }
>  
> @@ -1222,10 +1218,9 @@ canonicalize_loop_induction_variables (class loop *loop,
>       by find_loop_niter_by_eval.  Be sure to keep it for future.  */
>    if (niter && TREE_CODE (niter) == INTEGER_CST)
>      {
> -      vec<edge> exits = get_loop_exit_edges  (loop);
> +      auto_vec<edge> exits = get_loop_exit_edges  (loop);
>        record_niter_bound (loop, wi::to_widest (niter),
>  			  exit == single_likely_exit (loop, exits), true);
> -      exits.release ();
>      }
>  
>    /* Force re-computation of loop bounds so we can remove redundant exits.  */
> diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
> index a2717a411a3..cdd1ac76833 100644
> --- a/gcc/tree-ssa-loop-manip.c
> +++ b/gcc/tree-ssa-loop-manip.c
> @@ -368,11 +368,10 @@ get_loops_exits (bitmap *loop_exits)
>  
>    FOR_EACH_LOOP (loop, 0)
>      {
> -      vec<edge> exit_edges = get_loop_exit_edges (loop);
> +      auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
>        loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
>        FOR_EACH_VEC_ELT (exit_edges, j, e)
>          bitmap_set_bit (loop_exits[loop->num], e->dest->index);
> -      exit_edges.release ();
>      }
>  }
>  
> diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> index 7d61ef080eb..8bb29c2470f 100644
> --- a/gcc/tree-ssa-loop-niter.c
> +++ b/gcc/tree-ssa-loop-niter.c
> @@ -2752,7 +2752,7 @@ tree
>  find_loop_niter (class loop *loop, edge *exit)
>  {
>    unsigned i;
> -  vec<edge> exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>    edge ex;
>    tree niter = NULL_TREE, aniter;
>    class tree_niter_desc desc;
> @@ -2803,7 +2803,6 @@ find_loop_niter (class loop *loop, edge *exit)
>  	  continue;
>  	}
>      }
> -  exits.release ();
>  
>    return niter ? niter : chrec_dont_know;
>  }
> @@ -2837,21 +2836,18 @@ finite_loop_p (class loop *loop)
>    if (loop->finite_p)
>      {
>        unsigned i;
> -      vec<edge> exits = get_loop_exit_edges (loop);
> +      auto_vec<edge> exits = get_loop_exit_edges (loop);
>        edge ex;
>  
>        /* If the loop has a normal exit, we can assume it will terminate.  */
>        FOR_EACH_VEC_ELT (exits, i, ex)
>  	if (!(ex->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_FAKE)))
>  	  {
> -	    exits.release ();
>  	    if (dump_file)
>  	      fprintf (dump_file, "Assume loop %i to be finite: it has an exit "
>  		       "and -ffinite-loops is on.\n", loop->num);
>  	    return true;
>  	  }
> -
> -      exits.release ();
>      }
>  
>    return false;
> @@ -3114,7 +3110,7 @@ tree
>  find_loop_niter_by_eval (class loop *loop, edge *exit)
>  {
>    unsigned i;
> -  vec<edge> exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>    edge ex;
>    tree niter = NULL_TREE, aniter;
>  
> @@ -3123,10 +3119,7 @@ find_loop_niter_by_eval (class loop *loop, edge *exit)
>    /* Loops with multiple exits are expensive to handle and less important.  */
>    if (!flag_expensive_optimizations
>        && exits.length () > 1)
> -    {
> -      exits.release ();
> -      return chrec_dont_know;
> -    }
> +    return chrec_dont_know;
>  
>    FOR_EACH_VEC_ELT (exits, i, ex)
>      {
> @@ -3144,7 +3137,6 @@ find_loop_niter_by_eval (class loop *loop, edge *exit)
>        niter = aniter;
>        *exit = ex;
>      }
> -  exits.release ();
>  
>    return niter ? niter : chrec_dont_know;
>  }
> @@ -4236,7 +4228,6 @@ get_upper_bound_based_on_builtin_expr_with_prob (gcond *cond)
>  void
>  estimate_numbers_of_iterations (class loop *loop)
>  {
> -  vec<edge> exits;
>    tree niter, type;
>    unsigned i;
>    class tree_niter_desc niter_desc;
> @@ -4275,7 +4266,7 @@ estimate_numbers_of_iterations (class loop *loop)
>    number_of_latch_executions (loop);
>  
>    basic_block *body = get_loop_body (loop);
> -  exits = get_loop_exit_edges (loop, body);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop, body);
>    likely_exit = single_likely_exit (loop, exits);
>    FOR_EACH_VEC_ELT (exits, i, ex)
>      {
> @@ -4311,7 +4302,6 @@ estimate_numbers_of_iterations (class loop *loop)
>  		       true, ex == likely_exit, true);
>        record_control_iv (loop, &niter_desc);
>      }
> -  exits.release ();
>  
>    if (flag_aggressive_loop_optimizations)
>      infer_loop_bounds_from_undefined (loop, body);
> diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c
> index d19ece6410d..5e94a19c964 100644
> --- a/gcc/tree-ssa-loop-prefetch.c
> +++ b/gcc/tree-ssa-loop-prefetch.c
> @@ -1289,7 +1289,7 @@ mark_nontemporal_store (struct mem_ref *ref)
>  static void
>  emit_mfence_after_loop (class loop *loop)
>  {
> -  vec<edge> exits = get_loop_exit_edges (loop);
> +  auto_vec<edge> exits = get_loop_exit_edges (loop);
>    edge exit;
>    gcall *call;
>    gimple_stmt_iterator bsi;
> @@ -1309,7 +1309,6 @@ emit_mfence_after_loop (class loop *loop)
>        gsi_insert_before (&bsi, call, GSI_NEW_STMT);
>      }
>  
> -  exits.release ();
>    update_ssa (TODO_update_ssa_only_virtuals);
>  }
>  
> @@ -1327,7 +1326,7 @@ may_use_storent_in_loop_p (class loop *loop)
>       is a suitable place for it at each of the loop exits.  */
>    if (FENCE_FOLLOWING_MOVNT != NULL_TREE)
>      {
> -      vec<edge> exits = get_loop_exit_edges (loop);
> +      auto_vec<edge> exits = get_loop_exit_edges (loop);
>        unsigned i;
>        edge exit;
>  
> @@ -1335,8 +1334,6 @@ may_use_storent_in_loop_p (class loop *loop)
>  	if ((exit->flags & EDGE_ABNORMAL)
>  	    && exit->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
>  	  ret = false;
> -
> -      exits.release ();
>      }
>  
>    return ret;
> diff --git a/gcc/vec.h b/gcc/vec.h
> index 3ad99b83690..4f18116e1b8 100644
> --- a/gcc/vec.h
> +++ b/gcc/vec.h
> @@ -1533,6 +1533,13 @@ public:
>    auto_vec () { this->m_vec = NULL; }
>    auto_vec (size_t n) { this->create (n); }
>    ~auto_vec () { this->release (); }
> +
> +  auto_vec (auto_vec&& r)
> +    {
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +    }
> +  void operator= (auto_vec&&) = delete;
>  };
>  
>  
>
Richard Biener Sept. 24, 2020, 9:11 a.m. UTC | #3
On Wed, 26 Aug 2020, Richard Biener wrote:

> On Thu, 6 Aug 2020, Richard Biener wrote:
> 
> > On Thu, 6 Aug 2020, Richard Biener wrote:
> > 
> > > This adds a move CTOR to auto_vec<T, 0> and makes use of a
> > > auto_vec<edge> return value for get_loop_exit_edges denoting
> > > that lifetime management of the vector is handed to the caller.
> > > 
> > > The move CTOR prompted the hash_table change because it appearantly
> > > makes the copy CTOR implicitely deleted (good) and hash-table
> > > expansion of the odr_enum_map which is
> > > hash_map <nofree_string_hash, odr_enum> where odr_enum has an
> > > auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
> > > there's a latent bug there before this (I think we're not
> > > invoking DTORs, but we're invoking copy-CTORs).
> > > 
> > > Bootstrap / regtest running on x86_64-unknown-linux-gnu.
> > > 
> > > Does this all look sensible and is it a good change
> > > (the get_loop_exit_edges one)?
> > 
> > Regtest went OK, here's an update with a complete ChangeLog
> > (how useful..) plus the move assign operator deleted, copy
> > assign wouldn't work as auto-generated and at the moment
> > there's no use of assigning.  I guess if we'd have functions
> > that take an auto_vec<> argument meaning they will destroy
> > the vector that will become useful and we can implement it.
> > 
> > OK for trunk?
> 
> Ping.

Ping^2.

Thanks,
Richard.

> > Thanks,
> > Richard.
> > 
> > 
> > From d74c346e95ff967d930b7c83daabc26b0227aea3 Mon Sep 17 00:00:00 2001
> > From: Richard Biener <rguenther@suse.de>
> > Date: Thu, 6 Aug 2020 14:50:56 +0200
> > Subject: [PATCH] add move CTOR to auto_vec, use auto_vec for
> >  get_loop_exit_edges
> > 
> > This adds a move CTOR to auto_vec<T, 0> and makes use of a
> > auto_vec<edge> return value for get_loop_exit_edges denoting
> > that lifetime management of the vector is handed to the caller.
> > 
> > The move CTOR prompted the hash_table change because it appearantly
> > makes the copy CTOR implicitely deleted (good) and hash-table
> > expansion of the odr_enum_map which is
> > hash_map <nofree_string_hash, odr_enum> where odr_enum has an
> > auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
> > there's a latent bug there before this (I think we're not
> > invoking DTORs, but we're invoking copy-CTORs).
> > 
> > 2020-08-06  Richard Biener  <rguenther@suse.de>
> > 
> > 	* vec.h (auto_vec<T, 0>::auto_vec (auto_vec &&)): New move CTOR.
> > 	(auto_vec<T, 0>::operator=(auto_vec &&)): Delete.
> > 	* hash-table.h (hash_table::expand): Use std::move when expanding.
> > 	* cfgloop.h (get_loop_exit_edges): Return auto_vec<edge>.
> > 	* cfgloop.c (get_loop_exit_edges): Adjust.
> > 	* cfgloopmanip.c (fix_loop_placement): Likewise.
> > 	* ipa-fnsummary.c (analyze_function_body): Likewise.
> > 	* ira-build.c (create_loop_tree_nodes): Likewise.
> > 	(create_loop_tree_node_allocnos): Likewise.
> > 	(loop_with_complex_edge_p): Likewise.
> > 	* ira-color.c (ira_loop_edge_freq): Likewise.
> > 	* loop-unroll.c (analyze_insns_in_loop): Likewise.
> > 	* predict.c (predict_loops): Likewise.
> > 	* tree-predcom.c (last_always_executed_block): Likewise.
> > 	* tree-ssa-loop-ch.c (ch_base::copy_headers): Likewise.
> > 	* tree-ssa-loop-im.c (store_motion_loop): Likewise.
> > 	* tree-ssa-loop-ivcanon.c (loop_edge_to_cancel): Likewise.
> > 	(canonicalize_loop_induction_variables): Likewise.
> > 	* tree-ssa-loop-manip.c (get_loops_exits): Likewise.
> > 	* tree-ssa-loop-niter.c (find_loop_niter): Likewise.
> > 	(finite_loop_p): Likewise.
> > 	(find_loop_niter_by_eval): Likewise.
> > 	(estimate_numbers_of_iterations): Likewise.
> > 	* tree-ssa-loop-prefetch.c (emit_mfence_after_loop): Likewise.
> > 	(may_use_storent_in_loop_p): Likewise.
> > ---
> >  gcc/cfgloop.c                |  4 ++--
> >  gcc/cfgloop.h                |  2 +-
> >  gcc/cfgloopmanip.c           |  3 +--
> >  gcc/hash-table.h             |  2 +-
> >  gcc/ipa-fnsummary.c          |  4 +---
> >  gcc/ira-build.c              | 12 +++---------
> >  gcc/ira-color.c              |  4 +---
> >  gcc/loop-unroll.c            |  3 +--
> >  gcc/predict.c                |  9 ++-------
> >  gcc/tree-predcom.c           |  3 +--
> >  gcc/tree-ssa-loop-ch.c       |  3 +--
> >  gcc/tree-ssa-loop-im.c       |  3 +--
> >  gcc/tree-ssa-loop-ivcanon.c  |  9 ++-------
> >  gcc/tree-ssa-loop-manip.c    |  3 +--
> >  gcc/tree-ssa-loop-niter.c    | 20 +++++---------------
> >  gcc/tree-ssa-loop-prefetch.c |  7 ++-----
> >  gcc/vec.h                    |  7 +++++++
> >  17 files changed, 33 insertions(+), 65 deletions(-)
> > 
> > diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
> > index 7720e6e5d2c..33a26cca6a4 100644
> > --- a/gcc/cfgloop.c
> > +++ b/gcc/cfgloop.c
> > @@ -1202,10 +1202,10 @@ release_recorded_exits (function *fn)
> >  
> >  /* Returns the list of the exit edges of a LOOP.  */
> >  
> > -vec<edge> 
> > +auto_vec<edge>
> >  get_loop_exit_edges (const class loop *loop, basic_block *body)
> >  {
> > -  vec<edge> edges = vNULL;
> > +  auto_vec<edge> edges;
> >    edge e;
> >    unsigned i;
> >    edge_iterator ei;
> > diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
> > index 18b404e292f..f1687f37401 100644
> > --- a/gcc/cfgloop.h
> > +++ b/gcc/cfgloop.h
> > @@ -383,7 +383,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *,
> >  extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
> >  			       int (*) (const void *, const void *, void *));
> >  
> > -extern vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
> > +extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
> >  extern edge single_exit (const class loop *);
> >  extern edge single_likely_exit (class loop *loop, vec<edge>);
> >  extern unsigned num_loop_branches (const class loop *);
> > diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
> > index 73134a20e33..3c9e2a0a99c 100644
> > --- a/gcc/cfgloopmanip.c
> > +++ b/gcc/cfgloopmanip.c
> > @@ -126,7 +126,7 @@ fix_loop_placement (class loop *loop, bool *irred_invalidated)
> >  {
> >    unsigned i;
> >    edge e;
> > -  vec<edge> exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >    class loop *father = current_loops->tree_root, *act;
> >    bool ret = false;
> >  
> > @@ -157,7 +157,6 @@ fix_loop_placement (class loop *loop, bool *irred_invalidated)
> >        ret = true;
> >      }
> >  
> > -  exits.release ();
> >    return ret;
> >  }
> >  
> > diff --git a/gcc/hash-table.h b/gcc/hash-table.h
> > index 32f3a634e1e..487003c3acf 100644
> > --- a/gcc/hash-table.h
> > +++ b/gcc/hash-table.h
> > @@ -819,7 +819,7 @@ hash_table<Descriptor, Lazy, Allocator>::expand ()
> >        if (!is_empty (x) && !is_deleted (x))
> >          {
> >            value_type *q = find_empty_slot_for_expand (Descriptor::hash (x));
> > -	  new ((void*) q) value_type (x);
> > +	  new ((void*) q) value_type (std::move (x));
> >          }
> >  
> >        p++;
> > diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> > index 59e52927151..f750ec1725c 100644
> > --- a/gcc/ipa-fnsummary.c
> > +++ b/gcc/ipa-fnsummary.c
> > @@ -2767,7 +2767,6 @@ analyze_function_body (struct cgraph_node *node, bool early)
> >        scev_initialize ();
> >        FOR_EACH_LOOP (loop, 0)
> >  	{
> > -	  vec<edge> exits;
> >  	  edge ex;
> >  	  unsigned int j;
> >  	  class tree_niter_desc niter_desc;
> > @@ -2776,7 +2775,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
> >  	  else
> >  	    bb_predicate = false;
> >  
> > -	  exits = get_loop_exit_edges (loop);
> > +	  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >  	  FOR_EACH_VEC_ELT (exits, j, ex)
> >  	    if (number_of_iterations_exit (loop, ex, &niter_desc, false)
> >  		&& !is_gimple_min_invariant (niter_desc.niter))
> > @@ -2794,7 +2793,6 @@ analyze_function_body (struct cgraph_node *node, bool early)
> >  		   loop with independent predicate.  */
> >  		loop_iterations &= will_be_nonconstant;
> >  	    }
> > -	  exits.release ();
> >  	}
> >  
> >        /* To avoid quadratic behavior we analyze stride predicates only
> > diff --git a/gcc/ira-build.c b/gcc/ira-build.c
> > index 0bbdb4d0c4b..9b35d0e83a9 100644
> > --- a/gcc/ira-build.c
> > +++ b/gcc/ira-build.c
> > @@ -128,7 +128,6 @@ create_loop_tree_nodes (void)
> >    bool skip_p;
> >    edge_iterator ei;
> >    edge e;
> > -  vec<edge> edges;
> >    loop_p loop;
> >  
> >    ira_bb_nodes
> > @@ -173,14 +172,13 @@ create_loop_tree_nodes (void)
> >  	      }
> >  	  if (skip_p)
> >  	    continue;
> > -	  edges = get_loop_exit_edges (loop);
> > +	  auto_vec<edge> edges = get_loop_exit_edges (loop);
> >  	  FOR_EACH_VEC_ELT (edges, j, e)
> >  	    if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
> >  	      {
> >  		skip_p = true;
> >  		break;
> >  	      }
> > -	  edges.release ();
> >  	  if (skip_p)
> >  	    continue;
> >  	}
> > @@ -1964,17 +1962,15 @@ create_loop_tree_node_allocnos (ira_loop_tree_node_t loop_node)
> >        int i;
> >        edge_iterator ei;
> >        edge e;
> > -      vec<edge> edges;
> >  
> >        ira_assert (current_loops != NULL);
> >        FOR_EACH_EDGE (e, ei, loop_node->loop->header->preds)
> >  	if (e->src != loop_node->loop->latch)
> >  	  create_loop_allocnos (e);
> >  
> > -      edges = get_loop_exit_edges (loop_node->loop);
> > +      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
> >        FOR_EACH_VEC_ELT (edges, i, e)
> >  	create_loop_allocnos (e);
> > -      edges.release ();
> >      }
> >  }
> >  
> > @@ -2167,13 +2163,12 @@ loop_with_complex_edge_p (class loop *loop)
> >    int i;
> >    edge_iterator ei;
> >    edge e;
> > -  vec<edge> edges;
> >    bool res;
> >  
> >    FOR_EACH_EDGE (e, ei, loop->header->preds)
> >      if (e->flags & EDGE_EH)
> >        return true;
> > -  edges = get_loop_exit_edges (loop);
> > +  auto_vec<edge> edges = get_loop_exit_edges (loop);
> >    res = false;
> >    FOR_EACH_VEC_ELT (edges, i, e)
> >      if (e->flags & EDGE_COMPLEX)
> > @@ -2181,7 +2176,6 @@ loop_with_complex_edge_p (class loop *loop)
> >  	res = true;
> >  	break;
> >        }
> > -  edges.release ();
> >    return res;
> >  }
> >  #endif
> > diff --git a/gcc/ira-color.c b/gcc/ira-color.c
> > index dbb3b7a2a51..d3f8e23faff 100644
> > --- a/gcc/ira-color.c
> > +++ b/gcc/ira-color.c
> > @@ -2539,7 +2539,6 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
> >    int freq, i;
> >    edge_iterator ei;
> >    edge e;
> > -  vec<edge> edges;
> >  
> >    ira_assert (current_loops != NULL && loop_node->loop != NULL
> >  	      && (regno < 0 || regno >= FIRST_PSEUDO_REGISTER));
> > @@ -2555,13 +2554,12 @@ ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
> >      }
> >    else
> >      {
> > -      edges = get_loop_exit_edges (loop_node->loop);
> > +      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
> >        FOR_EACH_VEC_ELT (edges, i, e)
> >  	if (regno < 0
> >  	    || (bitmap_bit_p (df_get_live_out (e->src), regno)
> >  		&& bitmap_bit_p (df_get_live_in (e->dest), regno)))
> >  	  freq += EDGE_FREQUENCY (e);
> > -      edges.release ();
> >      }
> >  
> >    return REG_FREQ_FROM_EDGE_FREQ (freq);
> > diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
> > index 693c7768868..e1efe624361 100644
> > --- a/gcc/loop-unroll.c
> > +++ b/gcc/loop-unroll.c
> > @@ -1580,7 +1580,7 @@ analyze_insns_in_loop (class loop *loop)
> >    struct var_to_expand *ves = NULL;
> >    iv_to_split **slot1;
> >    var_to_expand **slot2;
> > -  vec<edge> edges = get_loop_exit_edges (loop);
> > +  auto_vec<edge> edges = get_loop_exit_edges (loop);
> >    edge exit;
> >    bool can_apply = false;
> >  
> > @@ -1656,7 +1656,6 @@ analyze_insns_in_loop (class loop *loop)
> >        }
> >      }
> >  
> > -  edges.release ();
> >    free (body);
> >    return opt_info;
> >  }
> > diff --git a/gcc/predict.c b/gcc/predict.c
> > index 0a317a7a4ac..a847b9b4045 100644
> > --- a/gcc/predict.c
> > +++ b/gcc/predict.c
> > @@ -1915,7 +1915,6 @@ predict_loops (void)
> >      {
> >        basic_block bb, *bbs;
> >        unsigned j, n_exits = 0;
> > -      vec<edge> exits;
> >        class tree_niter_desc niter_desc;
> >        edge ex;
> >        class nb_iter_bound *nb_iter;
> > @@ -1926,15 +1925,12 @@ predict_loops (void)
> >        gcond *stmt = NULL;
> >        bool recursion = with_recursion.contains (loop);
> >  
> > -      exits = get_loop_exit_edges (loop);
> > +      auto_vec<edge> exits = get_loop_exit_edges (loop);
> >        FOR_EACH_VEC_ELT (exits, j, ex)
> >  	if (!unlikely_executed_edge_p (ex) && !(ex->flags & EDGE_ABNORMAL_CALL))
> >  	  n_exits ++;
> >        if (!n_exits)
> > -	{
> > -          exits.release ();
> > -	  continue;
> > -	}
> > +	continue;
> >  
> >        if (dump_file && (dump_flags & TDF_DETAILS))
> >  	fprintf (dump_file, "Predicting loop %i%s with %i exits.\n",
> > @@ -2048,7 +2044,6 @@ predict_loops (void)
> >  	  probability = RDIV (REG_BR_PROB_BASE, nitercst);
> >  	  predict_edge (ex, predictor, probability);
> >  	}
> > -      exits.release ();
> >  
> >        /* Find information about loop bound variables.  */
> >        for (nb_iter = loop->bounds; nb_iter;
> > diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
> > index d2dcfe7f42d..93e6da1e2ab 100644
> > --- a/gcc/tree-predcom.c
> > +++ b/gcc/tree-predcom.c
> > @@ -737,13 +737,12 @@ static basic_block
> >  last_always_executed_block (class loop *loop)
> >  {
> >    unsigned i;
> > -  vec<edge> exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >    edge ex;
> >    basic_block last = loop->latch;
> >  
> >    FOR_EACH_VEC_ELT (exits, i, ex)
> >      last = nearest_common_dominator (CDI_DOMINATORS, last, ex->src);
> > -  exits.release ();
> >  
> >    return last;
> >  }
> > diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c
> > index b9002d8e294..b86acf7c39d 100644
> > --- a/gcc/tree-ssa-loop-ch.c
> > +++ b/gcc/tree-ssa-loop-ch.c
> > @@ -504,14 +504,13 @@ ch_base::copy_headers (function *fun)
> >  	{
> >  	  edge entry = copied[i].first;
> >  	  loop_p loop = copied[i].second;
> > -	  vec<edge> exit_edges = get_loop_exit_edges (loop);
> > +	  auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
> >  	  bitmap exit_bbs = BITMAP_ALLOC (NULL);
> >  	  for (unsigned j = 0; j < exit_edges.length (); ++j)
> >  	    bitmap_set_bit (exit_bbs, exit_edges[j]->dest->index);
> >  	  bitmap_set_bit (exit_bbs, loop->header->index);
> >  	  do_rpo_vn (cfun, entry, exit_bbs);
> >  	  BITMAP_FREE (exit_bbs);
> > -	  exit_edges.release ();
> >  	}
> >      }
> >    free (bbs);
> > diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
> > index 35da1fb26a6..8b7eb57514f 100644
> > --- a/gcc/tree-ssa-loop-im.c
> > +++ b/gcc/tree-ssa-loop-im.c
> > @@ -2866,7 +2866,7 @@ loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
> >  static void
> >  store_motion_loop (class loop *loop, bitmap sm_executed)
> >  {
> > -  vec<edge> exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >    class loop *subloop;
> >    bitmap sm_in_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
> >  
> > @@ -2876,7 +2876,6 @@ store_motion_loop (class loop *loop, bitmap sm_executed)
> >        if (!bitmap_empty_p (sm_in_loop))
> >  	hoist_memory_references (loop, sm_in_loop, exits);
> >      }
> > -  exits.release ();
> >  
> >    bitmap_ior_into (sm_executed, sm_in_loop);
> >    for (subloop = loop->inner; subloop != NULL; subloop = subloop->next)
> > diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
> > index 298ab215530..5bb781dc7fa 100644
> > --- a/gcc/tree-ssa-loop-ivcanon.c
> > +++ b/gcc/tree-ssa-loop-ivcanon.c
> > @@ -444,7 +444,6 @@ estimated_unrolled_size (struct loop_size *size,
> >  static edge
> >  loop_edge_to_cancel (class loop *loop)
> >  {
> > -  vec<edge> exits;
> >    unsigned i;
> >    edge edge_to_cancel;
> >    gimple_stmt_iterator gsi;
> > @@ -453,7 +452,7 @@ loop_edge_to_cancel (class loop *loop)
> >    if (EDGE_COUNT (loop->latch->preds) > 1)
> >      return NULL;
> >  
> > -  exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >  
> >    FOR_EACH_VEC_ELT (exits, i, edge_to_cancel)
> >      {
> > @@ -477,8 +476,6 @@ loop_edge_to_cancel (class loop *loop)
> >        if (edge_to_cancel->dest != loop->latch)
> >          continue;
> >  
> > -      exits.release ();
> > -
> >        /* Verify that the code in loop latch does nothing that may end program
> >           execution without really reaching the exit.  This may include
> >  	 non-pure/const function calls, EH statements, volatile ASMs etc.  */
> > @@ -487,7 +484,6 @@ loop_edge_to_cancel (class loop *loop)
> >  	   return NULL;
> >        return edge_to_cancel;
> >      }
> > -  exits.release ();
> >    return NULL;
> >  }
> >  
> > @@ -1222,10 +1218,9 @@ canonicalize_loop_induction_variables (class loop *loop,
> >       by find_loop_niter_by_eval.  Be sure to keep it for future.  */
> >    if (niter && TREE_CODE (niter) == INTEGER_CST)
> >      {
> > -      vec<edge> exits = get_loop_exit_edges  (loop);
> > +      auto_vec<edge> exits = get_loop_exit_edges  (loop);
> >        record_niter_bound (loop, wi::to_widest (niter),
> >  			  exit == single_likely_exit (loop, exits), true);
> > -      exits.release ();
> >      }
> >  
> >    /* Force re-computation of loop bounds so we can remove redundant exits.  */
> > diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
> > index a2717a411a3..cdd1ac76833 100644
> > --- a/gcc/tree-ssa-loop-manip.c
> > +++ b/gcc/tree-ssa-loop-manip.c
> > @@ -368,11 +368,10 @@ get_loops_exits (bitmap *loop_exits)
> >  
> >    FOR_EACH_LOOP (loop, 0)
> >      {
> > -      vec<edge> exit_edges = get_loop_exit_edges (loop);
> > +      auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
> >        loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
> >        FOR_EACH_VEC_ELT (exit_edges, j, e)
> >          bitmap_set_bit (loop_exits[loop->num], e->dest->index);
> > -      exit_edges.release ();
> >      }
> >  }
> >  
> > diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> > index 7d61ef080eb..8bb29c2470f 100644
> > --- a/gcc/tree-ssa-loop-niter.c
> > +++ b/gcc/tree-ssa-loop-niter.c
> > @@ -2752,7 +2752,7 @@ tree
> >  find_loop_niter (class loop *loop, edge *exit)
> >  {
> >    unsigned i;
> > -  vec<edge> exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >    edge ex;
> >    tree niter = NULL_TREE, aniter;
> >    class tree_niter_desc desc;
> > @@ -2803,7 +2803,6 @@ find_loop_niter (class loop *loop, edge *exit)
> >  	  continue;
> >  	}
> >      }
> > -  exits.release ();
> >  
> >    return niter ? niter : chrec_dont_know;
> >  }
> > @@ -2837,21 +2836,18 @@ finite_loop_p (class loop *loop)
> >    if (loop->finite_p)
> >      {
> >        unsigned i;
> > -      vec<edge> exits = get_loop_exit_edges (loop);
> > +      auto_vec<edge> exits = get_loop_exit_edges (loop);
> >        edge ex;
> >  
> >        /* If the loop has a normal exit, we can assume it will terminate.  */
> >        FOR_EACH_VEC_ELT (exits, i, ex)
> >  	if (!(ex->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_FAKE)))
> >  	  {
> > -	    exits.release ();
> >  	    if (dump_file)
> >  	      fprintf (dump_file, "Assume loop %i to be finite: it has an exit "
> >  		       "and -ffinite-loops is on.\n", loop->num);
> >  	    return true;
> >  	  }
> > -
> > -      exits.release ();
> >      }
> >  
> >    return false;
> > @@ -3114,7 +3110,7 @@ tree
> >  find_loop_niter_by_eval (class loop *loop, edge *exit)
> >  {
> >    unsigned i;
> > -  vec<edge> exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >    edge ex;
> >    tree niter = NULL_TREE, aniter;
> >  
> > @@ -3123,10 +3119,7 @@ find_loop_niter_by_eval (class loop *loop, edge *exit)
> >    /* Loops with multiple exits are expensive to handle and less important.  */
> >    if (!flag_expensive_optimizations
> >        && exits.length () > 1)
> > -    {
> > -      exits.release ();
> > -      return chrec_dont_know;
> > -    }
> > +    return chrec_dont_know;
> >  
> >    FOR_EACH_VEC_ELT (exits, i, ex)
> >      {
> > @@ -3144,7 +3137,6 @@ find_loop_niter_by_eval (class loop *loop, edge *exit)
> >        niter = aniter;
> >        *exit = ex;
> >      }
> > -  exits.release ();
> >  
> >    return niter ? niter : chrec_dont_know;
> >  }
> > @@ -4236,7 +4228,6 @@ get_upper_bound_based_on_builtin_expr_with_prob (gcond *cond)
> >  void
> >  estimate_numbers_of_iterations (class loop *loop)
> >  {
> > -  vec<edge> exits;
> >    tree niter, type;
> >    unsigned i;
> >    class tree_niter_desc niter_desc;
> > @@ -4275,7 +4266,7 @@ estimate_numbers_of_iterations (class loop *loop)
> >    number_of_latch_executions (loop);
> >  
> >    basic_block *body = get_loop_body (loop);
> > -  exits = get_loop_exit_edges (loop, body);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop, body);
> >    likely_exit = single_likely_exit (loop, exits);
> >    FOR_EACH_VEC_ELT (exits, i, ex)
> >      {
> > @@ -4311,7 +4302,6 @@ estimate_numbers_of_iterations (class loop *loop)
> >  		       true, ex == likely_exit, true);
> >        record_control_iv (loop, &niter_desc);
> >      }
> > -  exits.release ();
> >  
> >    if (flag_aggressive_loop_optimizations)
> >      infer_loop_bounds_from_undefined (loop, body);
> > diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c
> > index d19ece6410d..5e94a19c964 100644
> > --- a/gcc/tree-ssa-loop-prefetch.c
> > +++ b/gcc/tree-ssa-loop-prefetch.c
> > @@ -1289,7 +1289,7 @@ mark_nontemporal_store (struct mem_ref *ref)
> >  static void
> >  emit_mfence_after_loop (class loop *loop)
> >  {
> > -  vec<edge> exits = get_loop_exit_edges (loop);
> > +  auto_vec<edge> exits = get_loop_exit_edges (loop);
> >    edge exit;
> >    gcall *call;
> >    gimple_stmt_iterator bsi;
> > @@ -1309,7 +1309,6 @@ emit_mfence_after_loop (class loop *loop)
> >        gsi_insert_before (&bsi, call, GSI_NEW_STMT);
> >      }
> >  
> > -  exits.release ();
> >    update_ssa (TODO_update_ssa_only_virtuals);
> >  }
> >  
> > @@ -1327,7 +1326,7 @@ may_use_storent_in_loop_p (class loop *loop)
> >       is a suitable place for it at each of the loop exits.  */
> >    if (FENCE_FOLLOWING_MOVNT != NULL_TREE)
> >      {
> > -      vec<edge> exits = get_loop_exit_edges (loop);
> > +      auto_vec<edge> exits = get_loop_exit_edges (loop);
> >        unsigned i;
> >        edge exit;
> >  
> > @@ -1335,8 +1334,6 @@ may_use_storent_in_loop_p (class loop *loop)
> >  	if ((exit->flags & EDGE_ABNORMAL)
> >  	    && exit->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
> >  	  ret = false;
> > -
> > -      exits.release ();
> >      }
> >  
> >    return ret;
> > diff --git a/gcc/vec.h b/gcc/vec.h
> > index 3ad99b83690..4f18116e1b8 100644
> > --- a/gcc/vec.h
> > +++ b/gcc/vec.h
> > @@ -1533,6 +1533,13 @@ public:
> >    auto_vec () { this->m_vec = NULL; }
> >    auto_vec (size_t n) { this->create (n); }
> >    ~auto_vec () { this->release (); }
> > +
> > +  auto_vec (auto_vec&& r)
> > +    {
> > +      this->m_vec = r.m_vec;
> > +      r.m_vec = NULL;
> > +    }
> > +  void operator= (auto_vec&&) = delete;
> >  };
> >  
> >  
> > 
> 
>
Jonathan Wakely Sept. 24, 2020, 1:16 p.m. UTC | #4
On 24/09/20 11:11 +0200, Richard Biener wrote:
>On Wed, 26 Aug 2020, Richard Biener wrote:
>
>> On Thu, 6 Aug 2020, Richard Biener wrote:
>>
>> > On Thu, 6 Aug 2020, Richard Biener wrote:
>> >
>> > > This adds a move CTOR to auto_vec<T, 0> and makes use of a
>> > > auto_vec<edge> return value for get_loop_exit_edges denoting
>> > > that lifetime management of the vector is handed to the caller.
>> > >
>> > > The move CTOR prompted the hash_table change because it appearantly
>> > > makes the copy CTOR implicitely deleted (good) and hash-table
>> > > expansion of the odr_enum_map which is
>> > > hash_map <nofree_string_hash, odr_enum> where odr_enum has an
>> > > auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
>> > > there's a latent bug there before this (I think we're not
>> > > invoking DTORs, but we're invoking copy-CTORs).
>> > >
>> > > Bootstrap / regtest running on x86_64-unknown-linux-gnu.
>> > >
>> > > Does this all look sensible and is it a good change
>> > > (the get_loop_exit_edges one)?
>> >
>> > Regtest went OK, here's an update with a complete ChangeLog
>> > (how useful..) plus the move assign operator deleted, copy
>> > assign wouldn't work as auto-generated and at the moment
>> > there's no use of assigning.  I guess if we'd have functions
>> > that take an auto_vec<> argument meaning they will destroy
>> > the vector that will become useful and we can implement it.
>> >
>> > OK for trunk?
>>
>> Ping.
>
>Ping^2.

Looks good to me as far as the use of C++ features goes.
Richard Biener Sept. 24, 2020, 3:05 p.m. UTC | #5
On Thu, 24 Sep 2020, Jonathan Wakely wrote:

> On 24/09/20 11:11 +0200, Richard Biener wrote:
> >On Wed, 26 Aug 2020, Richard Biener wrote:
> >
> >> On Thu, 6 Aug 2020, Richard Biener wrote:
> >>
> >> > On Thu, 6 Aug 2020, Richard Biener wrote:
> >> >
> >> > > This adds a move CTOR to auto_vec<T, 0> and makes use of a
> >> > > auto_vec<edge> return value for get_loop_exit_edges denoting
> >> > > that lifetime management of the vector is handed to the caller.
> >> > >
> >> > > The move CTOR prompted the hash_table change because it appearantly
> >> > > makes the copy CTOR implicitely deleted (good) and hash-table
> >> > > expansion of the odr_enum_map which is
> >> > > hash_map <nofree_string_hash, odr_enum> where odr_enum has an
> >> > > auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
> >> > > there's a latent bug there before this (I think we're not
> >> > > invoking DTORs, but we're invoking copy-CTORs).
> >> > >
> >> > > Bootstrap / regtest running on x86_64-unknown-linux-gnu.
> >> > >
> >> > > Does this all look sensible and is it a good change
> >> > > (the get_loop_exit_edges one)?
> >> >
> >> > Regtest went OK, here's an update with a complete ChangeLog
> >> > (how useful..) plus the move assign operator deleted, copy
> >> > assign wouldn't work as auto-generated and at the moment
> >> > there's no use of assigning.  I guess if we'd have functions
> >> > that take an auto_vec<> argument meaning they will destroy
> >> > the vector that will become useful and we can implement it.
> >> >
> >> > OK for trunk?
> >>
> >> Ping.
> >
> >Ping^2.
> 
> Looks good to me as far as the use of C++ features goes.

Thanks, now pushed after re-testing.

Richard.
Tom de Vries Sept. 25, 2020, 11:40 a.m. UTC | #6
On 9/24/20 5:05 PM, Richard Biener wrote:
> On Thu, 24 Sep 2020, Jonathan Wakely wrote:
> 
>> On 24/09/20 11:11 +0200, Richard Biener wrote:
>>> On Wed, 26 Aug 2020, Richard Biener wrote:
>>>
>>>> On Thu, 6 Aug 2020, Richard Biener wrote:
>>>>
>>>>> On Thu, 6 Aug 2020, Richard Biener wrote:
>>>>>
>>>>>> This adds a move CTOR to auto_vec<T, 0> and makes use of a
>>>>>> auto_vec<edge> return value for get_loop_exit_edges denoting
>>>>>> that lifetime management of the vector is handed to the caller.
>>>>>>
>>>>>> The move CTOR prompted the hash_table change because it appearantly
>>>>>> makes the copy CTOR implicitely deleted (good) and hash-table
>>>>>> expansion of the odr_enum_map which is
>>>>>> hash_map <nofree_string_hash, odr_enum> where odr_enum has an
>>>>>> auto_vec<odr_enum_val, 0> member triggers this.  Not sure if
>>>>>> there's a latent bug there before this (I think we're not
>>>>>> invoking DTORs, but we're invoking copy-CTORs).
>>>>>>
>>>>>> Bootstrap / regtest running on x86_64-unknown-linux-gnu.
>>>>>>
>>>>>> Does this all look sensible and is it a good change
>>>>>> (the get_loop_exit_edges one)?
>>>>>
>>>>> Regtest went OK, here's an update with a complete ChangeLog
>>>>> (how useful..) plus the move assign operator deleted, copy
>>>>> assign wouldn't work as auto-generated and at the moment
>>>>> there's no use of assigning.  I guess if we'd have functions
>>>>> that take an auto_vec<> argument meaning they will destroy
>>>>> the vector that will become useful and we can implement it.
>>>>>
>>>>> OK for trunk?
>>>>
>>>> Ping.
>>>
>>> Ping^2.
>>
>> Looks good to me as far as the use of C++ features goes.
> 
> Thanks, now pushed after re-testing.

Ran into a build breaker after this commit, reported here (
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97207 ).

Thanks,
- Tom
diff mbox series

Patch

diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 7720e6e5d2c..33a26cca6a4 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -1202,10 +1202,10 @@  release_recorded_exits (function *fn)
 
 /* Returns the list of the exit edges of a LOOP.  */
 
-vec<edge> 
+auto_vec<edge>
 get_loop_exit_edges (const class loop *loop, basic_block *body)
 {
-  vec<edge> edges = vNULL;
+  auto_vec<edge> edges;
   edge e;
   unsigned i;
   edge_iterator ei;
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 18b404e292f..f1687f37401 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -383,7 +383,7 @@  extern basic_block *get_loop_body_in_custom_order (const class loop *,
 extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
 			       int (*) (const void *, const void *, void *));
 
-extern vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
+extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
 extern edge single_exit (const class loop *);
 extern edge single_likely_exit (class loop *loop, vec<edge>);
 extern unsigned num_loop_branches (const class loop *);
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index 73134a20e33..3c9e2a0a99c 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -126,7 +126,7 @@  fix_loop_placement (class loop *loop, bool *irred_invalidated)
 {
   unsigned i;
   edge e;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   class loop *father = current_loops->tree_root, *act;
   bool ret = false;
 
@@ -157,7 +157,6 @@  fix_loop_placement (class loop *loop, bool *irred_invalidated)
       ret = true;
     }
 
-  exits.release ();
   return ret;
 }
 
diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 32f3a634e1e..487003c3acf 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -819,7 +819,7 @@  hash_table<Descriptor, Lazy, Allocator>::expand ()
       if (!is_empty (x) && !is_deleted (x))
         {
           value_type *q = find_empty_slot_for_expand (Descriptor::hash (x));
-	  new ((void*) q) value_type (x);
+	  new ((void*) q) value_type (std::move (x));
         }
 
       p++;
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 59e52927151..f750ec1725c 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -2767,7 +2767,6 @@  analyze_function_body (struct cgraph_node *node, bool early)
       scev_initialize ();
       FOR_EACH_LOOP (loop, 0)
 	{
-	  vec<edge> exits;
 	  edge ex;
 	  unsigned int j;
 	  class tree_niter_desc niter_desc;
@@ -2776,7 +2775,7 @@  analyze_function_body (struct cgraph_node *node, bool early)
 	  else
 	    bb_predicate = false;
 
-	  exits = get_loop_exit_edges (loop);
+	  auto_vec<edge> exits = get_loop_exit_edges (loop);
 	  FOR_EACH_VEC_ELT (exits, j, ex)
 	    if (number_of_iterations_exit (loop, ex, &niter_desc, false)
 		&& !is_gimple_min_invariant (niter_desc.niter))
@@ -2794,7 +2793,6 @@  analyze_function_body (struct cgraph_node *node, bool early)
 		   loop with independent predicate.  */
 		loop_iterations &= will_be_nonconstant;
 	    }
-	  exits.release ();
 	}
 
       /* To avoid quadratic behavior we analyze stride predicates only
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 0bbdb4d0c4b..9b35d0e83a9 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -128,7 +128,6 @@  create_loop_tree_nodes (void)
   bool skip_p;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
   loop_p loop;
 
   ira_bb_nodes
@@ -173,14 +172,13 @@  create_loop_tree_nodes (void)
 	      }
 	  if (skip_p)
 	    continue;
-	  edges = get_loop_exit_edges (loop);
+	  auto_vec<edge> edges = get_loop_exit_edges (loop);
 	  FOR_EACH_VEC_ELT (edges, j, e)
 	    if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
 	      {
 		skip_p = true;
 		break;
 	      }
-	  edges.release ();
 	  if (skip_p)
 	    continue;
 	}
@@ -1964,17 +1962,15 @@  create_loop_tree_node_allocnos (ira_loop_tree_node_t loop_node)
       int i;
       edge_iterator ei;
       edge e;
-      vec<edge> edges;
 
       ira_assert (current_loops != NULL);
       FOR_EACH_EDGE (e, ei, loop_node->loop->header->preds)
 	if (e->src != loop_node->loop->latch)
 	  create_loop_allocnos (e);
 
-      edges = get_loop_exit_edges (loop_node->loop);
+      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
       FOR_EACH_VEC_ELT (edges, i, e)
 	create_loop_allocnos (e);
-      edges.release ();
     }
 }
 
@@ -2167,13 +2163,12 @@  loop_with_complex_edge_p (class loop *loop)
   int i;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
   bool res;
 
   FOR_EACH_EDGE (e, ei, loop->header->preds)
     if (e->flags & EDGE_EH)
       return true;
-  edges = get_loop_exit_edges (loop);
+  auto_vec<edge> edges = get_loop_exit_edges (loop);
   res = false;
   FOR_EACH_VEC_ELT (edges, i, e)
     if (e->flags & EDGE_COMPLEX)
@@ -2181,7 +2176,6 @@  loop_with_complex_edge_p (class loop *loop)
 	res = true;
 	break;
       }
-  edges.release ();
   return res;
 }
 #endif
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index dbb3b7a2a51..d3f8e23faff 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -2539,7 +2539,6 @@  ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
   int freq, i;
   edge_iterator ei;
   edge e;
-  vec<edge> edges;
 
   ira_assert (current_loops != NULL && loop_node->loop != NULL
 	      && (regno < 0 || regno >= FIRST_PSEUDO_REGISTER));
@@ -2555,13 +2554,12 @@  ira_loop_edge_freq (ira_loop_tree_node_t loop_node, int regno, bool exit_p)
     }
   else
     {
-      edges = get_loop_exit_edges (loop_node->loop);
+      auto_vec<edge> edges = get_loop_exit_edges (loop_node->loop);
       FOR_EACH_VEC_ELT (edges, i, e)
 	if (regno < 0
 	    || (bitmap_bit_p (df_get_live_out (e->src), regno)
 		&& bitmap_bit_p (df_get_live_in (e->dest), regno)))
 	  freq += EDGE_FREQUENCY (e);
-      edges.release ();
     }
 
   return REG_FREQ_FROM_EDGE_FREQ (freq);
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 693c7768868..e1efe624361 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -1580,7 +1580,7 @@  analyze_insns_in_loop (class loop *loop)
   struct var_to_expand *ves = NULL;
   iv_to_split **slot1;
   var_to_expand **slot2;
-  vec<edge> edges = get_loop_exit_edges (loop);
+  auto_vec<edge> edges = get_loop_exit_edges (loop);
   edge exit;
   bool can_apply = false;
 
@@ -1656,7 +1656,6 @@  analyze_insns_in_loop (class loop *loop)
       }
     }
 
-  edges.release ();
   free (body);
   return opt_info;
 }
diff --git a/gcc/predict.c b/gcc/predict.c
index 0a317a7a4ac..a847b9b4045 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -1915,7 +1915,6 @@  predict_loops (void)
     {
       basic_block bb, *bbs;
       unsigned j, n_exits = 0;
-      vec<edge> exits;
       class tree_niter_desc niter_desc;
       edge ex;
       class nb_iter_bound *nb_iter;
@@ -1926,15 +1925,12 @@  predict_loops (void)
       gcond *stmt = NULL;
       bool recursion = with_recursion.contains (loop);
 
-      exits = get_loop_exit_edges (loop);
+      auto_vec<edge> exits = get_loop_exit_edges (loop);
       FOR_EACH_VEC_ELT (exits, j, ex)
 	if (!unlikely_executed_edge_p (ex) && !(ex->flags & EDGE_ABNORMAL_CALL))
 	  n_exits ++;
       if (!n_exits)
-	{
-          exits.release ();
-	  continue;
-	}
+	continue;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "Predicting loop %i%s with %i exits.\n",
@@ -2048,7 +2044,6 @@  predict_loops (void)
 	  probability = RDIV (REG_BR_PROB_BASE, nitercst);
 	  predict_edge (ex, predictor, probability);
 	}
-      exits.release ();
 
       /* Find information about loop bound variables.  */
       for (nb_iter = loop->bounds; nb_iter;
diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
index d2dcfe7f42d..93e6da1e2ab 100644
--- a/gcc/tree-predcom.c
+++ b/gcc/tree-predcom.c
@@ -737,13 +737,12 @@  static basic_block
 last_always_executed_block (class loop *loop)
 {
   unsigned i;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge ex;
   basic_block last = loop->latch;
 
   FOR_EACH_VEC_ELT (exits, i, ex)
     last = nearest_common_dominator (CDI_DOMINATORS, last, ex->src);
-  exits.release ();
 
   return last;
 }
diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c
index b9002d8e294..b86acf7c39d 100644
--- a/gcc/tree-ssa-loop-ch.c
+++ b/gcc/tree-ssa-loop-ch.c
@@ -504,14 +504,13 @@  ch_base::copy_headers (function *fun)
 	{
 	  edge entry = copied[i].first;
 	  loop_p loop = copied[i].second;
-	  vec<edge> exit_edges = get_loop_exit_edges (loop);
+	  auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
 	  bitmap exit_bbs = BITMAP_ALLOC (NULL);
 	  for (unsigned j = 0; j < exit_edges.length (); ++j)
 	    bitmap_set_bit (exit_bbs, exit_edges[j]->dest->index);
 	  bitmap_set_bit (exit_bbs, loop->header->index);
 	  do_rpo_vn (cfun, entry, exit_bbs);
 	  BITMAP_FREE (exit_bbs);
-	  exit_edges.release ();
 	}
     }
   free (bbs);
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 35da1fb26a6..8b7eb57514f 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -2866,7 +2866,7 @@  loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
 static void
 store_motion_loop (class loop *loop, bitmap sm_executed)
 {
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   class loop *subloop;
   bitmap sm_in_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
 
@@ -2876,7 +2876,6 @@  store_motion_loop (class loop *loop, bitmap sm_executed)
       if (!bitmap_empty_p (sm_in_loop))
 	hoist_memory_references (loop, sm_in_loop, exits);
     }
-  exits.release ();
 
   bitmap_ior_into (sm_executed, sm_in_loop);
   for (subloop = loop->inner; subloop != NULL; subloop = subloop->next)
diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
index 298ab215530..5bb781dc7fa 100644
--- a/gcc/tree-ssa-loop-ivcanon.c
+++ b/gcc/tree-ssa-loop-ivcanon.c
@@ -444,7 +444,6 @@  estimated_unrolled_size (struct loop_size *size,
 static edge
 loop_edge_to_cancel (class loop *loop)
 {
-  vec<edge> exits;
   unsigned i;
   edge edge_to_cancel;
   gimple_stmt_iterator gsi;
@@ -453,7 +452,7 @@  loop_edge_to_cancel (class loop *loop)
   if (EDGE_COUNT (loop->latch->preds) > 1)
     return NULL;
 
-  exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
 
   FOR_EACH_VEC_ELT (exits, i, edge_to_cancel)
     {
@@ -477,8 +476,6 @@  loop_edge_to_cancel (class loop *loop)
       if (edge_to_cancel->dest != loop->latch)
         continue;
 
-      exits.release ();
-
       /* Verify that the code in loop latch does nothing that may end program
          execution without really reaching the exit.  This may include
 	 non-pure/const function calls, EH statements, volatile ASMs etc.  */
@@ -487,7 +484,6 @@  loop_edge_to_cancel (class loop *loop)
 	   return NULL;
       return edge_to_cancel;
     }
-  exits.release ();
   return NULL;
 }
 
@@ -1222,10 +1218,9 @@  canonicalize_loop_induction_variables (class loop *loop,
      by find_loop_niter_by_eval.  Be sure to keep it for future.  */
   if (niter && TREE_CODE (niter) == INTEGER_CST)
     {
-      vec<edge> exits = get_loop_exit_edges  (loop);
+      auto_vec<edge> exits = get_loop_exit_edges  (loop);
       record_niter_bound (loop, wi::to_widest (niter),
 			  exit == single_likely_exit (loop, exits), true);
-      exits.release ();
     }
 
   /* Force re-computation of loop bounds so we can remove redundant exits.  */
diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
index a2717a411a3..cdd1ac76833 100644
--- a/gcc/tree-ssa-loop-manip.c
+++ b/gcc/tree-ssa-loop-manip.c
@@ -368,11 +368,10 @@  get_loops_exits (bitmap *loop_exits)
 
   FOR_EACH_LOOP (loop, 0)
     {
-      vec<edge> exit_edges = get_loop_exit_edges (loop);
+      auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
       loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
       FOR_EACH_VEC_ELT (exit_edges, j, e)
         bitmap_set_bit (loop_exits[loop->num], e->dest->index);
-      exit_edges.release ();
     }
 }
 
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 7d61ef080eb..8bb29c2470f 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -2752,7 +2752,7 @@  tree
 find_loop_niter (class loop *loop, edge *exit)
 {
   unsigned i;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge ex;
   tree niter = NULL_TREE, aniter;
   class tree_niter_desc desc;
@@ -2803,7 +2803,6 @@  find_loop_niter (class loop *loop, edge *exit)
 	  continue;
 	}
     }
-  exits.release ();
 
   return niter ? niter : chrec_dont_know;
 }
@@ -2837,21 +2836,18 @@  finite_loop_p (class loop *loop)
   if (loop->finite_p)
     {
       unsigned i;
-      vec<edge> exits = get_loop_exit_edges (loop);
+      auto_vec<edge> exits = get_loop_exit_edges (loop);
       edge ex;
 
       /* If the loop has a normal exit, we can assume it will terminate.  */
       FOR_EACH_VEC_ELT (exits, i, ex)
 	if (!(ex->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_FAKE)))
 	  {
-	    exits.release ();
 	    if (dump_file)
 	      fprintf (dump_file, "Assume loop %i to be finite: it has an exit "
 		       "and -ffinite-loops is on.\n", loop->num);
 	    return true;
 	  }
-
-      exits.release ();
     }
 
   return false;
@@ -3114,7 +3110,7 @@  tree
 find_loop_niter_by_eval (class loop *loop, edge *exit)
 {
   unsigned i;
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge ex;
   tree niter = NULL_TREE, aniter;
 
@@ -3123,10 +3119,7 @@  find_loop_niter_by_eval (class loop *loop, edge *exit)
   /* Loops with multiple exits are expensive to handle and less important.  */
   if (!flag_expensive_optimizations
       && exits.length () > 1)
-    {
-      exits.release ();
-      return chrec_dont_know;
-    }
+    return chrec_dont_know;
 
   FOR_EACH_VEC_ELT (exits, i, ex)
     {
@@ -3144,7 +3137,6 @@  find_loop_niter_by_eval (class loop *loop, edge *exit)
       niter = aniter;
       *exit = ex;
     }
-  exits.release ();
 
   return niter ? niter : chrec_dont_know;
 }
@@ -4236,7 +4228,6 @@  get_upper_bound_based_on_builtin_expr_with_prob (gcond *cond)
 void
 estimate_numbers_of_iterations (class loop *loop)
 {
-  vec<edge> exits;
   tree niter, type;
   unsigned i;
   class tree_niter_desc niter_desc;
@@ -4275,7 +4266,7 @@  estimate_numbers_of_iterations (class loop *loop)
   number_of_latch_executions (loop);
 
   basic_block *body = get_loop_body (loop);
-  exits = get_loop_exit_edges (loop, body);
+  auto_vec<edge> exits = get_loop_exit_edges (loop, body);
   likely_exit = single_likely_exit (loop, exits);
   FOR_EACH_VEC_ELT (exits, i, ex)
     {
@@ -4311,7 +4302,6 @@  estimate_numbers_of_iterations (class loop *loop)
 		       true, ex == likely_exit, true);
       record_control_iv (loop, &niter_desc);
     }
-  exits.release ();
 
   if (flag_aggressive_loop_optimizations)
     infer_loop_bounds_from_undefined (loop, body);
diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c
index d19ece6410d..5e94a19c964 100644
--- a/gcc/tree-ssa-loop-prefetch.c
+++ b/gcc/tree-ssa-loop-prefetch.c
@@ -1289,7 +1289,7 @@  mark_nontemporal_store (struct mem_ref *ref)
 static void
 emit_mfence_after_loop (class loop *loop)
 {
-  vec<edge> exits = get_loop_exit_edges (loop);
+  auto_vec<edge> exits = get_loop_exit_edges (loop);
   edge exit;
   gcall *call;
   gimple_stmt_iterator bsi;
@@ -1309,7 +1309,6 @@  emit_mfence_after_loop (class loop *loop)
       gsi_insert_before (&bsi, call, GSI_NEW_STMT);
     }
 
-  exits.release ();
   update_ssa (TODO_update_ssa_only_virtuals);
 }
 
@@ -1327,7 +1326,7 @@  may_use_storent_in_loop_p (class loop *loop)
      is a suitable place for it at each of the loop exits.  */
   if (FENCE_FOLLOWING_MOVNT != NULL_TREE)
     {
-      vec<edge> exits = get_loop_exit_edges (loop);
+      auto_vec<edge> exits = get_loop_exit_edges (loop);
       unsigned i;
       edge exit;
 
@@ -1335,8 +1334,6 @@  may_use_storent_in_loop_p (class loop *loop)
 	if ((exit->flags & EDGE_ABNORMAL)
 	    && exit->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
 	  ret = false;
-
-      exits.release ();
     }
 
   return ret;
diff --git a/gcc/vec.h b/gcc/vec.h
index 3ad99b83690..38478bffc6b 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1533,6 +1533,12 @@  public:
   auto_vec () { this->m_vec = NULL; }
   auto_vec (size_t n) { this->create (n); }
   ~auto_vec () { this->release (); }
+
+  auto_vec (auto_vec&& r)
+    {
+      this->m_vec = r.m_vec;
+      r.m_vec = NULL;
+    }
 };