public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/6] auto_vec copy/move improvements
@ 2021-06-15  5:59 Trevor Saunders
  2021-06-15  5:59 ` [PATCH 2/6] return auto_vec from cgraph_node::collect_callers Trevor Saunders
                   ` (6 more replies)
  0 siblings, 7 replies; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  5:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

- Unfortunately using_auto_storage () needs to handle m_vec being null.
- Handle self move of an auto_vec to itself.
- punt on defining copy or move operators for auto_vec with inline storage,
  until there is a need for them and we can decide what semantics they should
have.
- Make sure auto_vec defines the classes move constructor and assignment
  operator, as well as ones taking vec<T>, so the compiler does not generate
them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
the ones taking vec<T> do not count as the classes move constructor or
assignment operator, but we want them as well to assign a plain vec to a
auto_vec.
- Explicitly delete auto_vec's copy constructor and assignment operator.  This
  prevents unintentional expenssive coppies of the vector and makes it clear
when coppies are needed that that is what is intended.  When it is necessary to
copy a vector copy () can be used.

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

bootstrapped and regtested on x86_64-linux-gnu, ok?

gcc/ChangeLog:

	* vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
	(auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
	constructor.
	(auto_vec<T, 0>::operator=): Define move assignment and delete copy
	assignment.
	(auto_vec<T, N>::auto_vec): Delete copy and move constructors.
	(auto_vec<T, N>::operator=): Delete copy and move assignment.
---
 gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/gcc/vec.h b/gcc/vec.h
index 193377cb69c..ceefa67e1ad 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1549,6 +1549,16 @@ public:
     this->release ();
   }
 
+  // Punt for now on moving auto_vec with inline storage.  For now this
+  // prevents people creating dangling pointers or the like.
+  auto_vec (auto_vec &&) = delete;
+  auto_vec &operator= (auto_vec &&) = delete;
+
+  // Punt for now on the inline storage, and you probably don't want to copy
+  // vectors anyway.  If you really must copy a vector use copy ().
+  auto_vec(const auto_vec &) = delete;
+  auto_vec &operator= (const auto_vec &) = delete;
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1570,14 +1580,43 @@ public:
       this->m_vec = r.m_vec;
       r.m_vec = NULL;
     }
+
+  auto_vec (auto_vec<T> &&r)
+    {
+      gcc_assert (!r.using_auto_storage ());
+      this->m_vec = r.m_vec;
+      r.m_vec = NULL;
+    }
+
   auto_vec& operator= (vec<T, va_heap>&& r)
     {
+	    if (this == &r)
+		    return *this;
+
+      gcc_assert (!r.using_auto_storage ());
+      this->release ();
+      this->m_vec = r.m_vec;
+      r.m_vec = NULL;
+      return *this;
+    }
+
+  auto_vec& operator= (auto_vec<T> &&r)
+    {
+	    if (this == &r)
+		    return *this;
+
       gcc_assert (!r.using_auto_storage ());
       this->release ();
       this->m_vec = r.m_vec;
       r.m_vec = NULL;
       return *this;
     }
+
+  // You probably don't want to copy a vector, so these are deleted to prevent
+  // unintentional use.  If you really need a copy of the vectors contents you
+  // can use copy ().
+  auto_vec(const auto_vec &) = delete;
+  auto_vec &operator= (const auto_vec &) = delete;
 };
 
 
@@ -2147,7 +2186,7 @@ template<typename T>
 inline bool
 vec<T, va_heap, vl_ptr>::using_auto_storage () const
 {
-  return m_vec->m_vecpfx.m_using_auto_storage;
+  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
 }
 
 /* Release VEC and call release of all element vectors.  */
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 2/6] return auto_vec from cgraph_node::collect_callers
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
@ 2021-06-15  5:59 ` Trevor Saunders
  2021-06-15  6:45   ` Richard Biener
  2021-06-15  5:59 ` [PATCH 3/6] return auto_vec from get_loop_hot_path Trevor Saunders
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  5:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

This ensures the callers of collect_callers () take ownership of the vector and
free it when appropriate.

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

bootstrapped and regtested on x86_64-linux-gnu, ok?

gcc/ChangeLog:

	* cgraph.c (cgraph_node::collect_callers): Return
	auto_vec<cgraph_edge *>.
	* cgraph.h (cgraph_node::collect_callers): Likewise.
	* ipa-cp.c (create_specialized_node): Adjust.
	(decide_about_value): Likewise.
	(decide_whether_version_node): Likewise.
	* ipa-sra.c (process_isra_node_results): Likewise.
---
 gcc/cgraph.c  | 4 ++--
 gcc/cgraph.h  | 2 +-
 gcc/ipa-cp.c  | 7 +++----
 gcc/ipa-sra.c | 2 +-
 4 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index d7c78d518bc..abe4e3ebfb3 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -3074,10 +3074,10 @@ collect_callers_of_node_1 (cgraph_node *node, void *data)
 /* Collect all callers of cgraph_node and its aliases that are known to lead to
    cgraph_node (i.e. are not overwritable).  */
 
-vec<cgraph_edge *>
+auto_vec<cgraph_edge *>
 cgraph_node::collect_callers (void)
 {
-  vec<cgraph_edge *> redirect_callers = vNULL;
+  auto_vec<cgraph_edge *> redirect_callers;
   call_for_symbol_thunks_and_aliases (collect_callers_of_node_1,
 				    &redirect_callers, false);
   return redirect_callers;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 4a1f89920f5..9f4338fdf87 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1139,7 +1139,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
 
   /* Collect all callers of cgraph_node and its aliases that are known to lead
      to NODE (i.e. are not overwritable) and that are not thunks.  */
-  vec<cgraph_edge *> collect_callers (void);
+  auto_vec<cgraph_edge *> collect_callers (void);
 
   /* Remove all callers from the node.  */
   void remove_callers (void);
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 2cae69e5a1b..57c18af2bab 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -4527,7 +4527,7 @@ create_specialized_node (struct cgraph_node *node,
 			 vec<tree> known_csts,
 			 vec<ipa_polymorphic_call_context> known_contexts,
 			 struct ipa_agg_replacement_value *aggvals,
-			 vec<cgraph_edge *> callers)
+			 vec<cgraph_edge *> &callers)
 {
   ipa_node_params *new_info, *info = ipa_node_params_sum->get (node);
   vec<ipa_replace_map *, va_gc> *replace_trees = NULL;
@@ -4672,7 +4672,6 @@ create_specialized_node (struct cgraph_node *node,
 
   ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, aggvals);
 
-  callers.release ();
   return new_node;
 }
 
@@ -5562,6 +5561,7 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset,
 						      offset, val->value));
   val->spec_node = create_specialized_node (node, known_csts, known_contexts,
 					    aggvals, callers);
+  callers.release ();
   overall_size += val->local_size_cost;
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "     overall size reached %li\n",
@@ -5638,7 +5638,7 @@ decide_whether_version_node (struct cgraph_node *node)
 	}
 
       struct cgraph_node *clone;
-      vec<cgraph_edge *> callers = node->collect_callers ();
+      auto_vec<cgraph_edge *> callers = node->collect_callers ();
 
       for (int i = callers.length () - 1; i >= 0; i--)
 	{
@@ -5654,7 +5654,6 @@ decide_whether_version_node (struct cgraph_node *node)
 	  /* If node is not called by anyone, or all its caller edges are
 	     self-recursive, the node is not really in use, no need to do
 	     cloning.  */
-	  callers.release ();
 	  info->do_clone_for_all_contexts = false;
 	  return ret;
 	}
diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c
index 3f90d4d81b6..3272daf56e4 100644
--- a/gcc/ipa-sra.c
+++ b/gcc/ipa-sra.c
@@ -3755,7 +3755,7 @@ process_isra_node_results (cgraph_node *node,
   unsigned &suffix_counter = clone_num_suffixes->get_or_insert (
 			       IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (
 				 node->decl)));
-  vec<cgraph_edge *> callers = node->collect_callers ();
+  auto_vec<cgraph_edge *> callers = node->collect_callers ();
   cgraph_node *new_node
     = node->create_virtual_clone (callers, NULL, new_adjustments, "isra",
 				  suffix_counter);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 3/6] return auto_vec from get_loop_hot_path
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
  2021-06-15  5:59 ` [PATCH 2/6] return auto_vec from cgraph_node::collect_callers Trevor Saunders
@ 2021-06-15  5:59 ` Trevor Saunders
  2021-06-15  6:45   ` Richard Biener
  2021-06-15  5:59 ` [PATCH 4/6] return auto_vec from get_dominated_by Trevor Saunders
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  5:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

This ensures callers take ownership of the returned vector.

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

bootstrapped and regtested on x86_64-linux-gnu, ok?

gcc/ChangeLog:

	* cfgloop.h (get_loop_hot_path): Return auto_vec<basic_block>.
	* cfgloopanal.c (get_loop_hot_path): Likewise.
	* tree-ssa-loop-ivcanon.c (tree_estimate_loop_size): Likewise.
---
 gcc/cfgloop.h               | 2 +-
 gcc/cfgloopanal.c           | 2 +-
 gcc/tree-ssa-loop-ivcanon.c | 5 ++---
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 113241da130..5e699276c88 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -840,7 +840,7 @@ enum
 
 extern void doloop_optimize_loops (void);
 extern void move_loop_invariants (void);
-extern vec<basic_block> get_loop_hot_path (const class loop *loop);
+extern auto_vec<basic_block> get_loop_hot_path (const class loop *loop);
 
 /* Returns the outermost loop of the loop nest that contains LOOP.*/
 static inline class loop *
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index d0eade3dd34..e7b7ae2163e 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -500,7 +500,7 @@ single_likely_exit (class loop *loop, vec<edge> exits)
    order against direction of edges from latch.  Specially, if
    header != latch, latch is the 1-st block.  */
 
-vec<basic_block>
+auto_vec<basic_block>
 get_loop_hot_path (const class loop *loop)
 {
   basic_block bb = loop->header;
diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
index 3f9e9d0869f..b1971f83544 100644
--- a/gcc/tree-ssa-loop-ivcanon.c
+++ b/gcc/tree-ssa-loop-ivcanon.c
@@ -218,7 +218,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
   gimple_stmt_iterator gsi;
   unsigned int i;
   bool after_exit;
-  vec<basic_block> path = get_loop_hot_path (loop);
+  auto_vec<basic_block> path = get_loop_hot_path (loop);
 
   size->overall = 0;
   size->eliminated_by_peeling = 0;
@@ -342,7 +342,6 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
 	      - size->last_iteration_eliminated_by_peeling) > upper_bound)
 	    {
               free (body);
-	      path.release ();
 	      return true;
 	    }
 	}
@@ -379,7 +378,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
 	    size->num_branches_on_hot_path++;
 	}
     }
-  path.release ();
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "size: %i-%i, last_iteration: %i-%i\n", size->overall,
     	     size->eliminated_by_peeling, size->last_iteration,
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 4/6] return auto_vec from get_dominated_by
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
  2021-06-15  5:59 ` [PATCH 2/6] return auto_vec from cgraph_node::collect_callers Trevor Saunders
  2021-06-15  5:59 ` [PATCH 3/6] return auto_vec from get_loop_hot_path Trevor Saunders
@ 2021-06-15  5:59 ` Trevor Saunders
  2021-06-15  6:46   ` Richard Biener
  2021-06-15  5:59 ` [PATCH 5/6] make get_domminated_by_region return a auto_vec Trevor Saunders
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  5:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

bootstrapped and regtested on x86_64-linux-gnu, ok?

gcc/ChangeLog:

	* dominance.c (get_dominated_by): Return auto_vec<basic_block>.
	* dominance.h (get_dominated_by): Likewise.
	* auto-profile.c (afdo_find_equiv_class): Adjust.
	* cfgloopmanip.c (duplicate_loop_to_header_edge): Likewise.
	* loop-unroll.c (unroll_loop_runtime_iterations): Likewise.
	* tree-cfg.c (test_linear_chain): Likewise.
	(test_diamond): Likewise.
---
 gcc/auto-profile.c |  9 +++------
 gcc/cfgloopmanip.c |  4 +---
 gcc/dominance.c    |  6 +++---
 gcc/dominance.h    |  2 +-
 gcc/loop-unroll.c  | 12 +++---------
 gcc/tree-cfg.c     | 14 ++++++--------
 6 files changed, 17 insertions(+), 30 deletions(-)

diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c
index ed788dc06a8..43d6fa0b1f0 100644
--- a/gcc/auto-profile.c
+++ b/gcc/auto-profile.c
@@ -1155,13 +1155,10 @@ afdo_find_equiv_class (bb_set *annotated_bb)
 
   FOR_ALL_BB_FN (bb, cfun)
   {
-    vec<basic_block> dom_bbs;
-
     if (bb->aux != NULL)
       continue;
     bb->aux = bb;
-    dom_bbs = get_dominated_by (CDI_DOMINATORS, bb);
-    for (basic_block bb1 : dom_bbs)
+    for (basic_block bb1 : get_dominated_by (CDI_DOMINATORS, bb))
       if (bb1->aux == NULL && dominated_by_p (CDI_POST_DOMINATORS, bb, bb1)
 	  && bb1->loop_father == bb->loop_father)
 	{
@@ -1172,8 +1169,8 @@ afdo_find_equiv_class (bb_set *annotated_bb)
 	      set_bb_annotated (bb, annotated_bb);
 	    }
 	}
-    dom_bbs = get_dominated_by (CDI_POST_DOMINATORS, bb);
-    for (basic_block bb1 : dom_bbs)
+
+    for (basic_block bb1 : get_dominated_by (CDI_POST_DOMINATORS, bb))
       if (bb1->aux == NULL && dominated_by_p (CDI_DOMINATORS, bb, bb1)
 	  && bb1->loop_father == bb->loop_father)
 	{
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index 4a9ab74642c..e6df28036c4 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -1414,13 +1414,12 @@ duplicate_loop_to_header_edge (class loop *loop, edge e,
   for (i = 0; i < n; i++)
     {
       basic_block dominated, dom_bb;
-      vec<basic_block> dom_bbs;
       unsigned j;
 
       bb = bbs[i];
       bb->aux = 0;
 
-      dom_bbs = get_dominated_by (CDI_DOMINATORS, bb);
+      auto_vec<basic_block> dom_bbs = get_dominated_by (CDI_DOMINATORS, bb);
       FOR_EACH_VEC_ELT (dom_bbs, j, dominated)
 	{
 	  if (flow_bb_inside_loop_p (loop, dominated))
@@ -1429,7 +1428,6 @@ duplicate_loop_to_header_edge (class loop *loop, edge e,
 			CDI_DOMINATORS, first_active[i], first_active_latch);
 	  set_immediate_dominator (CDI_DOMINATORS, dominated, dom_bb);
 	}
-      dom_bbs.release ();
     }
   free (first_active);
 
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 5fa172f3280..0e464cb7282 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -883,17 +883,17 @@ set_immediate_dominator (enum cdi_direction dir, basic_block bb,
 
 /* Returns the list of basic blocks immediately dominated by BB, in the
    direction DIR.  */
-vec<basic_block> 
+auto_vec<basic_block> 
 get_dominated_by (enum cdi_direction dir, basic_block bb)
 {
   unsigned int dir_index = dom_convert_dir_to_idx (dir);
   struct et_node *node = bb->dom[dir_index], *son = node->son, *ason;
-  vec<basic_block> bbs = vNULL;
+  auto_vec<basic_block> bbs;
 
   gcc_checking_assert (dom_computed[dir_index]);
 
   if (!son)
-    return vNULL;
+    return bbs;
 
   bbs.safe_push ((basic_block) son->data);
   for (ason = son->right; ason != son; ason = ason->right)
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 4eeac59fc59..515a369aacf 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -46,7 +46,7 @@ extern void free_dominance_info_for_region (function *,
 extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
 extern void set_immediate_dominator (enum cdi_direction, basic_block,
 				     basic_block);
-extern vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
+extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
 extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
 							 basic_block *,
 							 unsigned);
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 8b6fcf5074c..66d93487e29 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -884,7 +884,7 @@ unroll_loop_runtime_iterations (class loop *loop)
 {
   rtx old_niter, niter, tmp;
   rtx_insn *init_code, *branch_code;
-  unsigned i, j;
+  unsigned i;
   profile_probability p;
   basic_block preheader, *body, swtch, ezc_swtch = NULL;
   int may_exit_copy;
@@ -908,15 +908,9 @@ unroll_loop_runtime_iterations (class loop *loop)
   body = get_loop_body (loop);
   for (i = 0; i < loop->num_nodes; i++)
     {
-      vec<basic_block> ldom;
-      basic_block bb;
-
-      ldom = get_dominated_by (CDI_DOMINATORS, body[i]);
-      FOR_EACH_VEC_ELT (ldom, j, bb)
+      for (basic_block bb : get_dominated_by (CDI_DOMINATORS, body[i]))
 	if (!flow_bb_inside_loop_p (loop, bb))
 	  dom_bbs.safe_push (bb);
-
-      ldom.release ();
     }
   free (body);
 
@@ -1013,7 +1007,7 @@ unroll_loop_runtime_iterations (class loop *loop)
       gcc_assert (ok);
 
       /* Create item for switch.  */
-      j = n_peel - i - (extra_zero_check ? 0 : 1);
+      unsigned j = n_peel - i - (extra_zero_check ? 0 : 1);
       p = profile_probability::always ().apply_scale (1, i + 2);
 
       preheader = split_edge (loop_preheader_edge (loop));
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 02256580c98..6bdd1a561fd 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -9917,22 +9917,20 @@ test_linear_chain ()
   calculate_dominance_info (CDI_DOMINATORS);
   ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
   ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
-  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
   ASSERT_EQ (1, dom_by_b.length ());
   ASSERT_EQ (bb_c, dom_by_b[0]);
   free_dominance_info (CDI_DOMINATORS);
-  dom_by_b.release ();
 
   /* Similarly for post-dominance: each BB in our chain is post-dominated
      by the one after it.  */
   calculate_dominance_info (CDI_POST_DOMINATORS);
   ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
   ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
-  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  auto_vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
   ASSERT_EQ (1, postdom_by_b.length ());
   ASSERT_EQ (bb_a, postdom_by_b[0]);
   free_dominance_info (CDI_POST_DOMINATORS);
-  postdom_by_b.release ();
 
   pop_cfun ();
 }
@@ -9991,10 +9989,10 @@ test_diamond ()
   ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
   ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
   ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
-  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
+  auto_vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
   ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
   dom_by_a.release ();
-  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
+  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
   ASSERT_EQ (0, dom_by_b.length ());
   dom_by_b.release ();
   free_dominance_info (CDI_DOMINATORS);
@@ -10004,10 +10002,10 @@ test_diamond ()
   ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
   ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
   ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
-  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
+  auto_vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
   ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
   postdom_by_d.release ();
-  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
+  auto_vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
   ASSERT_EQ (0, postdom_by_b.length ());
   postdom_by_b.release ();
   free_dominance_info (CDI_POST_DOMINATORS);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
                   ` (2 preceding siblings ...)
  2021-06-15  5:59 ` [PATCH 4/6] return auto_vec from get_dominated_by Trevor Saunders
@ 2021-06-15  5:59 ` Trevor Saunders
  2021-06-15  6:49   ` Richard Biener
  2021-06-15  5:59 ` [PATCH 6/6] return auto_vec from more dominance functions Trevor Saunders
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  5:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

This makes it clear the caller owns the vector, and ensures it is cleaned up.

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

bootstrapped and regtested on x86_64-linux-gnu, ok?

gcc/ChangeLog:

	* dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
	* dominance.h (get_dominated_by_region): Likewise.
	* tree-cfg.c (gimple_duplicate_sese_region): Adjust.
	(gimple_duplicate_sese_tail): Likewise.
	(move_sese_region_to_fn): Likewise.
---
 gcc/dominance.c |  4 ++--
 gcc/dominance.h |  2 +-
 gcc/tree-cfg.c  | 18 +++++++-----------
 3 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/gcc/dominance.c b/gcc/dominance.c
index 0e464cb7282..4943102ff1d 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
    direction DIR) by some block between N_REGION ones stored in REGION,
    except for blocks in the REGION itself.  */
 
-vec<basic_block> 
+auto_vec<basic_block> 
 get_dominated_by_region (enum cdi_direction dir, basic_block *region,
 			 unsigned n_region)
 {
   unsigned i;
   basic_block dom;
-  vec<basic_block> doms = vNULL;
+  auto_vec<basic_block> doms;
 
   for (i = 0; i < n_region; i++)
     region[i]->flags |= BB_DUPLICATED;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 515a369aacf..c74ad297c6a 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
 extern void set_immediate_dominator (enum cdi_direction, basic_block,
 				     basic_block);
 extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
-extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
+extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
 							 basic_block *,
 							 unsigned);
 extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 6bdd1a561fd..c9403deed19 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
   bool free_region_copy = false, copying_header = false;
   class loop *loop = entry->dest->loop_father;
   edge exit_copy;
-  vec<basic_block> doms = vNULL;
   edge redirected;
   profile_count total_count = profile_count::uninitialized ();
   profile_count entry_count = profile_count::uninitialized ();
@@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
 
   /* Record blocks outside the region that are dominated by something
      inside.  */
+  auto_vec<basic_block> doms;
   if (update_dominance)
     {
-      doms.create (0);
       doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
     }
 
@@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
       set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
       doms.safe_push (get_bb_original (entry->dest));
       iterate_fix_dominators (CDI_DOMINATORS, doms, false);
-      doms.release ();
     }
 
   /* Add the other PHI node arguments.  */
@@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
   class loop *loop = exit->dest->loop_father;
   class loop *orig_loop = entry->dest->loop_father;
   basic_block switch_bb, entry_bb, nentry_bb;
-  vec<basic_block> doms;
   profile_count total_count = profile_count::uninitialized (),
 		exit_count = profile_count::uninitialized ();
   edge exits[2], nexits[2], e;
@@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
 
   /* Record blocks outside the region that are dominated by something
      inside.  */
-  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
+  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
+							n_region);
 
   total_count = exit->src->count;
   exit_count = exit->count ();
@@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
   /* Anything that is outside of the region, but was dominated by something
      inside needs to update dominance info.  */
   iterate_fix_dominators (CDI_DOMINATORS, doms, false);
-  doms.release ();
   /* Update the SSA web.  */
   update_ssa (TODO_update_ssa);
 
@@ -7567,7 +7564,7 @@ basic_block
 move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
 		        basic_block exit_bb, tree orig_block)
 {
-  vec<basic_block> bbs, dom_bbs;
+  vec<basic_block> bbs;
   basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
   basic_block after, bb, *entry_pred, *exit_succ, abb;
   struct function *saved_cfun = cfun;
@@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
 
   /* The blocks that used to be dominated by something in BBS will now be
      dominated by the new block.  */
-  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
-				     bbs.address (),
-				     bbs.length ());
+  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
+							   bbs.address (),
+							   bbs.length ());
 
   /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
      the predecessor edges to ENTRY_BB and the successor edges to
@@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
   FOR_EACH_VEC_ELT (dom_bbs, i, abb)
     set_immediate_dominator (CDI_DOMINATORS, abb, bb);
-  dom_bbs.release ();
 
   if (exit_bb)
     {
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 6/6] return auto_vec from more dominance functions
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
                   ` (3 preceding siblings ...)
  2021-06-15  5:59 ` [PATCH 5/6] make get_domminated_by_region return a auto_vec Trevor Saunders
@ 2021-06-15  5:59 ` Trevor Saunders
  2021-06-15  6:50   ` Richard Biener
  2021-06-15  6:42 ` [PATCH 1/6] auto_vec copy/move improvements Richard Biener
  2021-06-15 16:18 ` [PATCH 1/6] " Martin Sebor
  6 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  5:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

This ensures the vector gets cleaned up by the caller when appropriate.

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

bootstrapped and regtested on x86_64-linux-gnu, ok?

gcc/ChangeLog:

	* dominance.c (get_dominated_to_depth): Return auto_vec<basic_block>.
	* dominance.h (get_dominated_to_depth): Likewise.
	(get_all_dominated_blocks): Likewise.
	* cfgcleanup.c (delete_unreachable_blocks): Adjust.
	* gcse.c (hoist_code): Likewise.
	* tree-cfg.c (remove_edge_and_dominated_blocks): Likewise.
	* tree-parloops.c (oacc_entry_exit_ok): Likewise.
	* tree-ssa-dce.c (eliminate_unnecessary_stmts): Likewise.
	* tree-ssa-phiprop.c (pass_phiprop::execute): Likewise.
---
 gcc/cfgcleanup.c       |  4 +---
 gcc/dominance.c        |  6 +++---
 gcc/dominance.h        |  8 ++++----
 gcc/gcse.c             | 13 +++++--------
 gcc/tree-cfg.c         |  3 +--
 gcc/tree-parloops.c    |  3 +--
 gcc/tree-ssa-dce.c     |  3 +--
 gcc/tree-ssa-phiprop.c |  7 +++----
 8 files changed, 19 insertions(+), 28 deletions(-)

diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 17edc4f37ad..7b1e1ba6e80 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -3027,7 +3027,7 @@ delete_unreachable_blocks (void)
 		delete_basic_block (b);
 	      else
 		{
-		  vec<basic_block> h
+		  auto_vec<basic_block> h
 		    = get_all_dominated_blocks (CDI_DOMINATORS, b);
 
 		  while (h.length ())
@@ -3040,8 +3040,6 @@ delete_unreachable_blocks (void)
 
 		      delete_basic_block (b);
 		    }
-
-		  h.release ();
 		}
 
 	      changed = true;
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 4943102ff1d..6a262ce8283 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -933,10 +933,10 @@ get_dominated_by_region (enum cdi_direction dir, basic_block *region,
    produce a vector containing all dominated blocks.  The vector will be sorted
    in preorder.  */
 
-vec<basic_block> 
+auto_vec<basic_block> 
 get_dominated_to_depth (enum cdi_direction dir, basic_block bb, int depth)
 {
-  vec<basic_block> bbs = vNULL;
+  auto_vec<basic_block> bbs;
   unsigned i;
   unsigned next_level_start;
 
@@ -965,7 +965,7 @@ get_dominated_to_depth (enum cdi_direction dir, basic_block bb, int depth)
 /* Returns the list of basic blocks including BB dominated by BB, in the
    direction DIR.  The vector will be sorted in preorder.  */
 
-vec<basic_block> 
+auto_vec<basic_block> 
 get_all_dominated_blocks (enum cdi_direction dir, basic_block bb)
 {
   return get_dominated_to_depth (dir, bb, 0);
diff --git a/gcc/dominance.h b/gcc/dominance.h
index c74ad297c6a..1a8c248ee98 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -50,10 +50,10 @@ extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
 extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
 							 basic_block *,
 							 unsigned);
-extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
-							basic_block, int);
-extern vec<basic_block> get_all_dominated_blocks (enum cdi_direction,
-							  basic_block);
+extern auto_vec<basic_block> get_dominated_to_depth (enum cdi_direction,
+						     basic_block, int);
+extern auto_vec<basic_block> get_all_dominated_blocks (enum cdi_direction,
+						       basic_block);
 extern void redirect_immediate_dominators (enum cdi_direction, basic_block,
 					   basic_block);
 extern basic_block nearest_common_dominator (enum cdi_direction,
diff --git a/gcc/gcse.c b/gcc/gcse.c
index 9114f30705e..ecf7e51aac5 100644
--- a/gcc/gcse.c
+++ b/gcc/gcse.c
@@ -3050,9 +3050,7 @@ static int
 hoist_code (void)
 {
   basic_block bb, dominated;
-  vec<basic_block> dom_tree_walk;
   unsigned int dom_tree_walk_index;
-  vec<basic_block> domby;
   unsigned int i, j, k;
   struct gcse_expr **index_map;
   struct gcse_expr *expr;
@@ -3106,15 +3104,16 @@ hoist_code (void)
   if (flag_ira_hoist_pressure)
     hoisted_bbs = BITMAP_ALLOC (NULL);
 
-  dom_tree_walk = get_all_dominated_blocks (CDI_DOMINATORS,
-					    ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb);
+  auto_vec<basic_block> dom_tree_walk
+  = get_all_dominated_blocks (CDI_DOMINATORS,
+			      ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb);
 
   /* Walk over each basic block looking for potentially hoistable
      expressions, nothing gets hoisted from the entry block.  */
   FOR_EACH_VEC_ELT (dom_tree_walk, dom_tree_walk_index, bb)
     {
-      domby = get_dominated_to_depth (CDI_DOMINATORS, bb,
-				      param_max_hoist_depth);
+      auto_vec<basic_block> domby
+	= get_dominated_to_depth (CDI_DOMINATORS, bb, param_max_hoist_depth);
 
       if (domby.length () == 0)
 	continue;
@@ -3315,10 +3314,8 @@ hoist_code (void)
 	      bitmap_clear (from_bbs);
 	    }
 	}
-      domby.release ();
     }
 
-  dom_tree_walk.release ();
   BITMAP_FREE (from_bbs);
   if (flag_ira_hoist_pressure)
     BITMAP_FREE (hoisted_bbs);
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c9403deed19..4c32f83257f 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -8683,7 +8683,6 @@ gimple_flow_call_edges_add (sbitmap blocks)
 void
 remove_edge_and_dominated_blocks (edge e)
 {
-  vec<basic_block> bbs_to_remove = vNULL;
   vec<basic_block> bbs_to_fix_dom = vNULL;
   edge f;
   edge_iterator ei;
@@ -8734,6 +8733,7 @@ remove_edge_and_dominated_blocks (edge e)
     }
 
   auto_bitmap df, df_idom;
+  auto_vec<basic_block> bbs_to_remove;
   if (none_removed)
     bitmap_set_bit (df_idom,
 		    get_immediate_dominator (CDI_DOMINATORS, e->dest)->index);
@@ -8800,7 +8800,6 @@ remove_edge_and_dominated_blocks (edge e)
 
   iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
 
-  bbs_to_remove.release ();
   bbs_to_fix_dom.release ();
 }
 
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index deff2d5e08b..fe1baef32a7 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -3949,7 +3949,7 @@ oacc_entry_exit_ok (class loop *loop,
 		    reduction_info_table_type *reduction_list)
 {
   basic_block *loop_bbs = get_loop_body_in_dom_order (loop);
-  vec<basic_block> region_bbs
+  auto_vec<basic_block> region_bbs
     = get_all_dominated_blocks (CDI_DOMINATORS, ENTRY_BLOCK_PTR_FOR_FN (cfun));
 
   bitmap in_loop_bbs = BITMAP_ALLOC (NULL);
@@ -3972,7 +3972,6 @@ oacc_entry_exit_ok (class loop *loop,
 	}
     }
 
-  region_bbs.release ();
   free (loop_bbs);
 
   BITMAP_FREE (in_loop_bbs);
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index def6ae69e24..e2d3b63a30c 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1275,7 +1275,6 @@ eliminate_unnecessary_stmts (void)
   gimple_stmt_iterator gsi, psi;
   gimple *stmt;
   tree call;
-  vec<basic_block> h;
   auto_vec<edge> to_remove_edges;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -1306,6 +1305,7 @@ eliminate_unnecessary_stmts (void)
 
      as desired.  */
   gcc_assert (dom_info_available_p (CDI_DOMINATORS));
+  auto_vec<basic_block> h;
   h = get_all_dominated_blocks (CDI_DOMINATORS,
 				single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
 
@@ -1460,7 +1460,6 @@ eliminate_unnecessary_stmts (void)
       something_changed |= remove_dead_phis (bb);
     }
 
-  h.release ();
 
   /* Since we don't track liveness of virtual PHI nodes, it is possible that we
      rendered some PHI nodes unreachable while they are still in use.
diff --git a/gcc/tree-ssa-phiprop.c b/gcc/tree-ssa-phiprop.c
index 64d6eda5f6c..78b0461c839 100644
--- a/gcc/tree-ssa-phiprop.c
+++ b/gcc/tree-ssa-phiprop.c
@@ -484,7 +484,6 @@ public:
 unsigned int
 pass_phiprop::execute (function *fun)
 {
-  vec<basic_block> bbs;
   struct phiprop_d *phivn;
   bool did_something = false;
   basic_block bb;
@@ -499,8 +498,9 @@ pass_phiprop::execute (function *fun)
   phivn = XCNEWVEC (struct phiprop_d, n);
 
   /* Walk the dominator tree in preorder.  */
-  bbs = get_all_dominated_blocks (CDI_DOMINATORS,
-				  single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
+  auto_vec<basic_block> bbs
+  = get_all_dominated_blocks (CDI_DOMINATORS,
+			      single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
   FOR_EACH_VEC_ELT (bbs, i, bb)
     {
       /* Since we're going to move dereferences across predecessor
@@ -514,7 +514,6 @@ pass_phiprop::execute (function *fun)
   if (did_something)
     gsi_commit_edge_inserts ();
 
-  bbs.release ();
   free (phivn);
 
   free_dominance_info (CDI_POST_DOMINATORS);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
                   ` (4 preceding siblings ...)
  2021-06-15  5:59 ` [PATCH 6/6] return auto_vec from more dominance functions Trevor Saunders
@ 2021-06-15  6:42 ` Richard Biener
  2021-06-15  7:04   ` Trevor Saunders
  2021-06-15 16:18 ` [PATCH 1/6] " Martin Sebor
  6 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-15  6:42 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 8:00 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> - Unfortunately using_auto_storage () needs to handle m_vec being null.
> - Handle self move of an auto_vec to itself.
> - punt on defining copy or move operators for auto_vec with inline storage,
>   until there is a need for them and we can decide what semantics they should
> have.

Hmm, that will make using of the CTORs/assignments in "infrastructure"
fragile if you consider

void foo(vec<T> src)
{
  auto_vec<T> dest (src);
  ...
}

bar()
{
   auto_vec<X> a;  // vs. auto_vec<X, 1>
   a.safe_push (X()); // "decays" both to vec<X>
   foo (a);
}

that is, it will eventually lead to hard to track down results?  I wonder if we
should add a m_has_auto_storage and assert that the incoming vector
does not instead of just asserting it doesn't use it to make the failure mode
at least not dependent so much on "input"?

FWIW I agree that we likely want to avoid the copy that would be required
when auto-storage is used - OTOH if we can be sure the lifetime of the
result cannot be extended beyond the auto-storage provider then copying
m_vec will likely just work?

Besides this detail the patch looks OK.

Thanks,
Richard.

> - Make sure auto_vec defines the classes move constructor and assignment
>   operator, as well as ones taking vec<T>, so the compiler does not generate
> them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> the ones taking vec<T> do not count as the classes move constructor or
> assignment operator, but we want them as well to assign a plain vec to a
> auto_vec.
> - Explicitly delete auto_vec's copy constructor and assignment operator.  This
>   prevents unintentional expenssive coppies of the vector and makes it clear
> when coppies are needed that that is what is intended.  When it is necessary to
> copy a vector copy () can be used.
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> bootstrapped and regtested on x86_64-linux-gnu, ok?
>
> gcc/ChangeLog:
>
>         * vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
>         (auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
>         constructor.
>         (auto_vec<T, 0>::operator=): Define move assignment and delete copy
>         assignment.
>         (auto_vec<T, N>::auto_vec): Delete copy and move constructors.
>         (auto_vec<T, N>::operator=): Delete copy and move assignment.
> ---
>  gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 40 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/vec.h b/gcc/vec.h
> index 193377cb69c..ceefa67e1ad 100644
> --- a/gcc/vec.h
> +++ b/gcc/vec.h
> @@ -1549,6 +1549,16 @@ public:
>      this->release ();
>    }
>
> +  // Punt for now on moving auto_vec with inline storage.  For now this
> +  // prevents people creating dangling pointers or the like.
> +  auto_vec (auto_vec &&) = delete;
> +  auto_vec &operator= (auto_vec &&) = delete;
> +
> +  // Punt for now on the inline storage, and you probably don't want to copy
> +  // vectors anyway.  If you really must copy a vector use copy ().
> +  auto_vec(const auto_vec &) = delete;
> +  auto_vec &operator= (const auto_vec &) = delete;
> +
>  private:
>    vec<T, va_heap, vl_embed> m_auto;
>    T m_data[MAX (N - 1, 1)];
> @@ -1570,14 +1580,43 @@ public:
>        this->m_vec = r.m_vec;
>        r.m_vec = NULL;
>      }
> +
> +  auto_vec (auto_vec<T> &&r)
> +    {
> +      gcc_assert (!r.using_auto_storage ());
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +    }
> +
>    auto_vec& operator= (vec<T, va_heap>&& r)
>      {
> +           if (this == &r)
> +                   return *this;
> +
> +      gcc_assert (!r.using_auto_storage ());
> +      this->release ();
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +      return *this;
> +    }
> +
> +  auto_vec& operator= (auto_vec<T> &&r)
> +    {
> +           if (this == &r)
> +                   return *this;
> +
>        gcc_assert (!r.using_auto_storage ());
>        this->release ();
>        this->m_vec = r.m_vec;
>        r.m_vec = NULL;
>        return *this;
>      }
> +
> +  // You probably don't want to copy a vector, so these are deleted to prevent
> +  // unintentional use.  If you really need a copy of the vectors contents you
> +  // can use copy ().
> +  auto_vec(const auto_vec &) = delete;
> +  auto_vec &operator= (const auto_vec &) = delete;
>  };
>
>
> @@ -2147,7 +2186,7 @@ template<typename T>
>  inline bool
>  vec<T, va_heap, vl_ptr>::using_auto_storage () const
>  {
> -  return m_vec->m_vecpfx.m_using_auto_storage;
> +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
>  }
>
>  /* Release VEC and call release of all element vectors.  */
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 2/6] return auto_vec from cgraph_node::collect_callers
  2021-06-15  5:59 ` [PATCH 2/6] return auto_vec from cgraph_node::collect_callers Trevor Saunders
@ 2021-06-15  6:45   ` Richard Biener
  0 siblings, 0 replies; 51+ messages in thread
From: Richard Biener @ 2021-06-15  6:45 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 8:00 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> This ensures the callers of collect_callers () take ownership of the vector and
> free it when appropriate.
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> bootstrapped and regtested on x86_64-linux-gnu, ok?

OK.

> gcc/ChangeLog:
>
>         * cgraph.c (cgraph_node::collect_callers): Return
>         auto_vec<cgraph_edge *>.
>         * cgraph.h (cgraph_node::collect_callers): Likewise.
>         * ipa-cp.c (create_specialized_node): Adjust.
>         (decide_about_value): Likewise.
>         (decide_whether_version_node): Likewise.
>         * ipa-sra.c (process_isra_node_results): Likewise.
> ---
>  gcc/cgraph.c  | 4 ++--
>  gcc/cgraph.h  | 2 +-
>  gcc/ipa-cp.c  | 7 +++----
>  gcc/ipa-sra.c | 2 +-
>  4 files changed, 7 insertions(+), 8 deletions(-)
>
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index d7c78d518bc..abe4e3ebfb3 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -3074,10 +3074,10 @@ collect_callers_of_node_1 (cgraph_node *node, void *data)
>  /* Collect all callers of cgraph_node and its aliases that are known to lead to
>     cgraph_node (i.e. are not overwritable).  */
>
> -vec<cgraph_edge *>
> +auto_vec<cgraph_edge *>
>  cgraph_node::collect_callers (void)
>  {
> -  vec<cgraph_edge *> redirect_callers = vNULL;
> +  auto_vec<cgraph_edge *> redirect_callers;
>    call_for_symbol_thunks_and_aliases (collect_callers_of_node_1,
>                                     &redirect_callers, false);
>    return redirect_callers;
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index 4a1f89920f5..9f4338fdf87 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -1139,7 +1139,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
>
>    /* Collect all callers of cgraph_node and its aliases that are known to lead
>       to NODE (i.e. are not overwritable) and that are not thunks.  */
> -  vec<cgraph_edge *> collect_callers (void);
> +  auto_vec<cgraph_edge *> collect_callers (void);
>
>    /* Remove all callers from the node.  */
>    void remove_callers (void);
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index 2cae69e5a1b..57c18af2bab 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -4527,7 +4527,7 @@ create_specialized_node (struct cgraph_node *node,
>                          vec<tree> known_csts,
>                          vec<ipa_polymorphic_call_context> known_contexts,
>                          struct ipa_agg_replacement_value *aggvals,
> -                        vec<cgraph_edge *> callers)
> +                        vec<cgraph_edge *> &callers)
>  {
>    ipa_node_params *new_info, *info = ipa_node_params_sum->get (node);
>    vec<ipa_replace_map *, va_gc> *replace_trees = NULL;
> @@ -4672,7 +4672,6 @@ create_specialized_node (struct cgraph_node *node,
>
>    ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, aggvals);
>
> -  callers.release ();
>    return new_node;
>  }
>
> @@ -5562,6 +5561,7 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset,
>                                                       offset, val->value));
>    val->spec_node = create_specialized_node (node, known_csts, known_contexts,
>                                             aggvals, callers);
> +  callers.release ();
>    overall_size += val->local_size_cost;
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      fprintf (dump_file, "     overall size reached %li\n",
> @@ -5638,7 +5638,7 @@ decide_whether_version_node (struct cgraph_node *node)
>         }
>
>        struct cgraph_node *clone;
> -      vec<cgraph_edge *> callers = node->collect_callers ();
> +      auto_vec<cgraph_edge *> callers = node->collect_callers ();
>
>        for (int i = callers.length () - 1; i >= 0; i--)
>         {
> @@ -5654,7 +5654,6 @@ decide_whether_version_node (struct cgraph_node *node)
>           /* If node is not called by anyone, or all its caller edges are
>              self-recursive, the node is not really in use, no need to do
>              cloning.  */
> -         callers.release ();
>           info->do_clone_for_all_contexts = false;
>           return ret;
>         }
> diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c
> index 3f90d4d81b6..3272daf56e4 100644
> --- a/gcc/ipa-sra.c
> +++ b/gcc/ipa-sra.c
> @@ -3755,7 +3755,7 @@ process_isra_node_results (cgraph_node *node,
>    unsigned &suffix_counter = clone_num_suffixes->get_or_insert (
>                                IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (
>                                  node->decl)));
> -  vec<cgraph_edge *> callers = node->collect_callers ();
> +  auto_vec<cgraph_edge *> callers = node->collect_callers ();
>    cgraph_node *new_node
>      = node->create_virtual_clone (callers, NULL, new_adjustments, "isra",
>                                   suffix_counter);
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 3/6] return auto_vec from get_loop_hot_path
  2021-06-15  5:59 ` [PATCH 3/6] return auto_vec from get_loop_hot_path Trevor Saunders
@ 2021-06-15  6:45   ` Richard Biener
  2021-06-17 13:48     ` Christophe Lyon
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-15  6:45 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 8:01 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> This ensures callers take ownership of the returned vector.
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> bootstrapped and regtested on x86_64-linux-gnu, ok?

OK.

> gcc/ChangeLog:
>
>         * cfgloop.h (get_loop_hot_path): Return auto_vec<basic_block>.
>         * cfgloopanal.c (get_loop_hot_path): Likewise.
>         * tree-ssa-loop-ivcanon.c (tree_estimate_loop_size): Likewise.
> ---
>  gcc/cfgloop.h               | 2 +-
>  gcc/cfgloopanal.c           | 2 +-
>  gcc/tree-ssa-loop-ivcanon.c | 5 ++---
>  3 files changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
> index 113241da130..5e699276c88 100644
> --- a/gcc/cfgloop.h
> +++ b/gcc/cfgloop.h
> @@ -840,7 +840,7 @@ enum
>
>  extern void doloop_optimize_loops (void);
>  extern void move_loop_invariants (void);
> -extern vec<basic_block> get_loop_hot_path (const class loop *loop);
> +extern auto_vec<basic_block> get_loop_hot_path (const class loop *loop);
>
>  /* Returns the outermost loop of the loop nest that contains LOOP.*/
>  static inline class loop *
> diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
> index d0eade3dd34..e7b7ae2163e 100644
> --- a/gcc/cfgloopanal.c
> +++ b/gcc/cfgloopanal.c
> @@ -500,7 +500,7 @@ single_likely_exit (class loop *loop, vec<edge> exits)
>     order against direction of edges from latch.  Specially, if
>     header != latch, latch is the 1-st block.  */
>
> -vec<basic_block>
> +auto_vec<basic_block>
>  get_loop_hot_path (const class loop *loop)
>  {
>    basic_block bb = loop->header;
> diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
> index 3f9e9d0869f..b1971f83544 100644
> --- a/gcc/tree-ssa-loop-ivcanon.c
> +++ b/gcc/tree-ssa-loop-ivcanon.c
> @@ -218,7 +218,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
>    gimple_stmt_iterator gsi;
>    unsigned int i;
>    bool after_exit;
> -  vec<basic_block> path = get_loop_hot_path (loop);
> +  auto_vec<basic_block> path = get_loop_hot_path (loop);
>
>    size->overall = 0;
>    size->eliminated_by_peeling = 0;
> @@ -342,7 +342,6 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
>               - size->last_iteration_eliminated_by_peeling) > upper_bound)
>             {
>                free (body);
> -             path.release ();
>               return true;
>             }
>         }
> @@ -379,7 +378,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
>             size->num_branches_on_hot_path++;
>         }
>      }
> -  path.release ();
> +
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      fprintf (dump_file, "size: %i-%i, last_iteration: %i-%i\n", size->overall,
>              size->eliminated_by_peeling, size->last_iteration,
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 4/6] return auto_vec from get_dominated_by
  2021-06-15  5:59 ` [PATCH 4/6] return auto_vec from get_dominated_by Trevor Saunders
@ 2021-06-15  6:46   ` Richard Biener
  2021-06-15 11:18     ` Bernhard Reutner-Fischer
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-15  6:46 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> bootstrapped and regtested on x86_64-linux-gnu, ok?

OK.

Thanks,
Richard.

> gcc/ChangeLog:
>
>         * dominance.c (get_dominated_by): Return auto_vec<basic_block>.
>         * dominance.h (get_dominated_by): Likewise.
>         * auto-profile.c (afdo_find_equiv_class): Adjust.
>         * cfgloopmanip.c (duplicate_loop_to_header_edge): Likewise.
>         * loop-unroll.c (unroll_loop_runtime_iterations): Likewise.
>         * tree-cfg.c (test_linear_chain): Likewise.
>         (test_diamond): Likewise.
> ---
>  gcc/auto-profile.c |  9 +++------
>  gcc/cfgloopmanip.c |  4 +---
>  gcc/dominance.c    |  6 +++---
>  gcc/dominance.h    |  2 +-
>  gcc/loop-unroll.c  | 12 +++---------
>  gcc/tree-cfg.c     | 14 ++++++--------
>  6 files changed, 17 insertions(+), 30 deletions(-)
>
> diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c
> index ed788dc06a8..43d6fa0b1f0 100644
> --- a/gcc/auto-profile.c
> +++ b/gcc/auto-profile.c
> @@ -1155,13 +1155,10 @@ afdo_find_equiv_class (bb_set *annotated_bb)
>
>    FOR_ALL_BB_FN (bb, cfun)
>    {
> -    vec<basic_block> dom_bbs;
> -
>      if (bb->aux != NULL)
>        continue;
>      bb->aux = bb;
> -    dom_bbs = get_dominated_by (CDI_DOMINATORS, bb);
> -    for (basic_block bb1 : dom_bbs)
> +    for (basic_block bb1 : get_dominated_by (CDI_DOMINATORS, bb))
>        if (bb1->aux == NULL && dominated_by_p (CDI_POST_DOMINATORS, bb, bb1)
>           && bb1->loop_father == bb->loop_father)
>         {
> @@ -1172,8 +1169,8 @@ afdo_find_equiv_class (bb_set *annotated_bb)
>               set_bb_annotated (bb, annotated_bb);
>             }
>         }
> -    dom_bbs = get_dominated_by (CDI_POST_DOMINATORS, bb);
> -    for (basic_block bb1 : dom_bbs)
> +
> +    for (basic_block bb1 : get_dominated_by (CDI_POST_DOMINATORS, bb))
>        if (bb1->aux == NULL && dominated_by_p (CDI_DOMINATORS, bb, bb1)
>           && bb1->loop_father == bb->loop_father)
>         {
> diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
> index 4a9ab74642c..e6df28036c4 100644
> --- a/gcc/cfgloopmanip.c
> +++ b/gcc/cfgloopmanip.c
> @@ -1414,13 +1414,12 @@ duplicate_loop_to_header_edge (class loop *loop, edge e,
>    for (i = 0; i < n; i++)
>      {
>        basic_block dominated, dom_bb;
> -      vec<basic_block> dom_bbs;
>        unsigned j;
>
>        bb = bbs[i];
>        bb->aux = 0;
>
> -      dom_bbs = get_dominated_by (CDI_DOMINATORS, bb);
> +      auto_vec<basic_block> dom_bbs = get_dominated_by (CDI_DOMINATORS, bb);
>        FOR_EACH_VEC_ELT (dom_bbs, j, dominated)
>         {
>           if (flow_bb_inside_loop_p (loop, dominated))
> @@ -1429,7 +1428,6 @@ duplicate_loop_to_header_edge (class loop *loop, edge e,
>                         CDI_DOMINATORS, first_active[i], first_active_latch);
>           set_immediate_dominator (CDI_DOMINATORS, dominated, dom_bb);
>         }
> -      dom_bbs.release ();
>      }
>    free (first_active);
>
> diff --git a/gcc/dominance.c b/gcc/dominance.c
> index 5fa172f3280..0e464cb7282 100644
> --- a/gcc/dominance.c
> +++ b/gcc/dominance.c
> @@ -883,17 +883,17 @@ set_immediate_dominator (enum cdi_direction dir, basic_block bb,
>
>  /* Returns the list of basic blocks immediately dominated by BB, in the
>     direction DIR.  */
> -vec<basic_block>
> +auto_vec<basic_block>
>  get_dominated_by (enum cdi_direction dir, basic_block bb)
>  {
>    unsigned int dir_index = dom_convert_dir_to_idx (dir);
>    struct et_node *node = bb->dom[dir_index], *son = node->son, *ason;
> -  vec<basic_block> bbs = vNULL;
> +  auto_vec<basic_block> bbs;
>
>    gcc_checking_assert (dom_computed[dir_index]);
>
>    if (!son)
> -    return vNULL;
> +    return bbs;
>
>    bbs.safe_push ((basic_block) son->data);
>    for (ason = son->right; ason != son; ason = ason->right)
> diff --git a/gcc/dominance.h b/gcc/dominance.h
> index 4eeac59fc59..515a369aacf 100644
> --- a/gcc/dominance.h
> +++ b/gcc/dominance.h
> @@ -46,7 +46,7 @@ extern void free_dominance_info_for_region (function *,
>  extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>  extern void set_immediate_dominator (enum cdi_direction, basic_block,
>                                      basic_block);
> -extern vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> +extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>  extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
>                                                          basic_block *,
>                                                          unsigned);
> diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
> index 8b6fcf5074c..66d93487e29 100644
> --- a/gcc/loop-unroll.c
> +++ b/gcc/loop-unroll.c
> @@ -884,7 +884,7 @@ unroll_loop_runtime_iterations (class loop *loop)
>  {
>    rtx old_niter, niter, tmp;
>    rtx_insn *init_code, *branch_code;
> -  unsigned i, j;
> +  unsigned i;
>    profile_probability p;
>    basic_block preheader, *body, swtch, ezc_swtch = NULL;
>    int may_exit_copy;
> @@ -908,15 +908,9 @@ unroll_loop_runtime_iterations (class loop *loop)
>    body = get_loop_body (loop);
>    for (i = 0; i < loop->num_nodes; i++)
>      {
> -      vec<basic_block> ldom;
> -      basic_block bb;
> -
> -      ldom = get_dominated_by (CDI_DOMINATORS, body[i]);
> -      FOR_EACH_VEC_ELT (ldom, j, bb)
> +      for (basic_block bb : get_dominated_by (CDI_DOMINATORS, body[i]))
>         if (!flow_bb_inside_loop_p (loop, bb))
>           dom_bbs.safe_push (bb);
> -
> -      ldom.release ();
>      }
>    free (body);
>
> @@ -1013,7 +1007,7 @@ unroll_loop_runtime_iterations (class loop *loop)
>        gcc_assert (ok);
>
>        /* Create item for switch.  */
> -      j = n_peel - i - (extra_zero_check ? 0 : 1);
> +      unsigned j = n_peel - i - (extra_zero_check ? 0 : 1);
>        p = profile_probability::always ().apply_scale (1, i + 2);
>
>        preheader = split_edge (loop_preheader_edge (loop));
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index 02256580c98..6bdd1a561fd 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -9917,22 +9917,20 @@ test_linear_chain ()
>    calculate_dominance_info (CDI_DOMINATORS);
>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
>    ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
> -  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
> +  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
>    ASSERT_EQ (1, dom_by_b.length ());
>    ASSERT_EQ (bb_c, dom_by_b[0]);
>    free_dominance_info (CDI_DOMINATORS);
> -  dom_by_b.release ();
>
>    /* Similarly for post-dominance: each BB in our chain is post-dominated
>       by the one after it.  */
>    calculate_dominance_info (CDI_POST_DOMINATORS);
>    ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
>    ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
> -  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
> +  auto_vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
>    ASSERT_EQ (1, postdom_by_b.length ());
>    ASSERT_EQ (bb_a, postdom_by_b[0]);
>    free_dominance_info (CDI_POST_DOMINATORS);
> -  postdom_by_b.release ();
>
>    pop_cfun ();
>  }
> @@ -9991,10 +9989,10 @@ test_diamond ()
>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
> -  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
> +  auto_vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS, bb_a);
>    ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
>    dom_by_a.release ();
> -  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
> +  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS, bb_b);
>    ASSERT_EQ (0, dom_by_b.length ());
>    dom_by_b.release ();
>    free_dominance_info (CDI_DOMINATORS);
> @@ -10004,10 +10002,10 @@ test_diamond ()
>    ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_a));
>    ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_b));
>    ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS, bb_c));
> -  vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
> +  auto_vec<basic_block> postdom_by_d = get_dominated_by (CDI_POST_DOMINATORS, bb_d);
>    ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order.  */
>    postdom_by_d.release ();
> -  vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
> +  auto_vec<basic_block> postdom_by_b = get_dominated_by (CDI_POST_DOMINATORS, bb_b);
>    ASSERT_EQ (0, postdom_by_b.length ());
>    postdom_by_b.release ();
>    free_dominance_info (CDI_POST_DOMINATORS);
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-15  5:59 ` [PATCH 5/6] make get_domminated_by_region return a auto_vec Trevor Saunders
@ 2021-06-15  6:49   ` Richard Biener
  2021-06-16 12:46     ` Richard Sandiford
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-15  6:49 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> bootstrapped and regtested on x86_64-linux-gnu, ok?

OK.

Btw, are "standard API" returns places we can use 'auto'?  That would avoid
excessive indent for

-  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
-                                    bbs.address (),
-                                    bbs.length ());
+  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
+                                                          bbs.address (),
+                                                          bbs.length ());

and just uses

  auto dom_bbs = get_dominated_by_region (...

Not asking you to do this, just a question for the audience.

Thanks,
Richard.

> gcc/ChangeLog:
>
>         * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
>         * dominance.h (get_dominated_by_region): Likewise.
>         * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
>         (gimple_duplicate_sese_tail): Likewise.
>         (move_sese_region_to_fn): Likewise.
> ---
>  gcc/dominance.c |  4 ++--
>  gcc/dominance.h |  2 +-
>  gcc/tree-cfg.c  | 18 +++++++-----------
>  3 files changed, 10 insertions(+), 14 deletions(-)
>
> diff --git a/gcc/dominance.c b/gcc/dominance.c
> index 0e464cb7282..4943102ff1d 100644
> --- a/gcc/dominance.c
> +++ b/gcc/dominance.c
> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
>     direction DIR) by some block between N_REGION ones stored in REGION,
>     except for blocks in the REGION itself.  */
>
> -vec<basic_block>
> +auto_vec<basic_block>
>  get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>                          unsigned n_region)
>  {
>    unsigned i;
>    basic_block dom;
> -  vec<basic_block> doms = vNULL;
> +  auto_vec<basic_block> doms;
>
>    for (i = 0; i < n_region; i++)
>      region[i]->flags |= BB_DUPLICATED;
> diff --git a/gcc/dominance.h b/gcc/dominance.h
> index 515a369aacf..c74ad297c6a 100644
> --- a/gcc/dominance.h
> +++ b/gcc/dominance.h
> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>  extern void set_immediate_dominator (enum cdi_direction, basic_block,
>                                      basic_block);
>  extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>                                                          basic_block *,
>                                                          unsigned);
>  extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index 6bdd1a561fd..c9403deed19 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>    bool free_region_copy = false, copying_header = false;
>    class loop *loop = entry->dest->loop_father;
>    edge exit_copy;
> -  vec<basic_block> doms = vNULL;
>    edge redirected;
>    profile_count total_count = profile_count::uninitialized ();
>    profile_count entry_count = profile_count::uninitialized ();
> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>
>    /* Record blocks outside the region that are dominated by something
>       inside.  */
> +  auto_vec<basic_block> doms;
>    if (update_dominance)
>      {
> -      doms.create (0);
>        doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>      }
>
> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>        set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
>        doms.safe_push (get_bb_original (entry->dest));
>        iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> -      doms.release ();
>      }
>
>    /* Add the other PHI node arguments.  */
> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>    class loop *loop = exit->dest->loop_father;
>    class loop *orig_loop = entry->dest->loop_father;
>    basic_block switch_bb, entry_bb, nentry_bb;
> -  vec<basic_block> doms;
>    profile_count total_count = profile_count::uninitialized (),
>                 exit_count = profile_count::uninitialized ();
>    edge exits[2], nexits[2], e;
> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>
>    /* Record blocks outside the region that are dominated by something
>       inside.  */
> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
> +                                                       n_region);
>
>    total_count = exit->src->count;
>    exit_count = exit->count ();
> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>    /* Anything that is outside of the region, but was dominated by something
>       inside needs to update dominance info.  */
>    iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> -  doms.release ();
>    /* Update the SSA web.  */
>    update_ssa (TODO_update_ssa);
>
> @@ -7567,7 +7564,7 @@ basic_block
>  move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>                         basic_block exit_bb, tree orig_block)
>  {
> -  vec<basic_block> bbs, dom_bbs;
> +  vec<basic_block> bbs;
>    basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
>    basic_block after, bb, *entry_pred, *exit_succ, abb;
>    struct function *saved_cfun = cfun;
> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>
>    /* The blocks that used to be dominated by something in BBS will now be
>       dominated by the new block.  */
> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> -                                    bbs.address (),
> -                                    bbs.length ());
> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> +                                                          bbs.address (),
> +                                                          bbs.length ());
>
>    /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
>       the predecessor edges to ENTRY_BB and the successor edges to
> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>    set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
>    FOR_EACH_VEC_ELT (dom_bbs, i, abb)
>      set_immediate_dominator (CDI_DOMINATORS, abb, bb);
> -  dom_bbs.release ();
>
>    if (exit_bb)
>      {
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 6/6] return auto_vec from more dominance functions
  2021-06-15  5:59 ` [PATCH 6/6] return auto_vec from more dominance functions Trevor Saunders
@ 2021-06-15  6:50   ` Richard Biener
  0 siblings, 0 replies; 51+ messages in thread
From: Richard Biener @ 2021-06-15  6:50 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 8:03 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> This ensures the vector gets cleaned up by the caller when appropriate.
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> bootstrapped and regtested on x86_64-linux-gnu, ok?

OK.

Richard.

> gcc/ChangeLog:
>
>         * dominance.c (get_dominated_to_depth): Return auto_vec<basic_block>.
>         * dominance.h (get_dominated_to_depth): Likewise.
>         (get_all_dominated_blocks): Likewise.
>         * cfgcleanup.c (delete_unreachable_blocks): Adjust.
>         * gcse.c (hoist_code): Likewise.
>         * tree-cfg.c (remove_edge_and_dominated_blocks): Likewise.
>         * tree-parloops.c (oacc_entry_exit_ok): Likewise.
>         * tree-ssa-dce.c (eliminate_unnecessary_stmts): Likewise.
>         * tree-ssa-phiprop.c (pass_phiprop::execute): Likewise.
> ---
>  gcc/cfgcleanup.c       |  4 +---
>  gcc/dominance.c        |  6 +++---
>  gcc/dominance.h        |  8 ++++----
>  gcc/gcse.c             | 13 +++++--------
>  gcc/tree-cfg.c         |  3 +--
>  gcc/tree-parloops.c    |  3 +--
>  gcc/tree-ssa-dce.c     |  3 +--
>  gcc/tree-ssa-phiprop.c |  7 +++----
>  8 files changed, 19 insertions(+), 28 deletions(-)
>
> diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
> index 17edc4f37ad..7b1e1ba6e80 100644
> --- a/gcc/cfgcleanup.c
> +++ b/gcc/cfgcleanup.c
> @@ -3027,7 +3027,7 @@ delete_unreachable_blocks (void)
>                 delete_basic_block (b);
>               else
>                 {
> -                 vec<basic_block> h
> +                 auto_vec<basic_block> h
>                     = get_all_dominated_blocks (CDI_DOMINATORS, b);
>
>                   while (h.length ())
> @@ -3040,8 +3040,6 @@ delete_unreachable_blocks (void)
>
>                       delete_basic_block (b);
>                     }
> -
> -                 h.release ();
>                 }
>
>               changed = true;
> diff --git a/gcc/dominance.c b/gcc/dominance.c
> index 4943102ff1d..6a262ce8283 100644
> --- a/gcc/dominance.c
> +++ b/gcc/dominance.c
> @@ -933,10 +933,10 @@ get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>     produce a vector containing all dominated blocks.  The vector will be sorted
>     in preorder.  */
>
> -vec<basic_block>
> +auto_vec<basic_block>
>  get_dominated_to_depth (enum cdi_direction dir, basic_block bb, int depth)
>  {
> -  vec<basic_block> bbs = vNULL;
> +  auto_vec<basic_block> bbs;
>    unsigned i;
>    unsigned next_level_start;
>
> @@ -965,7 +965,7 @@ get_dominated_to_depth (enum cdi_direction dir, basic_block bb, int depth)
>  /* Returns the list of basic blocks including BB dominated by BB, in the
>     direction DIR.  The vector will be sorted in preorder.  */
>
> -vec<basic_block>
> +auto_vec<basic_block>
>  get_all_dominated_blocks (enum cdi_direction dir, basic_block bb)
>  {
>    return get_dominated_to_depth (dir, bb, 0);
> diff --git a/gcc/dominance.h b/gcc/dominance.h
> index c74ad297c6a..1a8c248ee98 100644
> --- a/gcc/dominance.h
> +++ b/gcc/dominance.h
> @@ -50,10 +50,10 @@ extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>  extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>                                                          basic_block *,
>                                                          unsigned);
> -extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> -                                                       basic_block, int);
> -extern vec<basic_block> get_all_dominated_blocks (enum cdi_direction,
> -                                                         basic_block);
> +extern auto_vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> +                                                    basic_block, int);
> +extern auto_vec<basic_block> get_all_dominated_blocks (enum cdi_direction,
> +                                                      basic_block);
>  extern void redirect_immediate_dominators (enum cdi_direction, basic_block,
>                                            basic_block);
>  extern basic_block nearest_common_dominator (enum cdi_direction,
> diff --git a/gcc/gcse.c b/gcc/gcse.c
> index 9114f30705e..ecf7e51aac5 100644
> --- a/gcc/gcse.c
> +++ b/gcc/gcse.c
> @@ -3050,9 +3050,7 @@ static int
>  hoist_code (void)
>  {
>    basic_block bb, dominated;
> -  vec<basic_block> dom_tree_walk;
>    unsigned int dom_tree_walk_index;
> -  vec<basic_block> domby;
>    unsigned int i, j, k;
>    struct gcse_expr **index_map;
>    struct gcse_expr *expr;
> @@ -3106,15 +3104,16 @@ hoist_code (void)
>    if (flag_ira_hoist_pressure)
>      hoisted_bbs = BITMAP_ALLOC (NULL);
>
> -  dom_tree_walk = get_all_dominated_blocks (CDI_DOMINATORS,
> -                                           ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb);
> +  auto_vec<basic_block> dom_tree_walk
> +  = get_all_dominated_blocks (CDI_DOMINATORS,
> +                             ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb);
>
>    /* Walk over each basic block looking for potentially hoistable
>       expressions, nothing gets hoisted from the entry block.  */
>    FOR_EACH_VEC_ELT (dom_tree_walk, dom_tree_walk_index, bb)
>      {
> -      domby = get_dominated_to_depth (CDI_DOMINATORS, bb,
> -                                     param_max_hoist_depth);
> +      auto_vec<basic_block> domby
> +       = get_dominated_to_depth (CDI_DOMINATORS, bb, param_max_hoist_depth);
>
>        if (domby.length () == 0)
>         continue;
> @@ -3315,10 +3314,8 @@ hoist_code (void)
>               bitmap_clear (from_bbs);
>             }
>         }
> -      domby.release ();
>      }
>
> -  dom_tree_walk.release ();
>    BITMAP_FREE (from_bbs);
>    if (flag_ira_hoist_pressure)
>      BITMAP_FREE (hoisted_bbs);
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index c9403deed19..4c32f83257f 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -8683,7 +8683,6 @@ gimple_flow_call_edges_add (sbitmap blocks)
>  void
>  remove_edge_and_dominated_blocks (edge e)
>  {
> -  vec<basic_block> bbs_to_remove = vNULL;
>    vec<basic_block> bbs_to_fix_dom = vNULL;
>    edge f;
>    edge_iterator ei;
> @@ -8734,6 +8733,7 @@ remove_edge_and_dominated_blocks (edge e)
>      }
>
>    auto_bitmap df, df_idom;
> +  auto_vec<basic_block> bbs_to_remove;
>    if (none_removed)
>      bitmap_set_bit (df_idom,
>                     get_immediate_dominator (CDI_DOMINATORS, e->dest)->index);
> @@ -8800,7 +8800,6 @@ remove_edge_and_dominated_blocks (edge e)
>
>    iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
>
> -  bbs_to_remove.release ();
>    bbs_to_fix_dom.release ();
>  }
>
> diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
> index deff2d5e08b..fe1baef32a7 100644
> --- a/gcc/tree-parloops.c
> +++ b/gcc/tree-parloops.c
> @@ -3949,7 +3949,7 @@ oacc_entry_exit_ok (class loop *loop,
>                     reduction_info_table_type *reduction_list)
>  {
>    basic_block *loop_bbs = get_loop_body_in_dom_order (loop);
> -  vec<basic_block> region_bbs
> +  auto_vec<basic_block> region_bbs
>      = get_all_dominated_blocks (CDI_DOMINATORS, ENTRY_BLOCK_PTR_FOR_FN (cfun));
>
>    bitmap in_loop_bbs = BITMAP_ALLOC (NULL);
> @@ -3972,7 +3972,6 @@ oacc_entry_exit_ok (class loop *loop,
>         }
>      }
>
> -  region_bbs.release ();
>    free (loop_bbs);
>
>    BITMAP_FREE (in_loop_bbs);
> diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
> index def6ae69e24..e2d3b63a30c 100644
> --- a/gcc/tree-ssa-dce.c
> +++ b/gcc/tree-ssa-dce.c
> @@ -1275,7 +1275,6 @@ eliminate_unnecessary_stmts (void)
>    gimple_stmt_iterator gsi, psi;
>    gimple *stmt;
>    tree call;
> -  vec<basic_block> h;
>    auto_vec<edge> to_remove_edges;
>
>    if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -1306,6 +1305,7 @@ eliminate_unnecessary_stmts (void)
>
>       as desired.  */
>    gcc_assert (dom_info_available_p (CDI_DOMINATORS));
> +  auto_vec<basic_block> h;
>    h = get_all_dominated_blocks (CDI_DOMINATORS,
>                                 single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
>
> @@ -1460,7 +1460,6 @@ eliminate_unnecessary_stmts (void)
>        something_changed |= remove_dead_phis (bb);
>      }
>
> -  h.release ();
>
>    /* Since we don't track liveness of virtual PHI nodes, it is possible that we
>       rendered some PHI nodes unreachable while they are still in use.
> diff --git a/gcc/tree-ssa-phiprop.c b/gcc/tree-ssa-phiprop.c
> index 64d6eda5f6c..78b0461c839 100644
> --- a/gcc/tree-ssa-phiprop.c
> +++ b/gcc/tree-ssa-phiprop.c
> @@ -484,7 +484,6 @@ public:
>  unsigned int
>  pass_phiprop::execute (function *fun)
>  {
> -  vec<basic_block> bbs;
>    struct phiprop_d *phivn;
>    bool did_something = false;
>    basic_block bb;
> @@ -499,8 +498,9 @@ pass_phiprop::execute (function *fun)
>    phivn = XCNEWVEC (struct phiprop_d, n);
>
>    /* Walk the dominator tree in preorder.  */
> -  bbs = get_all_dominated_blocks (CDI_DOMINATORS,
> -                                 single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
> +  auto_vec<basic_block> bbs
> +  = get_all_dominated_blocks (CDI_DOMINATORS,
> +                             single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
>    FOR_EACH_VEC_ELT (bbs, i, bb)
>      {
>        /* Since we're going to move dereferences across predecessor
> @@ -514,7 +514,6 @@ pass_phiprop::execute (function *fun)
>    if (did_something)
>      gsi_commit_edge_inserts ();
>
> -  bbs.release ();
>    free (phivn);
>
>    free_dominance_info (CDI_POST_DOMINATORS);
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15  6:42 ` [PATCH 1/6] auto_vec copy/move improvements Richard Biener
@ 2021-06-15  7:04   ` Trevor Saunders
  2021-06-15  7:11     ` Richard Biener
  0 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  7:04 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 08:42:35AM +0200, Richard Biener wrote:
> On Tue, Jun 15, 2021 at 8:00 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >
> > - Unfortunately using_auto_storage () needs to handle m_vec being null.
> > - Handle self move of an auto_vec to itself.
> > - punt on defining copy or move operators for auto_vec with inline storage,
> >   until there is a need for them and we can decide what semantics they should
> > have.
> 
> Hmm, that will make using of the CTORs/assignments in "infrastructure"
> fragile if you consider

It definitely restricts what you can do with auto_vec with inline
storage.  However that restriction is preexisting, and this just turns
it into a assertion failure rather than memory corruption.  So its
definitely not the final answer, but its better than what we have today
I believe, and leaves options open for when this has a user, as this
bootstraps nothing needs it today.

> void foo(vec<T> src)
> {
>   auto_vec<T> dest (src);
>   ...
> }
> 
> bar()
> {
>    auto_vec<X> a;  // vs. auto_vec<X, 1>
>    a.safe_push (X()); // "decays" both to vec<X>
>    foo (a);
> }
> 
> that is, it will eventually lead to hard to track down results?  I wonder if we
> should add a m_has_auto_storage and assert that the incoming vector
> does not instead of just asserting it doesn't use it to make the failure mode
> at least not dependent so much on "input"?

I'm not sure I follow this part.  I think example you are thinking of is
something like this
void foo(auto_vec<x> &&src)
{
	auto_vec<x> dst(src);
	...
}

And then some caller who wants to use inline storage
void bar()
{
	auto-vec<x> a;
	a.safe_push (x ());
	foo (a);
}

Which today I believe ends up with dst containing a pointer to part of
a, which is bogus and probably going to lead to memory corruption.
After this patch we get an assert when we try and create dst because
src.using_auto_storage () is true.  That's certainly not ideal, but
better than what we have today.

> FWIW I agree that we likely want to avoid the copy that would be required
> when auto-storage is used - OTOH if we can be sure the lifetime of the
> result cannot be extended beyond the auto-storage provider then copying
> m_vec will likely just work?

If I understand the case your thinking of correctly my question would be
why are you making a copy at all then, rather than passing a pointer or
reference to the original vector? I would think the two cases where a
copy may make sense is when the new object outlives the source, or when
you wish to mutate the new object leaving the original one unchanged,
for either of those copying the m_vec pointer so it points into the
original object wouldn't work?

> Besides this detail the patch looks OK.

I think there's some risk of shooting yourself in the foot with the
inline storage version as it is today, but I'd be ok with spliting that
part out into a separate patch and only adjusting the version with no
inline storage here.  I believe that's enough for the rest of the series
to work properly.

Thanks!

Trev

> 
> Thanks,
> Richard.
> 
> > - Make sure auto_vec defines the classes move constructor and assignment
> >   operator, as well as ones taking vec<T>, so the compiler does not generate
> > them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> > the ones taking vec<T> do not count as the classes move constructor or
> > assignment operator, but we want them as well to assign a plain vec to a
> > auto_vec.
> > - Explicitly delete auto_vec's copy constructor and assignment operator.  This
> >   prevents unintentional expenssive coppies of the vector and makes it clear
> > when coppies are needed that that is what is intended.  When it is necessary to
> > copy a vector copy () can be used.
> >
> > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> >
> > bootstrapped and regtested on x86_64-linux-gnu, ok?
> >
> > gcc/ChangeLog:
> >
> >         * vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
> >         (auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
> >         constructor.
> >         (auto_vec<T, 0>::operator=): Define move assignment and delete copy
> >         assignment.
> >         (auto_vec<T, N>::auto_vec): Delete copy and move constructors.
> >         (auto_vec<T, N>::operator=): Delete copy and move assignment.
> > ---
> >  gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 40 insertions(+), 1 deletion(-)
> >
> > diff --git a/gcc/vec.h b/gcc/vec.h
> > index 193377cb69c..ceefa67e1ad 100644
> > --- a/gcc/vec.h
> > +++ b/gcc/vec.h
> > @@ -1549,6 +1549,16 @@ public:
> >      this->release ();
> >    }
> >
> > +  // Punt for now on moving auto_vec with inline storage.  For now this
> > +  // prevents people creating dangling pointers or the like.
> > +  auto_vec (auto_vec &&) = delete;
> > +  auto_vec &operator= (auto_vec &&) = delete;
> > +
> > +  // Punt for now on the inline storage, and you probably don't want to copy
> > +  // vectors anyway.  If you really must copy a vector use copy ().
> > +  auto_vec(const auto_vec &) = delete;
> > +  auto_vec &operator= (const auto_vec &) = delete;
> > +
> >  private:
> >    vec<T, va_heap, vl_embed> m_auto;
> >    T m_data[MAX (N - 1, 1)];
> > @@ -1570,14 +1580,43 @@ public:
> >        this->m_vec = r.m_vec;
> >        r.m_vec = NULL;
> >      }
> > +
> > +  auto_vec (auto_vec<T> &&r)
> > +    {
> > +      gcc_assert (!r.using_auto_storage ());
> > +      this->m_vec = r.m_vec;
> > +      r.m_vec = NULL;
> > +    }
> > +
> >    auto_vec& operator= (vec<T, va_heap>&& r)
> >      {
> > +           if (this == &r)
> > +                   return *this;
> > +
> > +      gcc_assert (!r.using_auto_storage ());
> > +      this->release ();
> > +      this->m_vec = r.m_vec;
> > +      r.m_vec = NULL;
> > +      return *this;
> > +    }
> > +
> > +  auto_vec& operator= (auto_vec<T> &&r)
> > +    {
> > +           if (this == &r)
> > +                   return *this;
> > +
> >        gcc_assert (!r.using_auto_storage ());
> >        this->release ();
> >        this->m_vec = r.m_vec;
> >        r.m_vec = NULL;
> >        return *this;
> >      }
> > +
> > +  // You probably don't want to copy a vector, so these are deleted to prevent
> > +  // unintentional use.  If you really need a copy of the vectors contents you
> > +  // can use copy ().
> > +  auto_vec(const auto_vec &) = delete;
> > +  auto_vec &operator= (const auto_vec &) = delete;
> >  };
> >
> >
> > @@ -2147,7 +2186,7 @@ template<typename T>
> >  inline bool
> >  vec<T, va_heap, vl_ptr>::using_auto_storage () const
> >  {
> > -  return m_vec->m_vecpfx.m_using_auto_storage;
> > +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
> >  }
> >
> >  /* Release VEC and call release of all element vectors.  */
> > --
> > 2.20.1
> >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15  7:04   ` Trevor Saunders
@ 2021-06-15  7:11     ` Richard Biener
  2021-06-15  7:57       ` Trevor Saunders
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-15  7:11 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 9:04 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> On Tue, Jun 15, 2021 at 08:42:35AM +0200, Richard Biener wrote:
> > On Tue, Jun 15, 2021 at 8:00 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > >
> > > - Unfortunately using_auto_storage () needs to handle m_vec being null.
> > > - Handle self move of an auto_vec to itself.
> > > - punt on defining copy or move operators for auto_vec with inline storage,
> > >   until there is a need for them and we can decide what semantics they should
> > > have.
> >
> > Hmm, that will make using of the CTORs/assignments in "infrastructure"
> > fragile if you consider
>
> It definitely restricts what you can do with auto_vec with inline
> storage.  However that restriction is preexisting, and this just turns
> it into a assertion failure rather than memory corruption.

You mean the CTOR from vec<> is auto-generated at the moment?

>  So its
> definitely not the final answer, but its better than what we have today
> I believe, and leaves options open for when this has a user, as this
> bootstraps nothing needs it today.
>
> > void foo(vec<T> src)
> > {
> >   auto_vec<T> dest (src);
> >   ...
> > }
> >
> > bar()
> > {
> >    auto_vec<X> a;  // vs. auto_vec<X, 1>
> >    a.safe_push (X()); // "decays" both to vec<X>
> >    foo (a);
> > }
> >
> > that is, it will eventually lead to hard to track down results?  I wonder if we
> > should add a m_has_auto_storage and assert that the incoming vector
> > does not instead of just asserting it doesn't use it to make the failure mode
> > at least not dependent so much on "input"?
>
> I'm not sure I follow this part.  I think example you are thinking of is
> something like this
> void foo(auto_vec<x> &&src)
> {
>         auto_vec<x> dst(src);
>         ...
> }
>
> And then some caller who wants to use inline storage
> void bar()
> {
>         auto-vec<x> a;
>         a.safe_push (x ());
>         foo (a);
> }
>
> Which today I believe ends up with dst containing a pointer to part of
> a, which is bogus and probably going to lead to memory corruption.
> After this patch we get an assert when we try and create dst because
> src.using_auto_storage () is true.  That's certainly not ideal, but
> better than what we have today.

OK, so I guess one useful way to use the CTOR is when transfering vector
ownership to a function, but I expected that

void foo (auto_vec<x> mine)
{
}

would already do the trick here, destroying 'mine' when foo exits?

> > FWIW I agree that we likely want to avoid the copy that would be required
> > when auto-storage is used - OTOH if we can be sure the lifetime of the
> > result cannot be extended beyond the auto-storage provider then copying
> > m_vec will likely just work?
>
> If I understand the case your thinking of correctly my question would be
> why are you making a copy at all then, rather than passing a pointer or
> reference to the original vector? I would think the two cases where a
> copy may make sense is when the new object outlives the source, or when
> you wish to mutate the new object leaving the original one unchanged,
> for either of those copying the m_vec pointer so it points into the
> original object wouldn't work?

vec<> is used as (const) "reference" in a lot of places, avoiding the
extra indirection that happens when using const vec<> & since passing
its sole pointer member is cheap.  (maybe const vec<> should be passed
in all those cases though)

> > Besides this detail the patch looks OK.
>
> I think there's some risk of shooting yourself in the foot with the
> inline storage version as it is today, but I'd be ok with spliting that
> part out into a separate patch and only adjusting the version with no
> inline storage here.  I believe that's enough for the rest of the series
> to work properly.

I trust you with the change but I'm not too familiar with C++ to
trust myself with a final OK, so if you can split out this part and
post it separately that would make me more comfortable.

Thanks,
Richard.

>
> Thanks!
>
> Trev
>
> >
> > Thanks,
> > Richard.
> >
> > > - Make sure auto_vec defines the classes move constructor and assignment
> > >   operator, as well as ones taking vec<T>, so the compiler does not generate
> > > them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> > > the ones taking vec<T> do not count as the classes move constructor or
> > > assignment operator, but we want them as well to assign a plain vec to a
> > > auto_vec.
> > > - Explicitly delete auto_vec's copy constructor and assignment operator.  This
> > >   prevents unintentional expenssive coppies of the vector and makes it clear
> > > when coppies are needed that that is what is intended.  When it is necessary to
> > > copy a vector copy () can be used.
> > >
> > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > >
> > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > >
> > > gcc/ChangeLog:
> > >
> > >         * vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
> > >         (auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
> > >         constructor.
> > >         (auto_vec<T, 0>::operator=): Define move assignment and delete copy
> > >         assignment.
> > >         (auto_vec<T, N>::auto_vec): Delete copy and move constructors.
> > >         (auto_vec<T, N>::operator=): Delete copy and move assignment.
> > > ---
> > >  gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 40 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/gcc/vec.h b/gcc/vec.h
> > > index 193377cb69c..ceefa67e1ad 100644
> > > --- a/gcc/vec.h
> > > +++ b/gcc/vec.h
> > > @@ -1549,6 +1549,16 @@ public:
> > >      this->release ();
> > >    }
> > >
> > > +  // Punt for now on moving auto_vec with inline storage.  For now this
> > > +  // prevents people creating dangling pointers or the like.
> > > +  auto_vec (auto_vec &&) = delete;
> > > +  auto_vec &operator= (auto_vec &&) = delete;
> > > +
> > > +  // Punt for now on the inline storage, and you probably don't want to copy
> > > +  // vectors anyway.  If you really must copy a vector use copy ().
> > > +  auto_vec(const auto_vec &) = delete;
> > > +  auto_vec &operator= (const auto_vec &) = delete;
> > > +
> > >  private:
> > >    vec<T, va_heap, vl_embed> m_auto;
> > >    T m_data[MAX (N - 1, 1)];
> > > @@ -1570,14 +1580,43 @@ public:
> > >        this->m_vec = r.m_vec;
> > >        r.m_vec = NULL;
> > >      }
> > > +
> > > +  auto_vec (auto_vec<T> &&r)
> > > +    {
> > > +      gcc_assert (!r.using_auto_storage ());
> > > +      this->m_vec = r.m_vec;
> > > +      r.m_vec = NULL;
> > > +    }
> > > +
> > >    auto_vec& operator= (vec<T, va_heap>&& r)
> > >      {
> > > +           if (this == &r)
> > > +                   return *this;
> > > +
> > > +      gcc_assert (!r.using_auto_storage ());
> > > +      this->release ();
> > > +      this->m_vec = r.m_vec;
> > > +      r.m_vec = NULL;
> > > +      return *this;
> > > +    }
> > > +
> > > +  auto_vec& operator= (auto_vec<T> &&r)
> > > +    {
> > > +           if (this == &r)
> > > +                   return *this;
> > > +
> > >        gcc_assert (!r.using_auto_storage ());
> > >        this->release ();
> > >        this->m_vec = r.m_vec;
> > >        r.m_vec = NULL;
> > >        return *this;
> > >      }
> > > +
> > > +  // You probably don't want to copy a vector, so these are deleted to prevent
> > > +  // unintentional use.  If you really need a copy of the vectors contents you
> > > +  // can use copy ().
> > > +  auto_vec(const auto_vec &) = delete;
> > > +  auto_vec &operator= (const auto_vec &) = delete;
> > >  };
> > >
> > >
> > > @@ -2147,7 +2186,7 @@ template<typename T>
> > >  inline bool
> > >  vec<T, va_heap, vl_ptr>::using_auto_storage () const
> > >  {
> > > -  return m_vec->m_vecpfx.m_using_auto_storage;
> > > +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
> > >  }
> > >
> > >  /* Release VEC and call release of all element vectors.  */
> > > --
> > > 2.20.1
> > >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15  7:11     ` Richard Biener
@ 2021-06-15  7:57       ` Trevor Saunders
  2021-06-15  9:36         ` Richard Biener
  0 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-15  7:57 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 09:11:52AM +0200, Richard Biener wrote:
> On Tue, Jun 15, 2021 at 9:04 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >
> > On Tue, Jun 15, 2021 at 08:42:35AM +0200, Richard Biener wrote:
> > > On Tue, Jun 15, 2021 at 8:00 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > > >
> > > > - Unfortunately using_auto_storage () needs to handle m_vec being null.
> > > > - Handle self move of an auto_vec to itself.
> > > > - punt on defining copy or move operators for auto_vec with inline storage,
> > > >   until there is a need for them and we can decide what semantics they should
> > > > have.
> > >
> > > Hmm, that will make using of the CTORs/assignments in "infrastructure"
> > > fragile if you consider
> >
> > It definitely restricts what you can do with auto_vec with inline
> > storage.  However that restriction is preexisting, and this just turns
> > it into a assertion failure rather than memory corruption.
> 
> You mean the CTOR from vec<> is auto-generated at the moment?

I actually had to test this to be sure.  It depends, the constructor to
copy auto_vec<T, N> to auto_vec<T, N> is generated and just coppies the
representation, its basically memcpy, so that doesn't work properly.  If
you attempt to copy auto_vec<T, P> to auto_vec<T, Q> the compiler will
already refuse to generate the necessary constructor since the fields
don't match up, and so the case where the amount of inline storage is
different already fails to compile.

> >  So its
> > definitely not the final answer, but its better than what we have today
> > I believe, and leaves options open for when this has a user, as this
> > bootstraps nothing needs it today.
> >
> > > void foo(vec<T> src)
> > > {
> > >   auto_vec<T> dest (src);
> > >   ...
> > > }
> > >
> > > bar()
> > > {
> > >    auto_vec<X> a;  // vs. auto_vec<X, 1>
> > >    a.safe_push (X()); // "decays" both to vec<X>
> > >    foo (a);
> > > }
> > >
> > > that is, it will eventually lead to hard to track down results?  I wonder if we
> > > should add a m_has_auto_storage and assert that the incoming vector
> > > does not instead of just asserting it doesn't use it to make the failure mode
> > > at least not dependent so much on "input"?
> >
> > I'm not sure I follow this part.  I think example you are thinking of is
> > something like this
> > void foo(auto_vec<x> &&src)
> > {
> >         auto_vec<x> dst(src);
> >         ...
> > }
> >
> > And then some caller who wants to use inline storage
> > void bar()
> > {
> >         auto-vec<x> a;
> >         a.safe_push (x ());
> >         foo (a);
> > }
> >
> > Which today I believe ends up with dst containing a pointer to part of
> > a, which is bogus and probably going to lead to memory corruption.
> > After this patch we get an assert when we try and create dst because
> > src.using_auto_storage () is true.  That's certainly not ideal, but
> > better than what we have today.
> 
> OK, so I guess one useful way to use the CTOR is when transfering vector
> ownership to a function, but I expected that
> 
> void foo (auto_vec<x> mine)
> {
> }
> 
> would already do the trick here, destroying 'mine' when foo exits?

Yes, after this patch you will have to move the vector into the argument
of the function with something like foo (move (freeby));.  Today that
doesn't work because you get an implicitly generated copy constructor
for auto_vec<T> that just coppies the pointer producing an auto_vec in
the callie and the caller that both think they own the same vector.

> > > FWIW I agree that we likely want to avoid the copy that would be required
> > > when auto-storage is used - OTOH if we can be sure the lifetime of the
> > > result cannot be extended beyond the auto-storage provider then copying
> > > m_vec will likely just work?
> >
> > If I understand the case your thinking of correctly my question would be
> > why are you making a copy at all then, rather than passing a pointer or
> > reference to the original vector? I would think the two cases where a
> > copy may make sense is when the new object outlives the source, or when
> > you wish to mutate the new object leaving the original one unchanged,
> > for either of those copying the m_vec pointer so it points into the
> > original object wouldn't work?
> 
> vec<> is used as (const) "reference" in a lot of places, avoiding the
> extra indirection that happens when using const vec<> & since passing
> its sole pointer member is cheap.  (maybe const vec<> should be passed
> in all those cases though)

Certainly the C++ way of doing things is to pass const vec<T> & and hope
the abstraction gets optimized out.  Its unfortunate, but its also not
really clear how else you'd mark that your giving the called function a
possibly const borrowed view of the vector.  I suppose you can have yet
another type that you use in arguments and removes the layer of
abstraction when the called function doesn't need to mutate the vector.
Certainly if the call can mutate the vector you need to, and already do,
pass a vec<>& or vec<>*, and its just the case of functions that only
read the vector where this optimization can apply.  I find myself
wondering how much this manual optimization matters, or if at this point
lto bootstrapping production compilers takes care of this for us? That's
a question I don't think I have the data to answer.

> > > Besides this detail the patch looks OK.
> >
> > I think there's some risk of shooting yourself in the foot with the
> > inline storage version as it is today, but I'd be ok with spliting that
> > part out into a separate patch and only adjusting the version with no
> > inline storage here.  I believe that's enough for the rest of the series
> > to work properly.
> 
> I trust you with the change but I'm not too familiar with C++ to
> trust myself with a final OK, so if you can split out this part and
> post it separately that would make me more comfortable.

Sure, just to be clear you mean the deleted constructors and assignment
operators for the version of auto_vec<> with inline storage? I'll split
that out and make sure the series still bootstrapps and tests ok without
it, I really think it should  but might as well confirm.

Trev

> 
> Thanks,
> Richard.
> 
> >
> > Thanks!
> >
> > Trev
> >
> > >
> > > Thanks,
> > > Richard.
> > >
> > > > - Make sure auto_vec defines the classes move constructor and assignment
> > > >   operator, as well as ones taking vec<T>, so the compiler does not generate
> > > > them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> > > > the ones taking vec<T> do not count as the classes move constructor or
> > > > assignment operator, but we want them as well to assign a plain vec to a
> > > > auto_vec.
> > > > - Explicitly delete auto_vec's copy constructor and assignment operator.  This
> > > >   prevents unintentional expenssive coppies of the vector and makes it clear
> > > > when coppies are needed that that is what is intended.  When it is necessary to
> > > > copy a vector copy () can be used.
> > > >
> > > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > > >
> > > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > > >
> > > > gcc/ChangeLog:
> > > >
> > > >         * vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
> > > >         (auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
> > > >         constructor.
> > > >         (auto_vec<T, 0>::operator=): Define move assignment and delete copy
> > > >         assignment.
> > > >         (auto_vec<T, N>::auto_vec): Delete copy and move constructors.
> > > >         (auto_vec<T, N>::operator=): Delete copy and move assignment.
> > > > ---
> > > >  gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
> > > >  1 file changed, 40 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/gcc/vec.h b/gcc/vec.h
> > > > index 193377cb69c..ceefa67e1ad 100644
> > > > --- a/gcc/vec.h
> > > > +++ b/gcc/vec.h
> > > > @@ -1549,6 +1549,16 @@ public:
> > > >      this->release ();
> > > >    }
> > > >
> > > > +  // Punt for now on moving auto_vec with inline storage.  For now this
> > > > +  // prevents people creating dangling pointers or the like.
> > > > +  auto_vec (auto_vec &&) = delete;
> > > > +  auto_vec &operator= (auto_vec &&) = delete;
> > > > +
> > > > +  // Punt for now on the inline storage, and you probably don't want to copy
> > > > +  // vectors anyway.  If you really must copy a vector use copy ().
> > > > +  auto_vec(const auto_vec &) = delete;
> > > > +  auto_vec &operator= (const auto_vec &) = delete;
> > > > +
> > > >  private:
> > > >    vec<T, va_heap, vl_embed> m_auto;
> > > >    T m_data[MAX (N - 1, 1)];
> > > > @@ -1570,14 +1580,43 @@ public:
> > > >        this->m_vec = r.m_vec;
> > > >        r.m_vec = NULL;
> > > >      }
> > > > +
> > > > +  auto_vec (auto_vec<T> &&r)
> > > > +    {
> > > > +      gcc_assert (!r.using_auto_storage ());
> > > > +      this->m_vec = r.m_vec;
> > > > +      r.m_vec = NULL;
> > > > +    }
> > > > +
> > > >    auto_vec& operator= (vec<T, va_heap>&& r)
> > > >      {
> > > > +           if (this == &r)
> > > > +                   return *this;
> > > > +
> > > > +      gcc_assert (!r.using_auto_storage ());
> > > > +      this->release ();
> > > > +      this->m_vec = r.m_vec;
> > > > +      r.m_vec = NULL;
> > > > +      return *this;
> > > > +    }
> > > > +
> > > > +  auto_vec& operator= (auto_vec<T> &&r)
> > > > +    {
> > > > +           if (this == &r)
> > > > +                   return *this;
> > > > +
> > > >        gcc_assert (!r.using_auto_storage ());
> > > >        this->release ();
> > > >        this->m_vec = r.m_vec;
> > > >        r.m_vec = NULL;
> > > >        return *this;
> > > >      }
> > > > +
> > > > +  // You probably don't want to copy a vector, so these are deleted to prevent
> > > > +  // unintentional use.  If you really need a copy of the vectors contents you
> > > > +  // can use copy ().
> > > > +  auto_vec(const auto_vec &) = delete;
> > > > +  auto_vec &operator= (const auto_vec &) = delete;
> > > >  };
> > > >
> > > >
> > > > @@ -2147,7 +2186,7 @@ template<typename T>
> > > >  inline bool
> > > >  vec<T, va_heap, vl_ptr>::using_auto_storage () const
> > > >  {
> > > > -  return m_vec->m_vecpfx.m_using_auto_storage;
> > > > +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
> > > >  }
> > > >
> > > >  /* Release VEC and call release of all element vectors.  */
> > > > --
> > > > 2.20.1
> > > >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15  7:57       ` Trevor Saunders
@ 2021-06-15  9:36         ` Richard Biener
  2021-06-16  3:17           ` [PATCH, V2] " Trevor Saunders
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-15  9:36 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Tue, Jun 15, 2021 at 9:57 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> On Tue, Jun 15, 2021 at 09:11:52AM +0200, Richard Biener wrote:
> > On Tue, Jun 15, 2021 at 9:04 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > >
> > > On Tue, Jun 15, 2021 at 08:42:35AM +0200, Richard Biener wrote:
> > > > On Tue, Jun 15, 2021 at 8:00 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > > > >
> > > > > - Unfortunately using_auto_storage () needs to handle m_vec being null.
> > > > > - Handle self move of an auto_vec to itself.
> > > > > - punt on defining copy or move operators for auto_vec with inline storage,
> > > > >   until there is a need for them and we can decide what semantics they should
> > > > > have.
> > > >
> > > > Hmm, that will make using of the CTORs/assignments in "infrastructure"
> > > > fragile if you consider
> > >
> > > It definitely restricts what you can do with auto_vec with inline
> > > storage.  However that restriction is preexisting, and this just turns
> > > it into a assertion failure rather than memory corruption.
> >
> > You mean the CTOR from vec<> is auto-generated at the moment?
>
> I actually had to test this to be sure.  It depends, the constructor to
> copy auto_vec<T, N> to auto_vec<T, N> is generated and just coppies the
> representation, its basically memcpy, so that doesn't work properly.  If
> you attempt to copy auto_vec<T, P> to auto_vec<T, Q> the compiler will
> already refuse to generate the necessary constructor since the fields
> don't match up, and so the case where the amount of inline storage is
> different already fails to compile.
>
> > >  So its
> > > definitely not the final answer, but its better than what we have today
> > > I believe, and leaves options open for when this has a user, as this
> > > bootstraps nothing needs it today.
> > >
> > > > void foo(vec<T> src)
> > > > {
> > > >   auto_vec<T> dest (src);
> > > >   ...
> > > > }
> > > >
> > > > bar()
> > > > {
> > > >    auto_vec<X> a;  // vs. auto_vec<X, 1>
> > > >    a.safe_push (X()); // "decays" both to vec<X>
> > > >    foo (a);
> > > > }
> > > >
> > > > that is, it will eventually lead to hard to track down results?  I wonder if we
> > > > should add a m_has_auto_storage and assert that the incoming vector
> > > > does not instead of just asserting it doesn't use it to make the failure mode
> > > > at least not dependent so much on "input"?
> > >
> > > I'm not sure I follow this part.  I think example you are thinking of is
> > > something like this
> > > void foo(auto_vec<x> &&src)
> > > {
> > >         auto_vec<x> dst(src);
> > >         ...
> > > }
> > >
> > > And then some caller who wants to use inline storage
> > > void bar()
> > > {
> > >         auto-vec<x> a;
> > >         a.safe_push (x ());
> > >         foo (a);
> > > }
> > >
> > > Which today I believe ends up with dst containing a pointer to part of
> > > a, which is bogus and probably going to lead to memory corruption.
> > > After this patch we get an assert when we try and create dst because
> > > src.using_auto_storage () is true.  That's certainly not ideal, but
> > > better than what we have today.
> >
> > OK, so I guess one useful way to use the CTOR is when transfering vector
> > ownership to a function, but I expected that
> >
> > void foo (auto_vec<x> mine)
> > {
> > }
> >
> > would already do the trick here, destroying 'mine' when foo exits?
>
> Yes, after this patch you will have to move the vector into the argument
> of the function with something like foo (move (freeby));.  Today that
> doesn't work because you get an implicitly generated copy constructor
> for auto_vec<T> that just coppies the pointer producing an auto_vec in
> the callie and the caller that both think they own the same vector.
>
> > > > FWIW I agree that we likely want to avoid the copy that would be required
> > > > when auto-storage is used - OTOH if we can be sure the lifetime of the
> > > > result cannot be extended beyond the auto-storage provider then copying
> > > > m_vec will likely just work?
> > >
> > > If I understand the case your thinking of correctly my question would be
> > > why are you making a copy at all then, rather than passing a pointer or
> > > reference to the original vector? I would think the two cases where a
> > > copy may make sense is when the new object outlives the source, or when
> > > you wish to mutate the new object leaving the original one unchanged,
> > > for either of those copying the m_vec pointer so it points into the
> > > original object wouldn't work?
> >
> > vec<> is used as (const) "reference" in a lot of places, avoiding the
> > extra indirection that happens when using const vec<> & since passing
> > its sole pointer member is cheap.  (maybe const vec<> should be passed
> > in all those cases though)
>
> Certainly the C++ way of doing things is to pass const vec<T> & and hope
> the abstraction gets optimized out.  Its unfortunate, but its also not
> really clear how else you'd mark that your giving the called function a
> possibly const borrowed view of the vector.  I suppose you can have yet
> another type that you use in arguments and removes the layer of
> abstraction when the called function doesn't need to mutate the vector.
> Certainly if the call can mutate the vector you need to, and already do,
> pass a vec<>& or vec<>*, and its just the case of functions that only
> read the vector where this optimization can apply.  I find myself
> wondering how much this manual optimization matters, or if at this point
> lto bootstrapping production compilers takes care of this for us? That's
> a question I don't think I have the data to answer.
>
> > > > Besides this detail the patch looks OK.
> > >
> > > I think there's some risk of shooting yourself in the foot with the
> > > inline storage version as it is today, but I'd be ok with spliting that
> > > part out into a separate patch and only adjusting the version with no
> > > inline storage here.  I believe that's enough for the rest of the series
> > > to work properly.
> >
> > I trust you with the change but I'm not too familiar with C++ to
> > trust myself with a final OK, so if you can split out this part and
> > post it separately that would make me more comfortable.
>
> Sure, just to be clear you mean the deleted constructors and assignment
> operators for the version of auto_vec<> with inline storage?

Yes.

> I'll split
> that out and make sure the series still bootstrapps and tests ok without
> it, I really think it should  but might as well confirm.

Thanks,
Richard.

> Trev
>
> >
> > Thanks,
> > Richard.
> >
> > >
> > > Thanks!
> > >
> > > Trev
> > >
> > > >
> > > > Thanks,
> > > > Richard.
> > > >
> > > > > - Make sure auto_vec defines the classes move constructor and assignment
> > > > >   operator, as well as ones taking vec<T>, so the compiler does not generate
> > > > > them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> > > > > the ones taking vec<T> do not count as the classes move constructor or
> > > > > assignment operator, but we want them as well to assign a plain vec to a
> > > > > auto_vec.
> > > > > - Explicitly delete auto_vec's copy constructor and assignment operator.  This
> > > > >   prevents unintentional expenssive coppies of the vector and makes it clear
> > > > > when coppies are needed that that is what is intended.  When it is necessary to
> > > > > copy a vector copy () can be used.
> > > > >
> > > > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > > > >
> > > > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > > > >
> > > > > gcc/ChangeLog:
> > > > >
> > > > >         * vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
> > > > >         (auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
> > > > >         constructor.
> > > > >         (auto_vec<T, 0>::operator=): Define move assignment and delete copy
> > > > >         assignment.
> > > > >         (auto_vec<T, N>::auto_vec): Delete copy and move constructors.
> > > > >         (auto_vec<T, N>::operator=): Delete copy and move assignment.
> > > > > ---
> > > > >  gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
> > > > >  1 file changed, 40 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/gcc/vec.h b/gcc/vec.h
> > > > > index 193377cb69c..ceefa67e1ad 100644
> > > > > --- a/gcc/vec.h
> > > > > +++ b/gcc/vec.h
> > > > > @@ -1549,6 +1549,16 @@ public:
> > > > >      this->release ();
> > > > >    }
> > > > >
> > > > > +  // Punt for now on moving auto_vec with inline storage.  For now this
> > > > > +  // prevents people creating dangling pointers or the like.
> > > > > +  auto_vec (auto_vec &&) = delete;
> > > > > +  auto_vec &operator= (auto_vec &&) = delete;
> > > > > +
> > > > > +  // Punt for now on the inline storage, and you probably don't want to copy
> > > > > +  // vectors anyway.  If you really must copy a vector use copy ().
> > > > > +  auto_vec(const auto_vec &) = delete;
> > > > > +  auto_vec &operator= (const auto_vec &) = delete;
> > > > > +
> > > > >  private:
> > > > >    vec<T, va_heap, vl_embed> m_auto;
> > > > >    T m_data[MAX (N - 1, 1)];
> > > > > @@ -1570,14 +1580,43 @@ public:
> > > > >        this->m_vec = r.m_vec;
> > > > >        r.m_vec = NULL;
> > > > >      }
> > > > > +
> > > > > +  auto_vec (auto_vec<T> &&r)
> > > > > +    {
> > > > > +      gcc_assert (!r.using_auto_storage ());
> > > > > +      this->m_vec = r.m_vec;
> > > > > +      r.m_vec = NULL;
> > > > > +    }
> > > > > +
> > > > >    auto_vec& operator= (vec<T, va_heap>&& r)
> > > > >      {
> > > > > +           if (this == &r)
> > > > > +                   return *this;
> > > > > +
> > > > > +      gcc_assert (!r.using_auto_storage ());
> > > > > +      this->release ();
> > > > > +      this->m_vec = r.m_vec;
> > > > > +      r.m_vec = NULL;
> > > > > +      return *this;
> > > > > +    }
> > > > > +
> > > > > +  auto_vec& operator= (auto_vec<T> &&r)
> > > > > +    {
> > > > > +           if (this == &r)
> > > > > +                   return *this;
> > > > > +
> > > > >        gcc_assert (!r.using_auto_storage ());
> > > > >        this->release ();
> > > > >        this->m_vec = r.m_vec;
> > > > >        r.m_vec = NULL;
> > > > >        return *this;
> > > > >      }
> > > > > +
> > > > > +  // You probably don't want to copy a vector, so these are deleted to prevent
> > > > > +  // unintentional use.  If you really need a copy of the vectors contents you
> > > > > +  // can use copy ().
> > > > > +  auto_vec(const auto_vec &) = delete;
> > > > > +  auto_vec &operator= (const auto_vec &) = delete;
> > > > >  };
> > > > >
> > > > >
> > > > > @@ -2147,7 +2186,7 @@ template<typename T>
> > > > >  inline bool
> > > > >  vec<T, va_heap, vl_ptr>::using_auto_storage () const
> > > > >  {
> > > > > -  return m_vec->m_vecpfx.m_using_auto_storage;
> > > > > +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
> > > > >  }
> > > > >
> > > > >  /* Release VEC and call release of all element vectors.  */
> > > > > --
> > > > > 2.20.1
> > > > >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 4/6] return auto_vec from get_dominated_by
  2021-06-15  6:46   ` Richard Biener
@ 2021-06-15 11:18     ` Bernhard Reutner-Fischer
  2021-06-16  3:09       ` Trevor Saunders
  0 siblings, 1 reply; 51+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-06-15 11:18 UTC (permalink / raw)
  To: Richard Biener, Richard Biener via Gcc-patches, Trevor Saunders
  Cc: GCC Patches

On 15 June 2021 08:46:57 CEST, Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org>
>wrote:
>>
>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>
>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>
>OK.
>
>Thanks,
>Richard.
>
>> gcc/ChangeLog:
>>
>>         * dominance.c (get_dominated_by): Return
>auto_vec<basic_block>.
>>         * dominance.h (get_dominated_by): Likewise.
>>         * auto-profile.c (afdo_find_equiv_class): Adjust.
>>         * cfgloopmanip.c (duplicate_loop_to_header_edge): Likewise.
>>         * loop-unroll.c (unroll_loop_runtime_iterations): Likewise.
>>         * tree-cfg.c (test_linear_chain): Likewise.
>>         (test_diamond): Likewise.
>> ---

>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>> index 02256580c98..6bdd1a561fd 100644
>> --- a/gcc/tree-cfg.c
>> +++ b/gcc/tree-cfg.c
>> @@ -9917,22 +9917,20 @@ test_linear_chain ()
>>    calculate_dominance_info (CDI_DOMINATORS);
>>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
>>    ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
>> -  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS,
>bb_b);
>> +  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS,
>bb_b);
>>    ASSERT_EQ (1, dom_by_b.length ());
>>    ASSERT_EQ (bb_c, dom_by_b[0]);
>>    free_dominance_info (CDI_DOMINATORS);
>> -  dom_by_b.release ();
>>
>>    /* Similarly for post-dominance: each BB in our chain is
>post-dominated
>>       by the one after it.  */
>>    calculate_dominance_info (CDI_POST_DOMINATORS);
>>    ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS,
>bb_a));
>>    ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS,
>bb_b));
>> -  vec<basic_block> postdom_by_b = get_dominated_by
>(CDI_POST_DOMINATORS, bb_b);
>> +  auto_vec<basic_block> postdom_by_b = get_dominated_by
>(CDI_POST_DOMINATORS, bb_b);
>>    ASSERT_EQ (1, postdom_by_b.length ());
>>    ASSERT_EQ (bb_a, postdom_by_b[0]);
>>    free_dominance_info (CDI_POST_DOMINATORS);
>> -  postdom_by_b.release ();
>>
>>    pop_cfun ();
>>  }
>> @@ -9991,10 +9989,10 @@ test_diamond ()
>>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
>>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
>>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
>> -  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS,
>bb_a);
>> +  auto_vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS,
>bb_a);
>>    ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
>>    dom_by_a.release ();

I'm curious why you keep the release() above and ...

>> -  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS,
>bb_b);
>> +  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS,
>bb_b);
>>    ASSERT_EQ (0, dom_by_b.length ());
>>    dom_by_b.release ();

here and

>>    free_dominance_info (CDI_DOMINATORS);
>> @@ -10004,10 +10002,10 @@ test_diamond ()
>>    ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS,
>bb_a));
>>    ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS,
>bb_b));
>>    ASSERT_EQ (bb_d, get_immediate_dominator (CDI_POST_DOMINATORS,
>bb_c));
>> -  vec<basic_block> postdom_by_d = get_dominated_by
>(CDI_POST_DOMINATORS, bb_d);
>> +  auto_vec<basic_block> postdom_by_d = get_dominated_by
>(CDI_POST_DOMINATORS, bb_d);
>>    ASSERT_EQ (3, postdom_by_d.length ()); /* A, B, C in some order. 
>*/
>>    postdom_by_d.release ();

here and 

>> -  vec<basic_block> postdom_by_b = get_dominated_by
>(CDI_POST_DOMINATORS, bb_b);
>> +  auto_vec<basic_block> postdom_by_b = get_dominated_by
>(CDI_POST_DOMINATORS, bb_b);
>>    ASSERT_EQ (0, postdom_by_b.length ());
>>    postdom_by_b.release ();

here?

thanks,

>>    free_dominance_info (CDI_POST_DOMINATORS);
>> --
>> 2.20.1
>>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
                   ` (5 preceding siblings ...)
  2021-06-15  6:42 ` [PATCH 1/6] auto_vec copy/move improvements Richard Biener
@ 2021-06-15 16:18 ` Martin Sebor
  2021-06-16  3:31   ` Trevor Saunders
  6 siblings, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-15 16:18 UTC (permalink / raw)
  To: Trevor Saunders, gcc-patches

On 6/14/21 11:59 PM, Trevor Saunders wrote:
> - Unfortunately using_auto_storage () needs to handle m_vec being null.
> - Handle self move of an auto_vec to itself.
> - punt on defining copy or move operators for auto_vec with inline storage,
>    until there is a need for them and we can decide what semantics they should
> have.
> - Make sure auto_vec defines the classes move constructor and assignment
>    operator, as well as ones taking vec<T>, so the compiler does not generate
> them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> the ones taking vec<T> do not count as the classes move constructor or
> assignment operator, but we want them as well to assign a plain vec to a
> auto_vec.
> - Explicitly delete auto_vec's copy constructor and assignment operator.  This
>    prevents unintentional expenssive coppies of the vector and makes it clear
> when coppies are needed that that is what is intended.  When it is necessary to
> copy a vector copy () can be used.
> 
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> 
> bootstrapped and regtested on x86_64-linux-gnu, ok?
> 
> gcc/ChangeLog:
> 
> 	* vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
> 	(auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
> 	constructor.
> 	(auto_vec<T, 0>::operator=): Define move assignment and delete copy
> 	assignment.
> 	(auto_vec<T, N>::auto_vec): Delete copy and move constructors.
> 	(auto_vec<T, N>::operator=): Delete copy and move assignment.

auto_vec should be copy constructible and copy assignable to be
usable as its own element (for example).  There is nothing to gain
by preventing it but make auto_vec harder to use.

Martin



> ---
>   gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/gcc/vec.h b/gcc/vec.h
> index 193377cb69c..ceefa67e1ad 100644
> --- a/gcc/vec.h
> +++ b/gcc/vec.h
> @@ -1549,6 +1549,16 @@ public:
>       this->release ();
>     }
>   
> +  // Punt for now on moving auto_vec with inline storage.  For now this
> +  // prevents people creating dangling pointers or the like.
> +  auto_vec (auto_vec &&) = delete;
> +  auto_vec &operator= (auto_vec &&) = delete;
> +
> +  // Punt for now on the inline storage, and you probably don't want to copy
> +  // vectors anyway.  If you really must copy a vector use copy ().
> +  auto_vec(const auto_vec &) = delete;
> +  auto_vec &operator= (const auto_vec &) = delete;
> +
>   private:
>     vec<T, va_heap, vl_embed> m_auto;
>     T m_data[MAX (N - 1, 1)];
> @@ -1570,14 +1580,43 @@ public:
>         this->m_vec = r.m_vec;
>         r.m_vec = NULL;
>       }
> +
> +  auto_vec (auto_vec<T> &&r)
> +    {
> +      gcc_assert (!r.using_auto_storage ());
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +    }
> +
>     auto_vec& operator= (vec<T, va_heap>&& r)
>       {
> +	    if (this == &r)
> +		    return *this;
> +
> +      gcc_assert (!r.using_auto_storage ());
> +      this->release ();
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +      return *this;
> +    }
> +
> +  auto_vec& operator= (auto_vec<T> &&r)
> +    {
> +	    if (this == &r)
> +		    return *this;
> +
>         gcc_assert (!r.using_auto_storage ());
>         this->release ();
>         this->m_vec = r.m_vec;
>         r.m_vec = NULL;
>         return *this;
>       }
> +
> +  // You probably don't want to copy a vector, so these are deleted to prevent
> +  // unintentional use.  If you really need a copy of the vectors contents you
> +  // can use copy ().
> +  auto_vec(const auto_vec &) = delete;
> +  auto_vec &operator= (const auto_vec &) = delete;
>   };
>   
>   
> @@ -2147,7 +2186,7 @@ template<typename T>
>   inline bool
>   vec<T, va_heap, vl_ptr>::using_auto_storage () const
>   {
> -  return m_vec->m_vecpfx.m_using_auto_storage;
> +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
>   }
>   
>   /* Release VEC and call release of all element vectors.  */
> 


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 4/6] return auto_vec from get_dominated_by
  2021-06-15 11:18     ` Bernhard Reutner-Fischer
@ 2021-06-16  3:09       ` Trevor Saunders
  2021-06-16  5:45         ` Bernhard Reutner-Fischer
  0 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-16  3:09 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer; +Cc: Richard Biener, Richard Biener via Gcc-patches

On Tue, Jun 15, 2021 at 01:18:54PM +0200, Bernhard Reutner-Fischer wrote:
> On 15 June 2021 08:46:57 CEST, Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org>
> >wrote:
> >>
> >> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> >>
> >> bootstrapped and regtested on x86_64-linux-gnu, ok?
> >
> >OK.
> >
> >Thanks,
> >Richard.
> >
> >> gcc/ChangeLog:
> >>
> >>         * dominance.c (get_dominated_by): Return
> >auto_vec<basic_block>.
> >>         * dominance.h (get_dominated_by): Likewise.
> >>         * auto-profile.c (afdo_find_equiv_class): Adjust.
> >>         * cfgloopmanip.c (duplicate_loop_to_header_edge): Likewise.
> >>         * loop-unroll.c (unroll_loop_runtime_iterations): Likewise.
> >>         * tree-cfg.c (test_linear_chain): Likewise.
> >>         (test_diamond): Likewise.
> >> ---
> 
> >> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >> index 02256580c98..6bdd1a561fd 100644
> >> --- a/gcc/tree-cfg.c
> >> +++ b/gcc/tree-cfg.c
> >> @@ -9917,22 +9917,20 @@ test_linear_chain ()
> >>    calculate_dominance_info (CDI_DOMINATORS);
> >>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
> >>    ASSERT_EQ (bb_b, get_immediate_dominator (CDI_DOMINATORS, bb_c));
> >> -  vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS,
> >bb_b);
> >> +  auto_vec<basic_block> dom_by_b = get_dominated_by (CDI_DOMINATORS,
> >bb_b);
> >>    ASSERT_EQ (1, dom_by_b.length ());
> >>    ASSERT_EQ (bb_c, dom_by_b[0]);
> >>    free_dominance_info (CDI_DOMINATORS);
> >> -  dom_by_b.release ();
> >>
> >>    /* Similarly for post-dominance: each BB in our chain is
> >post-dominated
> >>       by the one after it.  */
> >>    calculate_dominance_info (CDI_POST_DOMINATORS);
> >>    ASSERT_EQ (bb_b, get_immediate_dominator (CDI_POST_DOMINATORS,
> >bb_a));
> >>    ASSERT_EQ (bb_c, get_immediate_dominator (CDI_POST_DOMINATORS,
> >bb_b));
> >> -  vec<basic_block> postdom_by_b = get_dominated_by
> >(CDI_POST_DOMINATORS, bb_b);
> >> +  auto_vec<basic_block> postdom_by_b = get_dominated_by
> >(CDI_POST_DOMINATORS, bb_b);
> >>    ASSERT_EQ (1, postdom_by_b.length ());
> >>    ASSERT_EQ (bb_a, postdom_by_b[0]);
> >>    free_dominance_info (CDI_POST_DOMINATORS);
> >> -  postdom_by_b.release ();
> >>
> >>    pop_cfun ();
> >>  }
> >> @@ -9991,10 +9989,10 @@ test_diamond ()
> >>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_b));
> >>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_c));
> >>    ASSERT_EQ (bb_a, get_immediate_dominator (CDI_DOMINATORS, bb_d));
> >> -  vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS,
> >bb_a);
> >> +  auto_vec<basic_block> dom_by_a = get_dominated_by (CDI_DOMINATORS,
> >bb_a);
> >>    ASSERT_EQ (3, dom_by_a.length ()); /* B, C, D, in some order.  */
> >>    dom_by_a.release ();
> 
> I'm curious why you keep the release() above and ...

There was no particular reason, I just didn't make a very complete
search to remove them all, as they should be harmless.  I'm certainly
happy to remove them, but wonder if it wouldn't make more sense to go on
a broader search for uses of release and see why they are necessary or
remove them.

thanks

Trev

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH, V2] auto_vec copy/move improvements
  2021-06-15  9:36         ` Richard Biener
@ 2021-06-16  3:17           ` Trevor Saunders
  2021-06-16 10:13             ` Richard Biener
  0 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-16  3:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Trevor Saunders

- Unfortunately using_auto_storage () needs to handle m_vec being null.
- Handle self move of an auto_vec to itself.
- Make sure auto_vec defines the classes move constructor and assignment
  operator, as well as ones taking vec<T>, so the compiler does not generate
them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
the ones taking vec<T> do not count as the classes move constructor or
assignment operator, but we want them as well to assign a plain vec to a
auto_vec.
- Explicitly delete auto_vec's copy constructor and assignment operator.  This
  prevents unintentional expenssive coppies of the vector and makes it clear
when coppies are needed that that is what is intended.  When it is necessary to
copy a vector copy () can be used.

Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>

This time without the changes to the inline storage version of auto_vec as
requested.  bootstrap andregtest on x86_64-linux-gnu with the other patches in
the series ongoing, ok if that passes?

Thanks

Trev

gcc/ChangeLog:

	* vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
	(auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
	constructor.
	(auto_vec<T, 0>::operator=): Define move assignment and delete copy
	assignment.
---
 gcc/vec.h | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/gcc/vec.h b/gcc/vec.h
index 193377cb69c..30ef9a69473 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1570,14 +1570,43 @@ public:
       this->m_vec = r.m_vec;
       r.m_vec = NULL;
     }
+
+  auto_vec (auto_vec<T> &&r)
+    {
+      gcc_assert (!r.using_auto_storage ());
+      this->m_vec = r.m_vec;
+      r.m_vec = NULL;
+    }
+
   auto_vec& operator= (vec<T, va_heap>&& r)
     {
+	    if (this == &r)
+		    return *this;
+
+      gcc_assert (!r.using_auto_storage ());
+      this->release ();
+      this->m_vec = r.m_vec;
+      r.m_vec = NULL;
+      return *this;
+    }
+
+  auto_vec& operator= (auto_vec<T> &&r)
+    {
+	    if (this == &r)
+		    return *this;
+
       gcc_assert (!r.using_auto_storage ());
       this->release ();
       this->m_vec = r.m_vec;
       r.m_vec = NULL;
       return *this;
     }
+
+  // You probably don't want to copy a vector, so these are deleted to prevent
+  // unintentional use.  If you really need a copy of the vectors contents you
+  // can use copy ().
+  auto_vec(const auto_vec &) = delete;
+  auto_vec &operator= (const auto_vec &) = delete;
 };
 
 
@@ -2147,7 +2176,7 @@ template<typename T>
 inline bool
 vec<T, va_heap, vl_ptr>::using_auto_storage () const
 {
-  return m_vec->m_vecpfx.m_using_auto_storage;
+  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
 }
 
 /* Release VEC and call release of all element vectors.  */
-- 
2.20.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 1/6] auto_vec copy/move improvements
  2021-06-15 16:18 ` [PATCH 1/6] " Martin Sebor
@ 2021-06-16  3:31   ` Trevor Saunders
  0 siblings, 0 replies; 51+ messages in thread
From: Trevor Saunders @ 2021-06-16  3:31 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On Tue, Jun 15, 2021 at 10:18:30AM -0600, Martin Sebor wrote:
> On 6/14/21 11:59 PM, Trevor Saunders wrote:
> > - Unfortunately using_auto_storage () needs to handle m_vec being null.
> > - Handle self move of an auto_vec to itself.
> > - punt on defining copy or move operators for auto_vec with inline storage,
> >    until there is a need for them and we can decide what semantics they should
> > have.
> > - Make sure auto_vec defines the classes move constructor and assignment
> >    operator, as well as ones taking vec<T>, so the compiler does not generate
> > them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> > the ones taking vec<T> do not count as the classes move constructor or
> > assignment operator, but we want them as well to assign a plain vec to a
> > auto_vec.
> > - Explicitly delete auto_vec's copy constructor and assignment operator.  This
> >    prevents unintentional expenssive coppies of the vector and makes it clear
> > when coppies are needed that that is what is intended.  When it is necessary to
> > copy a vector copy () can be used.
> > 
> > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > 
> > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > 
> > gcc/ChangeLog:
> > 
> > 	* vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
> > 	(auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
> > 	constructor.
> > 	(auto_vec<T, 0>::operator=): Define move assignment and delete copy
> > 	assignment.
> > 	(auto_vec<T, N>::auto_vec): Delete copy and move constructors.
> > 	(auto_vec<T, N>::operator=): Delete copy and move assignment.
> 
> auto_vec should be copy constructible and copy assignable to be
> usable as its own element (for example).  There is nothing to gain
> by preventing it but make auto_vec harder to use.

I disagree, and I think I've laid out the arguments before so I'll
spare people reading them again.  However here's one simple benefit, I
was curious how many places copy vectors today, in part for other
changes I'd like to make, today I can get that number by simply greping
for "copy ()", compared to the work that would involved to decide if
something will be a move or a copy.  It turns out the answer is about
68, in all of gcc, that's not a lot, and I wonder if making ownership
clearer will let us get rid of some.  Certainly if things change and
someone has a problem to solve where copy () just won't work everything
can be reconsidered, but imho "I have to type .copy ()" is a feature.
Certainly a deleted copy constructor is better than a broken one right?

Thanks

Trev

> 
> Martin
> 
> 
> 
> > ---
> >   gcc/vec.h | 41 ++++++++++++++++++++++++++++++++++++++++-
> >   1 file changed, 40 insertions(+), 1 deletion(-)
> > 
> > diff --git a/gcc/vec.h b/gcc/vec.h
> > index 193377cb69c..ceefa67e1ad 100644
> > --- a/gcc/vec.h
> > +++ b/gcc/vec.h
> > @@ -1549,6 +1549,16 @@ public:
> >       this->release ();
> >     }
> > +  // Punt for now on moving auto_vec with inline storage.  For now this
> > +  // prevents people creating dangling pointers or the like.
> > +  auto_vec (auto_vec &&) = delete;
> > +  auto_vec &operator= (auto_vec &&) = delete;
> > +
> > +  // Punt for now on the inline storage, and you probably don't want to copy
> > +  // vectors anyway.  If you really must copy a vector use copy ().
> > +  auto_vec(const auto_vec &) = delete;
> > +  auto_vec &operator= (const auto_vec &) = delete;
> > +
> >   private:
> >     vec<T, va_heap, vl_embed> m_auto;
> >     T m_data[MAX (N - 1, 1)];
> > @@ -1570,14 +1580,43 @@ public:
> >         this->m_vec = r.m_vec;
> >         r.m_vec = NULL;
> >       }
> > +
> > +  auto_vec (auto_vec<T> &&r)
> > +    {
> > +      gcc_assert (!r.using_auto_storage ());
> > +      this->m_vec = r.m_vec;
> > +      r.m_vec = NULL;
> > +    }
> > +
> >     auto_vec& operator= (vec<T, va_heap>&& r)
> >       {
> > +	    if (this == &r)
> > +		    return *this;
> > +
> > +      gcc_assert (!r.using_auto_storage ());
> > +      this->release ();
> > +      this->m_vec = r.m_vec;
> > +      r.m_vec = NULL;
> > +      return *this;
> > +    }
> > +
> > +  auto_vec& operator= (auto_vec<T> &&r)
> > +    {
> > +	    if (this == &r)
> > +		    return *this;
> > +
> >         gcc_assert (!r.using_auto_storage ());
> >         this->release ();
> >         this->m_vec = r.m_vec;
> >         r.m_vec = NULL;
> >         return *this;
> >       }
> > +
> > +  // You probably don't want to copy a vector, so these are deleted to prevent
> > +  // unintentional use.  If you really need a copy of the vectors contents you
> > +  // can use copy ().
> > +  auto_vec(const auto_vec &) = delete;
> > +  auto_vec &operator= (const auto_vec &) = delete;
> >   };
> > @@ -2147,7 +2186,7 @@ template<typename T>
> >   inline bool
> >   vec<T, va_heap, vl_ptr>::using_auto_storage () const
> >   {
> > -  return m_vec->m_vecpfx.m_using_auto_storage;
> > +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
> >   }
> >   /* Release VEC and call release of all element vectors.  */
> > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 4/6] return auto_vec from get_dominated_by
  2021-06-16  3:09       ` Trevor Saunders
@ 2021-06-16  5:45         ` Bernhard Reutner-Fischer
  2021-06-17  6:56           ` Trevor Saunders
  0 siblings, 1 reply; 51+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-06-16  5:45 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Richard Biener, Richard Biener via Gcc-patches

On 16 June 2021 05:09:17 CEST, Trevor Saunders <tbsaunde@tbsaunde.org> wrote:

>> I'm curious why you keep the release() above and ...
>
>There was no particular reason, I just didn't make a very complete
>search to remove them all, as they should be harmless.  I'm certainly
>happy to remove them, but wonder if it wouldn't make more sense to go
>on
>a broader search for uses of release and see why they are necessary or
>remove them.

Yes.
One spot where you removed the early release() was in gimple_duplicate_sese_region and gimple_duplicate_sese_tail. I did wonder if there are adverse effects on memory usage for TUs with lots of basic blocks but you certainly thought about that when you removed the explicit doms.release().

thanks!

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH, V2] auto_vec copy/move improvements
  2021-06-16  3:17           ` [PATCH, V2] " Trevor Saunders
@ 2021-06-16 10:13             ` Richard Biener
  2021-06-16 17:01               ` Martin Sebor
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-16 10:13 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: GCC Patches

On Wed, Jun 16, 2021 at 5:18 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> - Unfortunately using_auto_storage () needs to handle m_vec being null.
> - Handle self move of an auto_vec to itself.
> - Make sure auto_vec defines the classes move constructor and assignment
>   operator, as well as ones taking vec<T>, so the compiler does not generate
> them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
> the ones taking vec<T> do not count as the classes move constructor or
> assignment operator, but we want them as well to assign a plain vec to a
> auto_vec.
> - Explicitly delete auto_vec's copy constructor and assignment operator.  This
>   prevents unintentional expenssive coppies of the vector and makes it clear
> when coppies are needed that that is what is intended.  When it is necessary to
> copy a vector copy () can be used.
>
> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>
> This time without the changes to the inline storage version of auto_vec as
> requested.  bootstrap andregtest on x86_64-linux-gnu with the other patches in
> the series ongoing, ok if that passes?

OK.

Thanks,
Richard.

> Thanks
>
> Trev
>
> gcc/ChangeLog:
>
>         * vec.h (vl_ptr>::using_auto_storage): Handle null m_vec.
>         (auto_vec<T, 0>::auto_vec): Define move constructor, and delete copy
>         constructor.
>         (auto_vec<T, 0>::operator=): Define move assignment and delete copy
>         assignment.
> ---
>  gcc/vec.h | 31 ++++++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/vec.h b/gcc/vec.h
> index 193377cb69c..30ef9a69473 100644
> --- a/gcc/vec.h
> +++ b/gcc/vec.h
> @@ -1570,14 +1570,43 @@ public:
>        this->m_vec = r.m_vec;
>        r.m_vec = NULL;
>      }
> +
> +  auto_vec (auto_vec<T> &&r)
> +    {
> +      gcc_assert (!r.using_auto_storage ());
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +    }
> +
>    auto_vec& operator= (vec<T, va_heap>&& r)
>      {
> +           if (this == &r)
> +                   return *this;
> +
> +      gcc_assert (!r.using_auto_storage ());
> +      this->release ();
> +      this->m_vec = r.m_vec;
> +      r.m_vec = NULL;
> +      return *this;
> +    }
> +
> +  auto_vec& operator= (auto_vec<T> &&r)
> +    {
> +           if (this == &r)
> +                   return *this;
> +
>        gcc_assert (!r.using_auto_storage ());
>        this->release ();
>        this->m_vec = r.m_vec;
>        r.m_vec = NULL;
>        return *this;
>      }
> +
> +  // You probably don't want to copy a vector, so these are deleted to prevent
> +  // unintentional use.  If you really need a copy of the vectors contents you
> +  // can use copy ().
> +  auto_vec(const auto_vec &) = delete;
> +  auto_vec &operator= (const auto_vec &) = delete;
>  };
>
>
> @@ -2147,7 +2176,7 @@ template<typename T>
>  inline bool
>  vec<T, va_heap, vl_ptr>::using_auto_storage () const
>  {
> -  return m_vec->m_vecpfx.m_using_auto_storage;
> +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
>  }
>
>  /* Release VEC and call release of all element vectors.  */
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-15  6:49   ` Richard Biener
@ 2021-06-16 12:46     ` Richard Sandiford
  2021-06-16 16:01       ` Martin Sebor
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Sandiford @ 2021-06-16 12:46 UTC (permalink / raw)
  To: Richard Biener via Gcc-patches; +Cc: Trevor Saunders, Richard Biener

Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>
>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>>
>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>
>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>
> OK.
>
> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> excessive indent for
>
> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> -                                    bbs.address (),
> -                                    bbs.length ());
> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> +                                                          bbs.address (),
> +                                                          bbs.length ());
>
> and just uses
>
>   auto dom_bbs = get_dominated_by_region (...
>
> Not asking you to do this, just a question for the audience.

Personally I think this would be surprising for something that doesn't
have copy semantics.  (Not that I'm trying to reopen that debate here :-)
FWIW, I agree not having copy semantics is probably the most practical
way forward for now.)

Thanks,
Richard

> Thanks,
> Richard.
>
>> gcc/ChangeLog:
>>
>>         * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
>>         * dominance.h (get_dominated_by_region): Likewise.
>>         * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
>>         (gimple_duplicate_sese_tail): Likewise.
>>         (move_sese_region_to_fn): Likewise.
>> ---
>>  gcc/dominance.c |  4 ++--
>>  gcc/dominance.h |  2 +-
>>  gcc/tree-cfg.c  | 18 +++++++-----------
>>  3 files changed, 10 insertions(+), 14 deletions(-)
>>
>> diff --git a/gcc/dominance.c b/gcc/dominance.c
>> index 0e464cb7282..4943102ff1d 100644
>> --- a/gcc/dominance.c
>> +++ b/gcc/dominance.c
>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
>>     direction DIR) by some block between N_REGION ones stored in REGION,
>>     except for blocks in the REGION itself.  */
>>
>> -vec<basic_block>
>> +auto_vec<basic_block>
>>  get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>>                          unsigned n_region)
>>  {
>>    unsigned i;
>>    basic_block dom;
>> -  vec<basic_block> doms = vNULL;
>> +  auto_vec<basic_block> doms;
>>
>>    for (i = 0; i < n_region; i++)
>>      region[i]->flags |= BB_DUPLICATED;
>> diff --git a/gcc/dominance.h b/gcc/dominance.h
>> index 515a369aacf..c74ad297c6a 100644
>> --- a/gcc/dominance.h
>> +++ b/gcc/dominance.h
>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>>  extern void set_immediate_dominator (enum cdi_direction, basic_block,
>>                                      basic_block);
>>  extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>                                                          basic_block *,
>>                                                          unsigned);
>>  extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>> index 6bdd1a561fd..c9403deed19 100644
>> --- a/gcc/tree-cfg.c
>> +++ b/gcc/tree-cfg.c
>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>    bool free_region_copy = false, copying_header = false;
>>    class loop *loop = entry->dest->loop_father;
>>    edge exit_copy;
>> -  vec<basic_block> doms = vNULL;
>>    edge redirected;
>>    profile_count total_count = profile_count::uninitialized ();
>>    profile_count entry_count = profile_count::uninitialized ();
>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>
>>    /* Record blocks outside the region that are dominated by something
>>       inside.  */
>> +  auto_vec<basic_block> doms;
>>    if (update_dominance)
>>      {
>> -      doms.create (0);
>>        doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>      }
>>
>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>        set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
>>        doms.safe_push (get_bb_original (entry->dest));
>>        iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>> -      doms.release ();
>>      }
>>
>>    /* Add the other PHI node arguments.  */
>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>    class loop *loop = exit->dest->loop_father;
>>    class loop *orig_loop = entry->dest->loop_father;
>>    basic_block switch_bb, entry_bb, nentry_bb;
>> -  vec<basic_block> doms;
>>    profile_count total_count = profile_count::uninitialized (),
>>                 exit_count = profile_count::uninitialized ();
>>    edge exits[2], nexits[2], e;
>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>
>>    /* Record blocks outside the region that are dominated by something
>>       inside.  */
>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
>> +                                                       n_region);
>>
>>    total_count = exit->src->count;
>>    exit_count = exit->count ();
>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>    /* Anything that is outside of the region, but was dominated by something
>>       inside needs to update dominance info.  */
>>    iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>> -  doms.release ();
>>    /* Update the SSA web.  */
>>    update_ssa (TODO_update_ssa);
>>
>> @@ -7567,7 +7564,7 @@ basic_block
>>  move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>                         basic_block exit_bb, tree orig_block)
>>  {
>> -  vec<basic_block> bbs, dom_bbs;
>> +  vec<basic_block> bbs;
>>    basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
>>    basic_block after, bb, *entry_pred, *exit_succ, abb;
>>    struct function *saved_cfun = cfun;
>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>
>>    /* The blocks that used to be dominated by something in BBS will now be
>>       dominated by the new block.  */
>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>> -                                    bbs.address (),
>> -                                    bbs.length ());
>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>> +                                                          bbs.address (),
>> +                                                          bbs.length ());
>>
>>    /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
>>       the predecessor edges to ENTRY_BB and the successor edges to
>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>    set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
>>    FOR_EACH_VEC_ELT (dom_bbs, i, abb)
>>      set_immediate_dominator (CDI_DOMINATORS, abb, bb);
>> -  dom_bbs.release ();
>>
>>    if (exit_bb)
>>      {
>> --
>> 2.20.1
>>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-16 12:46     ` Richard Sandiford
@ 2021-06-16 16:01       ` Martin Sebor
  2021-06-17  6:03         ` Richard Biener
  0 siblings, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-16 16:01 UTC (permalink / raw)
  To: Richard Biener via Gcc-patches, Trevor Saunders, Richard Biener,
	richard.sandiford

On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>>
>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>>>
>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>>
>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>>
>> OK.
>>
>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
>> excessive indent for
>>
>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>> -                                    bbs.address (),
>> -                                    bbs.length ());
>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>> +                                                          bbs.address (),
>> +                                                          bbs.length ());
>>
>> and just uses
>>
>>    auto dom_bbs = get_dominated_by_region (...
>>
>> Not asking you to do this, just a question for the audience.
> 
> Personally I think this would be surprising for something that doesn't
> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> FWIW, I agree not having copy semantics is probably the most practical
> way forward for now.)

But you did open the door for me to reiterate my strong disagreement
with that.  The best C++ practice going back to the early 1990's is
to make types safely copyable and assignable.  It is the default for
all types, in both C++ and C, and so natural and expected.

Preventing copying is appropriate in special and rare circumstances
(e.g, a mutex may not be copyable, or a file or iostream object may
not be because they represent a unique physical resource.)

In the absence of such special circumstances preventing copying is
unexpected, and in the case of an essential building block such as
a container, makes the type difficult to use.

The only argument for disabling copying that has been given is
that it could be surprising(*).  But because all types are copyable
by default the "surprise" is usually when one can't be.

I think Richi's "surprising" has to do with the fact that it lets
one inadvertently copy a large amount of data, thus leading to
an inefficiency.  But by analogy, there are infinitely many ways
to end up with inefficient code (e.g., deep recursion, or heap
allocation in a loop), and they are not a reason to ban the coding
constructs that might lead to it.

IIUC, Jason's comment about surprising effects was about implicit
conversion from auto_vec to vec.  I share that concern, and agree
that it should be addressed by preventing the conversion (as Jason
suggested).

Martin

> 
> Thanks,
> Richard
> 
>> Thanks,
>> Richard.
>>
>>> gcc/ChangeLog:
>>>
>>>          * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
>>>          * dominance.h (get_dominated_by_region): Likewise.
>>>          * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
>>>          (gimple_duplicate_sese_tail): Likewise.
>>>          (move_sese_region_to_fn): Likewise.
>>> ---
>>>   gcc/dominance.c |  4 ++--
>>>   gcc/dominance.h |  2 +-
>>>   gcc/tree-cfg.c  | 18 +++++++-----------
>>>   3 files changed, 10 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/gcc/dominance.c b/gcc/dominance.c
>>> index 0e464cb7282..4943102ff1d 100644
>>> --- a/gcc/dominance.c
>>> +++ b/gcc/dominance.c
>>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
>>>      direction DIR) by some block between N_REGION ones stored in REGION,
>>>      except for blocks in the REGION itself.  */
>>>
>>> -vec<basic_block>
>>> +auto_vec<basic_block>
>>>   get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>>>                           unsigned n_region)
>>>   {
>>>     unsigned i;
>>>     basic_block dom;
>>> -  vec<basic_block> doms = vNULL;
>>> +  auto_vec<basic_block> doms;
>>>
>>>     for (i = 0; i < n_region; i++)
>>>       region[i]->flags |= BB_DUPLICATED;
>>> diff --git a/gcc/dominance.h b/gcc/dominance.h
>>> index 515a369aacf..c74ad297c6a 100644
>>> --- a/gcc/dominance.h
>>> +++ b/gcc/dominance.h
>>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>>>   extern void set_immediate_dominator (enum cdi_direction, basic_block,
>>>                                       basic_block);
>>>   extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>                                                           basic_block *,
>>>                                                           unsigned);
>>>   extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>> index 6bdd1a561fd..c9403deed19 100644
>>> --- a/gcc/tree-cfg.c
>>> +++ b/gcc/tree-cfg.c
>>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>     bool free_region_copy = false, copying_header = false;
>>>     class loop *loop = entry->dest->loop_father;
>>>     edge exit_copy;
>>> -  vec<basic_block> doms = vNULL;
>>>     edge redirected;
>>>     profile_count total_count = profile_count::uninitialized ();
>>>     profile_count entry_count = profile_count::uninitialized ();
>>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>
>>>     /* Record blocks outside the region that are dominated by something
>>>        inside.  */
>>> +  auto_vec<basic_block> doms;
>>>     if (update_dominance)
>>>       {
>>> -      doms.create (0);
>>>         doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>       }
>>>
>>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>         set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
>>>         doms.safe_push (get_bb_original (entry->dest));
>>>         iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>> -      doms.release ();
>>>       }
>>>
>>>     /* Add the other PHI node arguments.  */
>>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>     class loop *loop = exit->dest->loop_father;
>>>     class loop *orig_loop = entry->dest->loop_father;
>>>     basic_block switch_bb, entry_bb, nentry_bb;
>>> -  vec<basic_block> doms;
>>>     profile_count total_count = profile_count::uninitialized (),
>>>                  exit_count = profile_count::uninitialized ();
>>>     edge exits[2], nexits[2], e;
>>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>
>>>     /* Record blocks outside the region that are dominated by something
>>>        inside.  */
>>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
>>> +                                                       n_region);
>>>
>>>     total_count = exit->src->count;
>>>     exit_count = exit->count ();
>>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>     /* Anything that is outside of the region, but was dominated by something
>>>        inside needs to update dominance info.  */
>>>     iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>> -  doms.release ();
>>>     /* Update the SSA web.  */
>>>     update_ssa (TODO_update_ssa);
>>>
>>> @@ -7567,7 +7564,7 @@ basic_block
>>>   move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>                          basic_block exit_bb, tree orig_block)
>>>   {
>>> -  vec<basic_block> bbs, dom_bbs;
>>> +  vec<basic_block> bbs;
>>>     basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
>>>     basic_block after, bb, *entry_pred, *exit_succ, abb;
>>>     struct function *saved_cfun = cfun;
>>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>
>>>     /* The blocks that used to be dominated by something in BBS will now be
>>>        dominated by the new block.  */
>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>> -                                    bbs.address (),
>>> -                                    bbs.length ());
>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>> +                                                          bbs.address (),
>>> +                                                          bbs.length ());
>>>
>>>     /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
>>>        the predecessor edges to ENTRY_BB and the successor edges to
>>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>     set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
>>>     FOR_EACH_VEC_ELT (dom_bbs, i, abb)
>>>       set_immediate_dominator (CDI_DOMINATORS, abb, bb);
>>> -  dom_bbs.release ();
>>>
>>>     if (exit_bb)
>>>       {
>>> --
>>> 2.20.1
>>>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH, V2] auto_vec copy/move improvements
  2021-06-16 10:13             ` Richard Biener
@ 2021-06-16 17:01               ` Martin Sebor
  0 siblings, 0 replies; 51+ messages in thread
From: Martin Sebor @ 2021-06-16 17:01 UTC (permalink / raw)
  To: Richard Biener, Trevor Saunders; +Cc: GCC Patches

On 6/16/21 4:13 AM, Richard Biener via Gcc-patches wrote:
> On Wed, Jun 16, 2021 at 5:18 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>
>> - Unfortunately using_auto_storage () needs to handle m_vec being null.
>> - Handle self move of an auto_vec to itself.
>> - Make sure auto_vec defines the classes move constructor and assignment
>>    operator, as well as ones taking vec<T>, so the compiler does not generate
>> them for us.  Per https://en.cppreference.com/w/cpp/language/move_constructor
>> the ones taking vec<T> do not count as the classes move constructor or
>> assignment operator, but we want them as well to assign a plain vec to a
>> auto_vec.
>> - Explicitly delete auto_vec's copy constructor and assignment operator.  This
>>    prevents unintentional expenssive coppies of the vector and makes it clear
>> when coppies are needed that that is what is intended.  When it is necessary to
>> copy a vector copy () can be used.
>>
>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>
>> This time without the changes to the inline storage version of auto_vec as
>> requested.  bootstrap andregtest on x86_64-linux-gnu with the other patches in
>> the series ongoing, ok if that passes?
> 
> OK.

...
>> +
>> +  // You probably don't want to copy a vector, so these are deleted to prevent
>> +  // unintentional use.  If you really need a copy of the vectors contents you
>> +  // can use copy ().
>> +  auto_vec(const auto_vec &) = delete;
>> +  auto_vec &operator= (const auto_vec &) = delete;

To reiterate, I strongly disagree with this change as well as with
the comment.

Martin


>>   };
>>
>>
>> @@ -2147,7 +2176,7 @@ template<typename T>
>>   inline bool
>>   vec<T, va_heap, vl_ptr>::using_auto_storage () const
>>   {
>> -  return m_vec->m_vecpfx.m_using_auto_storage;
>> +  return m_vec ? m_vec->m_vecpfx.m_using_auto_storage : false;
>>   }
>>
>>   /* Release VEC and call release of all element vectors.  */
>> --
>> 2.20.1
>>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-16 16:01       ` Martin Sebor
@ 2021-06-17  6:03         ` Richard Biener
  2021-06-17  8:23           ` Trevor Saunders
  2021-06-17 14:43           ` Martin Sebor
  0 siblings, 2 replies; 51+ messages in thread
From: Richard Biener @ 2021-06-17  6:03 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Richard Biener via Gcc-patches, Trevor Saunders, Richard Sandiford

On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> > Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> >> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >>>
> >>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
> >>>
> >>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> >>>
> >>> bootstrapped and regtested on x86_64-linux-gnu, ok?
> >>
> >> OK.
> >>
> >> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> >> excessive indent for
> >>
> >> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >> -                                    bbs.address (),
> >> -                                    bbs.length ());
> >> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >> +                                                          bbs.address (),
> >> +                                                          bbs.length ());
> >>
> >> and just uses
> >>
> >>    auto dom_bbs = get_dominated_by_region (...
> >>
> >> Not asking you to do this, just a question for the audience.
> >
> > Personally I think this would be surprising for something that doesn't
> > have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> > FWIW, I agree not having copy semantics is probably the most practical
> > way forward for now.)
>
> But you did open the door for me to reiterate my strong disagreement
> with that.  The best C++ practice going back to the early 1990's is
> to make types safely copyable and assignable.  It is the default for
> all types, in both C++ and C, and so natural and expected.
>
> Preventing copying is appropriate in special and rare circumstances
> (e.g, a mutex may not be copyable, or a file or iostream object may
> not be because they represent a unique physical resource.)
>
> In the absence of such special circumstances preventing copying is
> unexpected, and in the case of an essential building block such as
> a container, makes the type difficult to use.
>
> The only argument for disabling copying that has been given is
> that it could be surprising(*).  But because all types are copyable
> by default the "surprise" is usually when one can't be.
>
> I think Richi's "surprising" has to do with the fact that it lets
> one inadvertently copy a large amount of data, thus leading to
> an inefficiency.  But by analogy, there are infinitely many ways
> to end up with inefficient code (e.g., deep recursion, or heap
> allocation in a loop), and they are not a reason to ban the coding
> constructs that might lead to it.
>
> IIUC, Jason's comment about surprising effects was about implicit
> conversion from auto_vec to vec.  I share that concern, and agree
> that it should be addressed by preventing the conversion (as Jason
> suggested).

But fact is that how vec<> and auto_vec<> are used today in GCC
do not favor that.  In fact your proposed vec<> would be quite radically
different (and IMHO vec<> and auto_vec<> should be unified then to
form your proposed new container).  auto_vec<> at the moment simply
maintains ownership like a smart pointer - which is _also_ not copyable.

Richard.

> Martin
>
> >
> > Thanks,
> > Richard
> >
> >> Thanks,
> >> Richard.
> >>
> >>> gcc/ChangeLog:
> >>>
> >>>          * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
> >>>          * dominance.h (get_dominated_by_region): Likewise.
> >>>          * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
> >>>          (gimple_duplicate_sese_tail): Likewise.
> >>>          (move_sese_region_to_fn): Likewise.
> >>> ---
> >>>   gcc/dominance.c |  4 ++--
> >>>   gcc/dominance.h |  2 +-
> >>>   gcc/tree-cfg.c  | 18 +++++++-----------
> >>>   3 files changed, 10 insertions(+), 14 deletions(-)
> >>>
> >>> diff --git a/gcc/dominance.c b/gcc/dominance.c
> >>> index 0e464cb7282..4943102ff1d 100644
> >>> --- a/gcc/dominance.c
> >>> +++ b/gcc/dominance.c
> >>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
> >>>      direction DIR) by some block between N_REGION ones stored in REGION,
> >>>      except for blocks in the REGION itself.  */
> >>>
> >>> -vec<basic_block>
> >>> +auto_vec<basic_block>
> >>>   get_dominated_by_region (enum cdi_direction dir, basic_block *region,
> >>>                           unsigned n_region)
> >>>   {
> >>>     unsigned i;
> >>>     basic_block dom;
> >>> -  vec<basic_block> doms = vNULL;
> >>> +  auto_vec<basic_block> doms;
> >>>
> >>>     for (i = 0; i < n_region; i++)
> >>>       region[i]->flags |= BB_DUPLICATED;
> >>> diff --git a/gcc/dominance.h b/gcc/dominance.h
> >>> index 515a369aacf..c74ad297c6a 100644
> >>> --- a/gcc/dominance.h
> >>> +++ b/gcc/dominance.h
> >>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
> >>>   extern void set_immediate_dominator (enum cdi_direction, basic_block,
> >>>                                       basic_block);
> >>>   extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> >>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
> >>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
> >>>                                                           basic_block *,
> >>>                                                           unsigned);
> >>>   extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> >>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >>> index 6bdd1a561fd..c9403deed19 100644
> >>> --- a/gcc/tree-cfg.c
> >>> +++ b/gcc/tree-cfg.c
> >>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>     bool free_region_copy = false, copying_header = false;
> >>>     class loop *loop = entry->dest->loop_father;
> >>>     edge exit_copy;
> >>> -  vec<basic_block> doms = vNULL;
> >>>     edge redirected;
> >>>     profile_count total_count = profile_count::uninitialized ();
> >>>     profile_count entry_count = profile_count::uninitialized ();
> >>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>
> >>>     /* Record blocks outside the region that are dominated by something
> >>>        inside.  */
> >>> +  auto_vec<basic_block> doms;
> >>>     if (update_dominance)
> >>>       {
> >>> -      doms.create (0);
> >>>         doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> >>>       }
> >>>
> >>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>         set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
> >>>         doms.safe_push (get_bb_original (entry->dest));
> >>>         iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> >>> -      doms.release ();
> >>>       }
> >>>
> >>>     /* Add the other PHI node arguments.  */
> >>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>     class loop *loop = exit->dest->loop_father;
> >>>     class loop *orig_loop = entry->dest->loop_father;
> >>>     basic_block switch_bb, entry_bb, nentry_bb;
> >>> -  vec<basic_block> doms;
> >>>     profile_count total_count = profile_count::uninitialized (),
> >>>                  exit_count = profile_count::uninitialized ();
> >>>     edge exits[2], nexits[2], e;
> >>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>
> >>>     /* Record blocks outside the region that are dominated by something
> >>>        inside.  */
> >>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> >>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
> >>> +                                                       n_region);
> >>>
> >>>     total_count = exit->src->count;
> >>>     exit_count = exit->count ();
> >>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>     /* Anything that is outside of the region, but was dominated by something
> >>>        inside needs to update dominance info.  */
> >>>     iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> >>> -  doms.release ();
> >>>     /* Update the SSA web.  */
> >>>     update_ssa (TODO_update_ssa);
> >>>
> >>> @@ -7567,7 +7564,7 @@ basic_block
> >>>   move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>                          basic_block exit_bb, tree orig_block)
> >>>   {
> >>> -  vec<basic_block> bbs, dom_bbs;
> >>> +  vec<basic_block> bbs;
> >>>     basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
> >>>     basic_block after, bb, *entry_pred, *exit_succ, abb;
> >>>     struct function *saved_cfun = cfun;
> >>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>
> >>>     /* The blocks that used to be dominated by something in BBS will now be
> >>>        dominated by the new block.  */
> >>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>> -                                    bbs.address (),
> >>> -                                    bbs.length ());
> >>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>> +                                                          bbs.address (),
> >>> +                                                          bbs.length ());
> >>>
> >>>     /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
> >>>        the predecessor edges to ENTRY_BB and the successor edges to
> >>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>     set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
> >>>     FOR_EACH_VEC_ELT (dom_bbs, i, abb)
> >>>       set_immediate_dominator (CDI_DOMINATORS, abb, bb);
> >>> -  dom_bbs.release ();
> >>>
> >>>     if (exit_bb)
> >>>       {
> >>> --
> >>> 2.20.1
> >>>
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 4/6] return auto_vec from get_dominated_by
  2021-06-16  5:45         ` Bernhard Reutner-Fischer
@ 2021-06-17  6:56           ` Trevor Saunders
  0 siblings, 0 replies; 51+ messages in thread
From: Trevor Saunders @ 2021-06-17  6:56 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer; +Cc: Richard Biener, Richard Biener via Gcc-patches

On Wed, Jun 16, 2021 at 07:45:01AM +0200, Bernhard Reutner-Fischer wrote:
> On 16 June 2021 05:09:17 CEST, Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> 
> >> I'm curious why you keep the release() above and ...
> >
> >There was no particular reason, I just didn't make a very complete
> >search to remove them all, as they should be harmless.  I'm certainly
> >happy to remove them, but wonder if it wouldn't make more sense to go
> >on
> >a broader search for uses of release and see why they are necessary or
> >remove them.
> 
> Yes.
> One spot where you removed the early release() was in gimple_duplicate_sese_region and gimple_duplicate_sese_tail. I did wonder if there are adverse effects on memory usage for TUs with lots of basic blocks but you certainly thought about that when you removed the explicit doms.release().

It should have essentially no impact on memory usage as the vector will
be released when it goes out of scope either way, so removing release ()
is basically just cleaning up useless code.

thanks

Trev
> 
> thanks!

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-17  6:03         ` Richard Biener
@ 2021-06-17  8:23           ` Trevor Saunders
  2021-06-17 14:43           ` Martin Sebor
  1 sibling, 0 replies; 51+ messages in thread
From: Trevor Saunders @ 2021-06-17  8:23 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Sebor, Richard Biener via Gcc-patches, Richard Sandiford

On Thu, Jun 17, 2021 at 08:03:53AM +0200, Richard Biener wrote:
> On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
> >
> > On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> > > Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> > >> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > >>>
> > >>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
> > >>>
> > >>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > >>>
> > >>> bootstrapped and regtested on x86_64-linux-gnu, ok?
> > >>
> > >> OK.
> > >>
> > >> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> > >> excessive indent for
> > >>
> > >> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > >> -                                    bbs.address (),
> > >> -                                    bbs.length ());
> > >> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > >> +                                                          bbs.address (),
> > >> +                                                          bbs.length ());
> > >>
> > >> and just uses
> > >>
> > >>    auto dom_bbs = get_dominated_by_region (...
> > >>
> > >> Not asking you to do this, just a question for the audience.
> > >
> > > Personally I think this would be surprising for something that doesn't
> > > have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> > > FWIW, I agree not having copy semantics is probably the most practical
> > > way forward for now.)
> >
> > But you did open the door for me to reiterate my strong disagreement
> > with that.  The best C++ practice going back to the early 1990's is
> > to make types safely copyable and assignable.  It is the default for
> > all types, in both C++ and C, and so natural and expected.

For C its certainly true that any struct can be coppied with memcpy or
plain assignment, but that doesn't mean it is expected to work, just
look at vec pre c++, there was a copy macro to copy one.  I don't
believe there is a function to copy a hashtab hashtable, presumably
because it was never needed, but here too we see a C datastructure that
can simply be memcpy'd.  Its rather narrow to only look at how C and C++
handle things, so lets look at some other languages that have learned
from the previous 30 years.  IN no particular order first looking at
python https://www.afternerd.com/blog/python-copy-list/ seems like a
reasonable summary, and we see assignment is just copying a reference to
a list and you call .copy() to dupplicate the list.  I believe java is
essentially the same as python perhaps with slightly different names for
methods.  I'm not an expert but
https://flaviocopes.com/go-copying-structs/ suggests go is the same as C
except a little better since it has a GC so you don't have to refcount
yourself.  As for rust I may have linked it already, but sorry I will
again, because I believe it makes a lot of good points,
https://www.oreilly.com/library/view/programming-rust/9781491927274/ch04.html
assignment moves variables, and you call a function to make a deeper
copy.  Its also worth noting the point that rust is enforcing good C++
practice, one of which I'd say is that you move or lend values whenever
possible, rather than making coppies, certainly when copy constructors
where the only thing available making them safe was the only option, but
fortunately today's C++ is very different from the c++ of the 90's, and
we shouldn't keep the same ideas of what's the best practice either.

> > Preventing copying is appropriate in special and rare circumstances
> > (e.g, a mutex may not be copyable, or a file or iostream object may
> > not be because they represent a unique physical resource.)

Well, copying a mutex can have definable semantics, but I doubt anyone
actually wants copyable mutexs.  As for files and streams its easy to
copy files, and streams may be easy depending, and as building blocks
one can certainly argue by your logic they should be copyable.  Or we
can take Richi's example, I would think by your logic an important
building block like unique_ptr should support copying by making a copy
of the referenced object, that would preserve the 1:1 relationship
between unique_ptr objects and the objects they own.  Further it would
allow me to easily copy vector<unique_ptr<T>> or unordered_map<int,
unique_ptr<T>>.  I suspect you would not support making unique_ptr
copyable, so I think the line of what should be copy constructable is
less clear than your making it out to be here, certainly that's a rather
extreme case, but I think under the framework you propose copyable
unique_ptr is defensable.

> > In the absence of such special circumstances preventing copying is
> > unexpected, and in the case of an essential building block such as
> > a container, makes the type difficult to use.
> >
> > The only argument for disabling copying that has been given is
> > that it could be surprising(*).  But because all types are copyable

Sorry if I didn't make myself clear, its not so much suprise as a couple
things.
- its unnecessarily easy to make coppies when move would do.
- especially for people not well versed in c++ its hard to tell at a
  glance without context if something is a move or a copy.  "assignments
  are moves, the only way to copy is with copy ()" is a one sentence
  rule that can be evaluated looking at the lines in a patch without
  checking types or the like.  To distinguish a copy and a move you have
  to check the type of the RHS is it an r-value reference? is move()
  called? is it a return from a function? and probably more things I'm
  forgetting at the moment.  That's not suprise, its about making it
  code easy to read, which is an important part of a good API.

> > by default the "surprise" is usually when one can't be.
> >
> > I think Richi's "surprising" has to do with the fact that it lets
> > one inadvertently copy a large amount of data, thus leading to
> > an inefficiency.  But by analogy, there are infinitely many ways
> > to end up with inefficient code (e.g., deep recursion, or heap
> > allocation in a loop), and they are not a reason to ban the coding
> > constructs that might lead to it.

No, they are reasons to ban certain practices, but in some cases while
its a pattern that should be viewed with suspicion its also too useful
to completely ban, nested loops certainly count here.  On the other hand
we have banned gets() on the grounds its basically impossible to use
correctly, and provides little value not available other ways.  We've
also more or less stopped using varargs functions other than printf  or
K&R style function declarations, because they are dangerous and there
are better options.

thanks

Trev

> > IIUC, Jason's comment about surprising effects was about implicit
> > conversion from auto_vec to vec.  I share that concern, and agree
> > that it should be addressed by preventing the conversion (as Jason
> > suggested).
> 
> But fact is that how vec<> and auto_vec<> are used today in GCC
> do not favor that.  In fact your proposed vec<> would be quite radically
> different (and IMHO vec<> and auto_vec<> should be unified then to
> form your proposed new container).  auto_vec<> at the moment simply
> maintains ownership like a smart pointer - which is _also_ not copyable.
> 
> Richard.
> 
> > Martin
> >
> > >
> > > Thanks,
> > > Richard
> > >
> > >> Thanks,
> > >> Richard.
> > >>
> > >>> gcc/ChangeLog:
> > >>>
> > >>>          * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
> > >>>          * dominance.h (get_dominated_by_region): Likewise.
> > >>>          * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
> > >>>          (gimple_duplicate_sese_tail): Likewise.
> > >>>          (move_sese_region_to_fn): Likewise.
> > >>> ---
> > >>>   gcc/dominance.c |  4 ++--
> > >>>   gcc/dominance.h |  2 +-
> > >>>   gcc/tree-cfg.c  | 18 +++++++-----------
> > >>>   3 files changed, 10 insertions(+), 14 deletions(-)
> > >>>
> > >>> diff --git a/gcc/dominance.c b/gcc/dominance.c
> > >>> index 0e464cb7282..4943102ff1d 100644
> > >>> --- a/gcc/dominance.c
> > >>> +++ b/gcc/dominance.c
> > >>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
> > >>>      direction DIR) by some block between N_REGION ones stored in REGION,
> > >>>      except for blocks in the REGION itself.  */
> > >>>
> > >>> -vec<basic_block>
> > >>> +auto_vec<basic_block>
> > >>>   get_dominated_by_region (enum cdi_direction dir, basic_block *region,
> > >>>                           unsigned n_region)
> > >>>   {
> > >>>     unsigned i;
> > >>>     basic_block dom;
> > >>> -  vec<basic_block> doms = vNULL;
> > >>> +  auto_vec<basic_block> doms;
> > >>>
> > >>>     for (i = 0; i < n_region; i++)
> > >>>       region[i]->flags |= BB_DUPLICATED;
> > >>> diff --git a/gcc/dominance.h b/gcc/dominance.h
> > >>> index 515a369aacf..c74ad297c6a 100644
> > >>> --- a/gcc/dominance.h
> > >>> +++ b/gcc/dominance.h
> > >>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
> > >>>   extern void set_immediate_dominator (enum cdi_direction, basic_block,
> > >>>                                       basic_block);
> > >>>   extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> > >>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
> > >>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
> > >>>                                                           basic_block *,
> > >>>                                                           unsigned);
> > >>>   extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> > >>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> > >>> index 6bdd1a561fd..c9403deed19 100644
> > >>> --- a/gcc/tree-cfg.c
> > >>> +++ b/gcc/tree-cfg.c
> > >>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> > >>>     bool free_region_copy = false, copying_header = false;
> > >>>     class loop *loop = entry->dest->loop_father;
> > >>>     edge exit_copy;
> > >>> -  vec<basic_block> doms = vNULL;
> > >>>     edge redirected;
> > >>>     profile_count total_count = profile_count::uninitialized ();
> > >>>     profile_count entry_count = profile_count::uninitialized ();
> > >>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> > >>>
> > >>>     /* Record blocks outside the region that are dominated by something
> > >>>        inside.  */
> > >>> +  auto_vec<basic_block> doms;
> > >>>     if (update_dominance)
> > >>>       {
> > >>> -      doms.create (0);
> > >>>         doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> > >>>       }
> > >>>
> > >>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> > >>>         set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
> > >>>         doms.safe_push (get_bb_original (entry->dest));
> > >>>         iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> > >>> -      doms.release ();
> > >>>       }
> > >>>
> > >>>     /* Add the other PHI node arguments.  */
> > >>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> > >>>     class loop *loop = exit->dest->loop_father;
> > >>>     class loop *orig_loop = entry->dest->loop_father;
> > >>>     basic_block switch_bb, entry_bb, nentry_bb;
> > >>> -  vec<basic_block> doms;
> > >>>     profile_count total_count = profile_count::uninitialized (),
> > >>>                  exit_count = profile_count::uninitialized ();
> > >>>     edge exits[2], nexits[2], e;
> > >>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> > >>>
> > >>>     /* Record blocks outside the region that are dominated by something
> > >>>        inside.  */
> > >>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> > >>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
> > >>> +                                                       n_region);
> > >>>
> > >>>     total_count = exit->src->count;
> > >>>     exit_count = exit->count ();
> > >>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> > >>>     /* Anything that is outside of the region, but was dominated by something
> > >>>        inside needs to update dominance info.  */
> > >>>     iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> > >>> -  doms.release ();
> > >>>     /* Update the SSA web.  */
> > >>>     update_ssa (TODO_update_ssa);
> > >>>
> > >>> @@ -7567,7 +7564,7 @@ basic_block
> > >>>   move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> > >>>                          basic_block exit_bb, tree orig_block)
> > >>>   {
> > >>> -  vec<basic_block> bbs, dom_bbs;
> > >>> +  vec<basic_block> bbs;
> > >>>     basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
> > >>>     basic_block after, bb, *entry_pred, *exit_succ, abb;
> > >>>     struct function *saved_cfun = cfun;
> > >>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> > >>>
> > >>>     /* The blocks that used to be dominated by something in BBS will now be
> > >>>        dominated by the new block.  */
> > >>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > >>> -                                    bbs.address (),
> > >>> -                                    bbs.length ());
> > >>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > >>> +                                                          bbs.address (),
> > >>> +                                                          bbs.length ());
> > >>>
> > >>>     /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
> > >>>        the predecessor edges to ENTRY_BB and the successor edges to
> > >>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> > >>>     set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
> > >>>     FOR_EACH_VEC_ELT (dom_bbs, i, abb)
> > >>>       set_immediate_dominator (CDI_DOMINATORS, abb, bb);
> > >>> -  dom_bbs.release ();
> > >>>
> > >>>     if (exit_bb)
> > >>>       {
> > >>> --
> > >>> 2.20.1
> > >>>
> >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 3/6] return auto_vec from get_loop_hot_path
  2021-06-15  6:45   ` Richard Biener
@ 2021-06-17 13:48     ` Christophe Lyon
  2021-06-17 14:41       ` Trevor Saunders
  0 siblings, 1 reply; 51+ messages in thread
From: Christophe Lyon @ 2021-06-17 13:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: Trevor Saunders, GCC Patches

On Tue, 15 Jun 2021 at 08:47, Richard Biener via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On Tue, Jun 15, 2021 at 8:01 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >
> > This ensures callers take ownership of the returned vector.
> >
> > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> >
> > bootstrapped and regtested on x86_64-linux-gnu, ok?
>
> OK.

Since this was committed, I've noticed build errors (for cross-compilers):
/tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:
In function 'auto_vec<basic_block_def*> get_loop_hot_path(const
loop*)':
/tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:528:10:
error: could not convert 'path' from 'vec<basic_block_def*>' to
'auto_vec<basic_block_def*>'
   return path;
          ^
/tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:529:1:
warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

I'm using gcc-4.8.5 as host compiler

Christophe

>
> > gcc/ChangeLog:
> >
> >         * cfgloop.h (get_loop_hot_path): Return auto_vec<basic_block>.
> >         * cfgloopanal.c (get_loop_hot_path): Likewise.
> >         * tree-ssa-loop-ivcanon.c (tree_estimate_loop_size): Likewise.
> > ---
> >  gcc/cfgloop.h               | 2 +-
> >  gcc/cfgloopanal.c           | 2 +-
> >  gcc/tree-ssa-loop-ivcanon.c | 5 ++---
> >  3 files changed, 4 insertions(+), 5 deletions(-)
> >
> > diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
> > index 113241da130..5e699276c88 100644
> > --- a/gcc/cfgloop.h
> > +++ b/gcc/cfgloop.h
> > @@ -840,7 +840,7 @@ enum
> >
> >  extern void doloop_optimize_loops (void);
> >  extern void move_loop_invariants (void);
> > -extern vec<basic_block> get_loop_hot_path (const class loop *loop);
> > +extern auto_vec<basic_block> get_loop_hot_path (const class loop *loop);
> >
> >  /* Returns the outermost loop of the loop nest that contains LOOP.*/
> >  static inline class loop *
> > diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
> > index d0eade3dd34..e7b7ae2163e 100644
> > --- a/gcc/cfgloopanal.c
> > +++ b/gcc/cfgloopanal.c
> > @@ -500,7 +500,7 @@ single_likely_exit (class loop *loop, vec<edge> exits)
> >     order against direction of edges from latch.  Specially, if
> >     header != latch, latch is the 1-st block.  */
> >
> > -vec<basic_block>
> > +auto_vec<basic_block>
> >  get_loop_hot_path (const class loop *loop)
> >  {
> >    basic_block bb = loop->header;
> > diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
> > index 3f9e9d0869f..b1971f83544 100644
> > --- a/gcc/tree-ssa-loop-ivcanon.c
> > +++ b/gcc/tree-ssa-loop-ivcanon.c
> > @@ -218,7 +218,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
> >    gimple_stmt_iterator gsi;
> >    unsigned int i;
> >    bool after_exit;
> > -  vec<basic_block> path = get_loop_hot_path (loop);
> > +  auto_vec<basic_block> path = get_loop_hot_path (loop);
> >
> >    size->overall = 0;
> >    size->eliminated_by_peeling = 0;
> > @@ -342,7 +342,6 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
> >               - size->last_iteration_eliminated_by_peeling) > upper_bound)
> >             {
> >                free (body);
> > -             path.release ();
> >               return true;
> >             }
> >         }
> > @@ -379,7 +378,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
> >             size->num_branches_on_hot_path++;
> >         }
> >      }
> > -  path.release ();
> > +
> >    if (dump_file && (dump_flags & TDF_DETAILS))
> >      fprintf (dump_file, "size: %i-%i, last_iteration: %i-%i\n", size->overall,
> >              size->eliminated_by_peeling, size->last_iteration,
> > --
> > 2.20.1
> >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 3/6] return auto_vec from get_loop_hot_path
  2021-06-17 13:48     ` Christophe Lyon
@ 2021-06-17 14:41       ` Trevor Saunders
  2021-06-17 18:34         ` Christophe Lyon
  0 siblings, 1 reply; 51+ messages in thread
From: Trevor Saunders @ 2021-06-17 14:41 UTC (permalink / raw)
  To: Christophe Lyon; +Cc: Richard Biener, GCC Patches

On Thu, Jun 17, 2021 at 03:48:28PM +0200, Christophe Lyon wrote:
> On Tue, 15 Jun 2021 at 08:47, Richard Biener via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > On Tue, Jun 15, 2021 at 8:01 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > >
> > > This ensures callers take ownership of the returned vector.
> > >
> > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > >
> > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> >
> > OK.
> 
> Since this was committed, I've noticed build errors (for cross-compilers):
> /tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:
> In function 'auto_vec<basic_block_def*> get_loop_hot_path(const
> loop*)':
> /tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:528:10:
> error: could not convert 'path' from 'vec<basic_block_def*>' to
> 'auto_vec<basic_block_def*>'
>    return path;
>           ^
> /tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:529:1:
> warning: control reaches end of non-void function [-Wreturn-type]
>  }
>  ^
> 
> I'm using gcc-4.8.5 as host compiler

Ah, interesting, I believe the following patch corrects the oversight
here.  Its interesting that newer compilers use the auto_vec(vec<T> &&)
constructor to fix this up but 4.8.5 refuses.

diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index fdd8d3f43fe..2db46c81036 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -504,7 +504,7 @@ auto_vec<basic_block>
 get_loop_hot_path (const class loop *loop)
  {
     basic_block bb = loop->header;
     -  vec<basic_block> path = vNULL;
     +  auto_vec<basic_block> path;
        bitmap visited = BITMAP_ALLOC (NULL);

	   while (true)

	   Sorry about the trouble, will commit the above as obvious if
	   it bootstraps.

	   Trev

> 
> Christophe
> 
> >
> > > gcc/ChangeLog:
> > >
> > >         * cfgloop.h (get_loop_hot_path): Return auto_vec<basic_block>.
> > >         * cfgloopanal.c (get_loop_hot_path): Likewise.
> > >         * tree-ssa-loop-ivcanon.c (tree_estimate_loop_size): Likewise.
> > > ---
> > >  gcc/cfgloop.h               | 2 +-
> > >  gcc/cfgloopanal.c           | 2 +-
> > >  gcc/tree-ssa-loop-ivcanon.c | 5 ++---
> > >  3 files changed, 4 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
> > > index 113241da130..5e699276c88 100644
> > > --- a/gcc/cfgloop.h
> > > +++ b/gcc/cfgloop.h
> > > @@ -840,7 +840,7 @@ enum
> > >
> > >  extern void doloop_optimize_loops (void);
> > >  extern void move_loop_invariants (void);
> > > -extern vec<basic_block> get_loop_hot_path (const class loop *loop);
> > > +extern auto_vec<basic_block> get_loop_hot_path (const class loop *loop);
> > >
> > >  /* Returns the outermost loop of the loop nest that contains LOOP.*/
> > >  static inline class loop *
> > > diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
> > > index d0eade3dd34..e7b7ae2163e 100644
> > > --- a/gcc/cfgloopanal.c
> > > +++ b/gcc/cfgloopanal.c
> > > @@ -500,7 +500,7 @@ single_likely_exit (class loop *loop, vec<edge> exits)
> > >     order against direction of edges from latch.  Specially, if
> > >     header != latch, latch is the 1-st block.  */
> > >
> > > -vec<basic_block>
> > > +auto_vec<basic_block>
> > >  get_loop_hot_path (const class loop *loop)
> > >  {
> > >    basic_block bb = loop->header;
> > > diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
> > > index 3f9e9d0869f..b1971f83544 100644
> > > --- a/gcc/tree-ssa-loop-ivcanon.c
> > > +++ b/gcc/tree-ssa-loop-ivcanon.c
> > > @@ -218,7 +218,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
> > >    gimple_stmt_iterator gsi;
> > >    unsigned int i;
> > >    bool after_exit;
> > > -  vec<basic_block> path = get_loop_hot_path (loop);
> > > +  auto_vec<basic_block> path = get_loop_hot_path (loop);
> > >
> > >    size->overall = 0;
> > >    size->eliminated_by_peeling = 0;
> > > @@ -342,7 +342,6 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
> > >               - size->last_iteration_eliminated_by_peeling) > upper_bound)
> > >             {
> > >                free (body);
> > > -             path.release ();
> > >               return true;
> > >             }
> > >         }
> > > @@ -379,7 +378,7 @@ tree_estimate_loop_size (class loop *loop, edge exit, edge edge_to_cancel,
> > >             size->num_branches_on_hot_path++;
> > >         }
> > >      }
> > > -  path.release ();
> > > +
> > >    if (dump_file && (dump_flags & TDF_DETAILS))
> > >      fprintf (dump_file, "size: %i-%i, last_iteration: %i-%i\n", size->overall,
> > >              size->eliminated_by_peeling, size->last_iteration,
> > > --
> > > 2.20.1
> > >

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-17  6:03         ` Richard Biener
  2021-06-17  8:23           ` Trevor Saunders
@ 2021-06-17 14:43           ` Martin Sebor
  2021-06-18 10:38             ` Richard Biener
  1 sibling, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-17 14:43 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Biener via Gcc-patches, Trevor Saunders, Richard Sandiford

On 6/17/21 12:03 AM, Richard Biener wrote:
> On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
>>> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>>>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>>>>
>>>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>>>>>
>>>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>>>>
>>>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>>>>
>>>> OK.
>>>>
>>>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
>>>> excessive indent for
>>>>
>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>> -                                    bbs.address (),
>>>> -                                    bbs.length ());
>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>> +                                                          bbs.address (),
>>>> +                                                          bbs.length ());
>>>>
>>>> and just uses
>>>>
>>>>     auto dom_bbs = get_dominated_by_region (...
>>>>
>>>> Not asking you to do this, just a question for the audience.
>>>
>>> Personally I think this would be surprising for something that doesn't
>>> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
>>> FWIW, I agree not having copy semantics is probably the most practical
>>> way forward for now.)
>>
>> But you did open the door for me to reiterate my strong disagreement
>> with that.  The best C++ practice going back to the early 1990's is
>> to make types safely copyable and assignable.  It is the default for
>> all types, in both C++ and C, and so natural and expected.
>>
>> Preventing copying is appropriate in special and rare circumstances
>> (e.g, a mutex may not be copyable, or a file or iostream object may
>> not be because they represent a unique physical resource.)
>>
>> In the absence of such special circumstances preventing copying is
>> unexpected, and in the case of an essential building block such as
>> a container, makes the type difficult to use.
>>
>> The only argument for disabling copying that has been given is
>> that it could be surprising(*).  But because all types are copyable
>> by default the "surprise" is usually when one can't be.
>>
>> I think Richi's "surprising" has to do with the fact that it lets
>> one inadvertently copy a large amount of data, thus leading to
>> an inefficiency.  But by analogy, there are infinitely many ways
>> to end up with inefficient code (e.g., deep recursion, or heap
>> allocation in a loop), and they are not a reason to ban the coding
>> constructs that might lead to it.
>>
>> IIUC, Jason's comment about surprising effects was about implicit
>> conversion from auto_vec to vec.  I share that concern, and agree
>> that it should be addressed by preventing the conversion (as Jason
>> suggested).
> 
> But fact is that how vec<> and auto_vec<> are used today in GCC
> do not favor that.  In fact your proposed vec<> would be quite radically
> different (and IMHO vec<> and auto_vec<> should be unified then to
> form your proposed new container).  auto_vec<> at the moment simply
> maintains ownership like a smart pointer - which is _also_ not copyable.

Yes, as we discussed in the review below, vec is not a good model
because (as you note again above) it's constrained by its legacy
uses.  The best I think we can do for it is to make it safer to
use.
https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html

(Smart pointers don't rule out copying.  A std::unique_ptr does
and std::shared_ptr doesn't.  But vec and especially auto_vec
are designed to be containers, not "unique pointers" so any
relationship there is purely superficial and a distraction.)

That auto_vec and vec share a name and an is-a relationship is
incidental, an implementation detail leaked into the API.  A better
name than vector is hard to come up with, but the public inheritance
is a design flaw, a bug waiting to be introduced due to the conversion
and the assumptions the base vec makes about POD-ness and shallow
copying.  Hindsight is always 20/20 but past mistakes should not
dictate the design of a general purpose vector-like container in
GCC.

I fully support fixing or at least mitigating the problems with
the vec base class (unsafe copying, pass-by-value etc.).  As I
mentioned, I already started working on this cleanup.  I also
have no objection to introducing a non-copyable form of a vector
template (I offered one in my patch), or even to making auto_vec
non-copyable provided a copyable and assignable one is introduced
at the same time, under some other name.

Having said that, and although I don't mind the cleanup being taken
off my plate, I would have expected the courtesy of at least a heads
up first.  I do find it disrespectful for someone else involved in
the review of my work to at the same time submit a patch of their
own that goes in the opposite direction, and for you to unilaterally
approve it while the other review hasn't concluded yet.

Martin

> 
> Richard.
> 
>> Martin
>>
>>>
>>> Thanks,
>>> Richard
>>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>>> gcc/ChangeLog:
>>>>>
>>>>>           * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
>>>>>           * dominance.h (get_dominated_by_region): Likewise.
>>>>>           * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
>>>>>           (gimple_duplicate_sese_tail): Likewise.
>>>>>           (move_sese_region_to_fn): Likewise.
>>>>> ---
>>>>>    gcc/dominance.c |  4 ++--
>>>>>    gcc/dominance.h |  2 +-
>>>>>    gcc/tree-cfg.c  | 18 +++++++-----------
>>>>>    3 files changed, 10 insertions(+), 14 deletions(-)
>>>>>
>>>>> diff --git a/gcc/dominance.c b/gcc/dominance.c
>>>>> index 0e464cb7282..4943102ff1d 100644
>>>>> --- a/gcc/dominance.c
>>>>> +++ b/gcc/dominance.c
>>>>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
>>>>>       direction DIR) by some block between N_REGION ones stored in REGION,
>>>>>       except for blocks in the REGION itself.  */
>>>>>
>>>>> -vec<basic_block>
>>>>> +auto_vec<basic_block>
>>>>>    get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>>>>>                            unsigned n_region)
>>>>>    {
>>>>>      unsigned i;
>>>>>      basic_block dom;
>>>>> -  vec<basic_block> doms = vNULL;
>>>>> +  auto_vec<basic_block> doms;
>>>>>
>>>>>      for (i = 0; i < n_region; i++)
>>>>>        region[i]->flags |= BB_DUPLICATED;
>>>>> diff --git a/gcc/dominance.h b/gcc/dominance.h
>>>>> index 515a369aacf..c74ad297c6a 100644
>>>>> --- a/gcc/dominance.h
>>>>> +++ b/gcc/dominance.h
>>>>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>>>>>    extern void set_immediate_dominator (enum cdi_direction, basic_block,
>>>>>                                        basic_block);
>>>>>    extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>>>>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>>>                                                            basic_block *,
>>>>>                                                            unsigned);
>>>>>    extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>> index 6bdd1a561fd..c9403deed19 100644
>>>>> --- a/gcc/tree-cfg.c
>>>>> +++ b/gcc/tree-cfg.c
>>>>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>      bool free_region_copy = false, copying_header = false;
>>>>>      class loop *loop = entry->dest->loop_father;
>>>>>      edge exit_copy;
>>>>> -  vec<basic_block> doms = vNULL;
>>>>>      edge redirected;
>>>>>      profile_count total_count = profile_count::uninitialized ();
>>>>>      profile_count entry_count = profile_count::uninitialized ();
>>>>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>
>>>>>      /* Record blocks outside the region that are dominated by something
>>>>>         inside.  */
>>>>> +  auto_vec<basic_block> doms;
>>>>>      if (update_dominance)
>>>>>        {
>>>>> -      doms.create (0);
>>>>>          doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>>>        }
>>>>>
>>>>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>          set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
>>>>>          doms.safe_push (get_bb_original (entry->dest));
>>>>>          iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>>>> -      doms.release ();
>>>>>        }
>>>>>
>>>>>      /* Add the other PHI node arguments.  */
>>>>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>      class loop *loop = exit->dest->loop_father;
>>>>>      class loop *orig_loop = entry->dest->loop_father;
>>>>>      basic_block switch_bb, entry_bb, nentry_bb;
>>>>> -  vec<basic_block> doms;
>>>>>      profile_count total_count = profile_count::uninitialized (),
>>>>>                   exit_count = profile_count::uninitialized ();
>>>>>      edge exits[2], nexits[2], e;
>>>>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>
>>>>>      /* Record blocks outside the region that are dominated by something
>>>>>         inside.  */
>>>>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
>>>>> +                                                       n_region);
>>>>>
>>>>>      total_count = exit->src->count;
>>>>>      exit_count = exit->count ();
>>>>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>      /* Anything that is outside of the region, but was dominated by something
>>>>>         inside needs to update dominance info.  */
>>>>>      iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>>>> -  doms.release ();
>>>>>      /* Update the SSA web.  */
>>>>>      update_ssa (TODO_update_ssa);
>>>>>
>>>>> @@ -7567,7 +7564,7 @@ basic_block
>>>>>    move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>                           basic_block exit_bb, tree orig_block)
>>>>>    {
>>>>> -  vec<basic_block> bbs, dom_bbs;
>>>>> +  vec<basic_block> bbs;
>>>>>      basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
>>>>>      basic_block after, bb, *entry_pred, *exit_succ, abb;
>>>>>      struct function *saved_cfun = cfun;
>>>>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>
>>>>>      /* The blocks that used to be dominated by something in BBS will now be
>>>>>         dominated by the new block.  */
>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>> -                                    bbs.address (),
>>>>> -                                    bbs.length ());
>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>> +                                                          bbs.address (),
>>>>> +                                                          bbs.length ());
>>>>>
>>>>>      /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
>>>>>         the predecessor edges to ENTRY_BB and the successor edges to
>>>>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>      set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
>>>>>      FOR_EACH_VEC_ELT (dom_bbs, i, abb)
>>>>>        set_immediate_dominator (CDI_DOMINATORS, abb, bb);
>>>>> -  dom_bbs.release ();
>>>>>
>>>>>      if (exit_bb)
>>>>>        {
>>>>> --
>>>>> 2.20.1
>>>>>
>>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 3/6] return auto_vec from get_loop_hot_path
  2021-06-17 14:41       ` Trevor Saunders
@ 2021-06-17 18:34         ` Christophe Lyon
  0 siblings, 0 replies; 51+ messages in thread
From: Christophe Lyon @ 2021-06-17 18:34 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Christophe Lyon, GCC Patches

On Thu, Jun 17, 2021 at 4:53 PM Trevor Saunders <tbsaunde@tbsaunde.org>
wrote:

> On Thu, Jun 17, 2021 at 03:48:28PM +0200, Christophe Lyon wrote:
> > On Tue, 15 Jun 2021 at 08:47, Richard Biener via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > > On Tue, Jun 15, 2021 at 8:01 AM Trevor Saunders <tbsaunde@tbsaunde.org>
> wrote:
> > > >
> > > > This ensures callers take ownership of the returned vector.
> > > >
> > > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > > >
> > > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > >
> > > OK.
> >
> > Since this was committed, I've noticed build errors (for
> cross-compilers):
> >
> /tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:
> > In function 'auto_vec<basic_block_def*> get_loop_hot_path(const
> > loop*)':
> >
> /tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:528:10:
> > error: could not convert 'path' from 'vec<basic_block_def*>' to
> > 'auto_vec<basic_block_def*>'
> >    return path;
> >           ^
> >
> /tmp/9562118_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgloopanal.c:529:1:
> > warning: control reaches end of non-void function [-Wreturn-type]
> >  }
> >  ^
> >
> > I'm using gcc-4.8.5 as host compiler
>
> Ah, interesting, I believe the following patch corrects the oversight
> here.  Its interesting that newer compilers use the auto_vec(vec<T> &&)
> constructor to fix this up but 4.8.5 refuses.
>
> diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
> index fdd8d3f43fe..2db46c81036 100644
> --- a/gcc/cfgloopanal.c
> +++ b/gcc/cfgloopanal.c
> @@ -504,7 +504,7 @@ auto_vec<basic_block>
>  get_loop_hot_path (const class loop *loop)
>   {
>      basic_block bb = loop->header;
>      -  vec<basic_block> path = vNULL;
>      +  auto_vec<basic_block> path;
>         bitmap visited = BITMAP_ALLOC (NULL);
>
>            while (true)
>
>            Sorry about the trouble, will commit the above as obvious if
>            it bootstraps.
>
>
Thanks, I confirm the builds complete again.

Christophe


>            Trev
>
> >
> > Christophe
> >
> > >
> > > > gcc/ChangeLog:
> > > >
> > > >         * cfgloop.h (get_loop_hot_path): Return
> auto_vec<basic_block>.
> > > >         * cfgloopanal.c (get_loop_hot_path): Likewise.
> > > >         * tree-ssa-loop-ivcanon.c (tree_estimate_loop_size):
> Likewise.
> > > > ---
> > > >  gcc/cfgloop.h               | 2 +-
> > > >  gcc/cfgloopanal.c           | 2 +-
> > > >  gcc/tree-ssa-loop-ivcanon.c | 5 ++---
> > > >  3 files changed, 4 insertions(+), 5 deletions(-)
> > > >
> > > > diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
> > > > index 113241da130..5e699276c88 100644
> > > > --- a/gcc/cfgloop.h
> > > > +++ b/gcc/cfgloop.h
> > > > @@ -840,7 +840,7 @@ enum
> > > >
> > > >  extern void doloop_optimize_loops (void);
> > > >  extern void move_loop_invariants (void);
> > > > -extern vec<basic_block> get_loop_hot_path (const class loop *loop);
> > > > +extern auto_vec<basic_block> get_loop_hot_path (const class loop
> *loop);
> > > >
> > > >  /* Returns the outermost loop of the loop nest that contains LOOP.*/
> > > >  static inline class loop *
> > > > diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
> > > > index d0eade3dd34..e7b7ae2163e 100644
> > > > --- a/gcc/cfgloopanal.c
> > > > +++ b/gcc/cfgloopanal.c
> > > > @@ -500,7 +500,7 @@ single_likely_exit (class loop *loop, vec<edge>
> exits)
> > > >     order against direction of edges from latch.  Specially, if
> > > >     header != latch, latch is the 1-st block.  */
> > > >
> > > > -vec<basic_block>
> > > > +auto_vec<basic_block>
> > > >  get_loop_hot_path (const class loop *loop)
> > > >  {
> > > >    basic_block bb = loop->header;
> > > > diff --git a/gcc/tree-ssa-loop-ivcanon.c
> b/gcc/tree-ssa-loop-ivcanon.c
> > > > index 3f9e9d0869f..b1971f83544 100644
> > > > --- a/gcc/tree-ssa-loop-ivcanon.c
> > > > +++ b/gcc/tree-ssa-loop-ivcanon.c
> > > > @@ -218,7 +218,7 @@ tree_estimate_loop_size (class loop *loop, edge
> exit, edge edge_to_cancel,
> > > >    gimple_stmt_iterator gsi;
> > > >    unsigned int i;
> > > >    bool after_exit;
> > > > -  vec<basic_block> path = get_loop_hot_path (loop);
> > > > +  auto_vec<basic_block> path = get_loop_hot_path (loop);
> > > >
> > > >    size->overall = 0;
> > > >    size->eliminated_by_peeling = 0;
> > > > @@ -342,7 +342,6 @@ tree_estimate_loop_size (class loop *loop, edge
> exit, edge edge_to_cancel,
> > > >               - size->last_iteration_eliminated_by_peeling) >
> upper_bound)
> > > >             {
> > > >                free (body);
> > > > -             path.release ();
> > > >               return true;
> > > >             }
> > > >         }
> > > > @@ -379,7 +378,7 @@ tree_estimate_loop_size (class loop *loop, edge
> exit, edge edge_to_cancel,
> > > >             size->num_branches_on_hot_path++;
> > > >         }
> > > >      }
> > > > -  path.release ();
> > > > +
> > > >    if (dump_file && (dump_flags & TDF_DETAILS))
> > > >      fprintf (dump_file, "size: %i-%i, last_iteration: %i-%i\n",
> size->overall,
> > > >              size->eliminated_by_peeling, size->last_iteration,
> > > > --
> > > > 2.20.1
> > > >
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-17 14:43           ` Martin Sebor
@ 2021-06-18 10:38             ` Richard Biener
  2021-06-18 10:53               ` Jakub Jelinek
  2021-06-18 16:03               ` Martin Sebor
  0 siblings, 2 replies; 51+ messages in thread
From: Richard Biener @ 2021-06-18 10:38 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Richard Biener via Gcc-patches, Trevor Saunders, Richard Sandiford

On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/17/21 12:03 AM, Richard Biener wrote:
> > On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
> >>
> >> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> >>> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> >>>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >>>>>
> >>>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
> >>>>>
> >>>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> >>>>>
> >>>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
> >>>>
> >>>> OK.
> >>>>
> >>>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> >>>> excessive indent for
> >>>>
> >>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>> -                                    bbs.address (),
> >>>> -                                    bbs.length ());
> >>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>> +                                                          bbs.address (),
> >>>> +                                                          bbs.length ());
> >>>>
> >>>> and just uses
> >>>>
> >>>>     auto dom_bbs = get_dominated_by_region (...
> >>>>
> >>>> Not asking you to do this, just a question for the audience.
> >>>
> >>> Personally I think this would be surprising for something that doesn't
> >>> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> >>> FWIW, I agree not having copy semantics is probably the most practical
> >>> way forward for now.)
> >>
> >> But you did open the door for me to reiterate my strong disagreement
> >> with that.  The best C++ practice going back to the early 1990's is
> >> to make types safely copyable and assignable.  It is the default for
> >> all types, in both C++ and C, and so natural and expected.
> >>
> >> Preventing copying is appropriate in special and rare circumstances
> >> (e.g, a mutex may not be copyable, or a file or iostream object may
> >> not be because they represent a unique physical resource.)
> >>
> >> In the absence of such special circumstances preventing copying is
> >> unexpected, and in the case of an essential building block such as
> >> a container, makes the type difficult to use.
> >>
> >> The only argument for disabling copying that has been given is
> >> that it could be surprising(*).  But because all types are copyable
> >> by default the "surprise" is usually when one can't be.
> >>
> >> I think Richi's "surprising" has to do with the fact that it lets
> >> one inadvertently copy a large amount of data, thus leading to
> >> an inefficiency.  But by analogy, there are infinitely many ways
> >> to end up with inefficient code (e.g., deep recursion, or heap
> >> allocation in a loop), and they are not a reason to ban the coding
> >> constructs that might lead to it.
> >>
> >> IIUC, Jason's comment about surprising effects was about implicit
> >> conversion from auto_vec to vec.  I share that concern, and agree
> >> that it should be addressed by preventing the conversion (as Jason
> >> suggested).
> >
> > But fact is that how vec<> and auto_vec<> are used today in GCC
> > do not favor that.  In fact your proposed vec<> would be quite radically
> > different (and IMHO vec<> and auto_vec<> should be unified then to
> > form your proposed new container).  auto_vec<> at the moment simply
> > maintains ownership like a smart pointer - which is _also_ not copyable.
>
> Yes, as we discussed in the review below, vec is not a good model
> because (as you note again above) it's constrained by its legacy
> uses.  The best I think we can do for it is to make it safer to
> use.
> https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html

Which is what Trevors patches do by simply disallowing things
that do not work at the moment.

> (Smart pointers don't rule out copying.  A std::unique_ptr does
> and std::shared_ptr doesn't.  But vec and especially auto_vec
> are designed to be containers, not "unique pointers" so any
> relationship there is purely superficial and a distraction.)
>
> That auto_vec and vec share a name and an is-a relationship is
> incidental, an implementation detail leaked into the API.  A better
> name than vector is hard to come up with, but the public inheritance
> is a design flaw, a bug waiting to be introduced due to the conversion
> and the assumptions the base vec makes about POD-ness and shallow
> copying.  Hindsight is always 20/20 but past mistakes should not
> dictate the design of a general purpose vector-like container in
> GCC.

That auto_vec<> "decays" to vec<> was on purpose design.

By-value passing of vec<> is also on purpose to avoid an extra
pointer indirection on each access.

> I fully support fixing or at least mitigating the problems with
> the vec base class (unsafe copying, pass-by-value etc.).  As I
> mentioned, I already started working on this cleanup.  I also
> have no objection to introducing a non-copyable form of a vector
> template (I offered one in my patch), or even to making auto_vec
> non-copyable provided a copyable and assignable one is introduced
> at the same time, under some other name.

Why at the same time?  I'm still not convinced we need another
vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
but then auto_vec<> doesn't bother to call the DTOR on its elements
either (it's actually vec<> again here).  So auto_vec<> is _not_
a fancier C++ vec<>, it's still just vec<> but with RAII for the container
itself.

> Having said that, and although I don't mind the cleanup being taken
> off my plate, I would have expected the courtesy of at least a heads
> up first.  I do find it disrespectful for someone else involved in
> the review of my work to at the same time submit a patch of their
> own that goes in the opposite direction, and for you to unilaterally
> approve it while the other review hasn't concluded yet.

Because the changes do not change anything as far as I understand.
They make more use of auto_vec<> ownership similar to when
I added the move ctor and adjusted a single loop API.  At the same
time it completes the move stuff and plugs some holes.

Richard.

> Martin
>
> >
> > Richard.
> >
> >> Martin
> >>
> >>>
> >>> Thanks,
> >>> Richard
> >>>
> >>>> Thanks,
> >>>> Richard.
> >>>>
> >>>>> gcc/ChangeLog:
> >>>>>
> >>>>>           * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
> >>>>>           * dominance.h (get_dominated_by_region): Likewise.
> >>>>>           * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
> >>>>>           (gimple_duplicate_sese_tail): Likewise.
> >>>>>           (move_sese_region_to_fn): Likewise.
> >>>>> ---
> >>>>>    gcc/dominance.c |  4 ++--
> >>>>>    gcc/dominance.h |  2 +-
> >>>>>    gcc/tree-cfg.c  | 18 +++++++-----------
> >>>>>    3 files changed, 10 insertions(+), 14 deletions(-)
> >>>>>
> >>>>> diff --git a/gcc/dominance.c b/gcc/dominance.c
> >>>>> index 0e464cb7282..4943102ff1d 100644
> >>>>> --- a/gcc/dominance.c
> >>>>> +++ b/gcc/dominance.c
> >>>>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
> >>>>>       direction DIR) by some block between N_REGION ones stored in REGION,
> >>>>>       except for blocks in the REGION itself.  */
> >>>>>
> >>>>> -vec<basic_block>
> >>>>> +auto_vec<basic_block>
> >>>>>    get_dominated_by_region (enum cdi_direction dir, basic_block *region,
> >>>>>                            unsigned n_region)
> >>>>>    {
> >>>>>      unsigned i;
> >>>>>      basic_block dom;
> >>>>> -  vec<basic_block> doms = vNULL;
> >>>>> +  auto_vec<basic_block> doms;
> >>>>>
> >>>>>      for (i = 0; i < n_region; i++)
> >>>>>        region[i]->flags |= BB_DUPLICATED;
> >>>>> diff --git a/gcc/dominance.h b/gcc/dominance.h
> >>>>> index 515a369aacf..c74ad297c6a 100644
> >>>>> --- a/gcc/dominance.h
> >>>>> +++ b/gcc/dominance.h
> >>>>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
> >>>>>    extern void set_immediate_dominator (enum cdi_direction, basic_block,
> >>>>>                                        basic_block);
> >>>>>    extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> >>>>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
> >>>>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
> >>>>>                                                            basic_block *,
> >>>>>                                                            unsigned);
> >>>>>    extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> >>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >>>>> index 6bdd1a561fd..c9403deed19 100644
> >>>>> --- a/gcc/tree-cfg.c
> >>>>> +++ b/gcc/tree-cfg.c
> >>>>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>>>      bool free_region_copy = false, copying_header = false;
> >>>>>      class loop *loop = entry->dest->loop_father;
> >>>>>      edge exit_copy;
> >>>>> -  vec<basic_block> doms = vNULL;
> >>>>>      edge redirected;
> >>>>>      profile_count total_count = profile_count::uninitialized ();
> >>>>>      profile_count entry_count = profile_count::uninitialized ();
> >>>>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>>>
> >>>>>      /* Record blocks outside the region that are dominated by something
> >>>>>         inside.  */
> >>>>> +  auto_vec<basic_block> doms;
> >>>>>      if (update_dominance)
> >>>>>        {
> >>>>> -      doms.create (0);
> >>>>>          doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> >>>>>        }
> >>>>>
> >>>>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>>>          set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
> >>>>>          doms.safe_push (get_bb_original (entry->dest));
> >>>>>          iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> >>>>> -      doms.release ();
> >>>>>        }
> >>>>>
> >>>>>      /* Add the other PHI node arguments.  */
> >>>>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>>>      class loop *loop = exit->dest->loop_father;
> >>>>>      class loop *orig_loop = entry->dest->loop_father;
> >>>>>      basic_block switch_bb, entry_bb, nentry_bb;
> >>>>> -  vec<basic_block> doms;
> >>>>>      profile_count total_count = profile_count::uninitialized (),
> >>>>>                   exit_count = profile_count::uninitialized ();
> >>>>>      edge exits[2], nexits[2], e;
> >>>>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>>>
> >>>>>      /* Record blocks outside the region that are dominated by something
> >>>>>         inside.  */
> >>>>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> >>>>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
> >>>>> +                                                       n_region);
> >>>>>
> >>>>>      total_count = exit->src->count;
> >>>>>      exit_count = exit->count ();
> >>>>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>>>      /* Anything that is outside of the region, but was dominated by something
> >>>>>         inside needs to update dominance info.  */
> >>>>>      iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> >>>>> -  doms.release ();
> >>>>>      /* Update the SSA web.  */
> >>>>>      update_ssa (TODO_update_ssa);
> >>>>>
> >>>>> @@ -7567,7 +7564,7 @@ basic_block
> >>>>>    move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>>>                           basic_block exit_bb, tree orig_block)
> >>>>>    {
> >>>>> -  vec<basic_block> bbs, dom_bbs;
> >>>>> +  vec<basic_block> bbs;
> >>>>>      basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
> >>>>>      basic_block after, bb, *entry_pred, *exit_succ, abb;
> >>>>>      struct function *saved_cfun = cfun;
> >>>>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>>>
> >>>>>      /* The blocks that used to be dominated by something in BBS will now be
> >>>>>         dominated by the new block.  */
> >>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>>> -                                    bbs.address (),
> >>>>> -                                    bbs.length ());
> >>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>>> +                                                          bbs.address (),
> >>>>> +                                                          bbs.length ());
> >>>>>
> >>>>>      /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
> >>>>>         the predecessor edges to ENTRY_BB and the successor edges to
> >>>>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>>>      set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
> >>>>>      FOR_EACH_VEC_ELT (dom_bbs, i, abb)
> >>>>>        set_immediate_dominator (CDI_DOMINATORS, abb, bb);
> >>>>> -  dom_bbs.release ();
> >>>>>
> >>>>>      if (exit_bb)
> >>>>>        {
> >>>>> --
> >>>>> 2.20.1
> >>>>>
> >>
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-18 10:38             ` Richard Biener
@ 2021-06-18 10:53               ` Jakub Jelinek
  2021-06-18 11:03                 ` Jonathan Wakely
  2021-06-18 16:03               ` Martin Sebor
  1 sibling, 1 reply; 51+ messages in thread
From: Jakub Jelinek @ 2021-06-18 10:53 UTC (permalink / raw)
  To: Richard Biener, Jonathan Wakely
  Cc: Martin Sebor, Trevor Saunders, Richard Biener via Gcc-patches,
	Richard Sandiford

On Fri, Jun 18, 2021 at 12:38:09PM +0200, Richard Biener via Gcc-patches wrote:
> > Yes, as we discussed in the review below, vec is not a good model
> > because (as you note again above) it's constrained by its legacy
> > uses.  The best I think we can do for it is to make it safer to
> > use.
> > https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> 
> Which is what Trevors patches do by simply disallowing things
> that do not work at the moment.

I only see
  // You probably don't want to copy a vector, so these are deleted to prevent
  // unintentional use.  If you really need a copy of the vectors contents you
  // can use copy ().
  auto_vec(const auto_vec &) = delete;
  auto_vec &operator= (const auto_vec &) = delete;
on the
template<typename T>
class auto_vec<T, 0> : public vec<T, va_heap>
specialization, but not on the
template<typename T, size_t N = 0>
class auto_vec : public vec<T, va_heap>
template itself.  Shouldn't that one have also the deleted
copy ctor/assignment operator and in addition to that maybe deleted
move ctor/move assignment operator?

	Jakub


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-18 10:53               ` Jakub Jelinek
@ 2021-06-18 11:03                 ` Jonathan Wakely
  2021-06-18 11:04                   ` Jonathan Wakely
  0 siblings, 1 reply; 51+ messages in thread
From: Jonathan Wakely @ 2021-06-18 11:03 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Biener, Martin Sebor, Trevor Saunders,
	Richard Biener via Gcc-patches, Richard Sandiford

On Fri, 18 Jun 2021 at 11:54, Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Fri, Jun 18, 2021 at 12:38:09PM +0200, Richard Biener via Gcc-patches wrote:
> > > Yes, as we discussed in the review below, vec is not a good model
> > > because (as you note again above) it's constrained by its legacy
> > > uses.  The best I think we can do for it is to make it safer to
> > > use.
> > > https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> >
> > Which is what Trevors patches do by simply disallowing things
> > that do not work at the moment.
>
> I only see
>   // You probably don't want to copy a vector, so these are deleted to prevent
>   // unintentional use.  If you really need a copy of the vectors contents you
>   // can use copy ().
>   auto_vec(const auto_vec &) = delete;
>   auto_vec &operator= (const auto_vec &) = delete;
> on the
> template<typename T>
> class auto_vec<T, 0> : public vec<T, va_heap>
> specialization, but not on the
> template<typename T, size_t N = 0>
> class auto_vec : public vec<T, va_heap>
> template itself.  Shouldn't that one have also the deleted
> copy ctor/assignment operator and in addition to that maybe deleted
> move ctor/move assignment operator?

That might have some value as documentation for people reading the
code, but it's not necessary. If vec has a deleted copy ctor and copy
assignment then it has no implicitly-defined move ctor and move
assignment. And the same goes for anything deriving from vec.


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-18 11:03                 ` Jonathan Wakely
@ 2021-06-18 11:04                   ` Jonathan Wakely
  0 siblings, 0 replies; 51+ messages in thread
From: Jonathan Wakely @ 2021-06-18 11:04 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Biener, Martin Sebor, Trevor Saunders,
	Richard Biener via Gcc-patches, Richard Sandiford

On Fri, 18 Jun 2021 at 12:03, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Fri, 18 Jun 2021 at 11:54, Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > On Fri, Jun 18, 2021 at 12:38:09PM +0200, Richard Biener via Gcc-patches wrote:
> > > > Yes, as we discussed in the review below, vec is not a good model
> > > > because (as you note again above) it's constrained by its legacy
> > > > uses.  The best I think we can do for it is to make it safer to
> > > > use.
> > > > https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> > >
> > > Which is what Trevors patches do by simply disallowing things
> > > that do not work at the moment.
> >
> > I only see
> >   // You probably don't want to copy a vector, so these are deleted to prevent
> >   // unintentional use.  If you really need a copy of the vectors contents you
> >   // can use copy ().
> >   auto_vec(const auto_vec &) = delete;
> >   auto_vec &operator= (const auto_vec &) = delete;
> > on the
> > template<typename T>
> > class auto_vec<T, 0> : public vec<T, va_heap>
> > specialization, but not on the
> > template<typename T, size_t N = 0>
> > class auto_vec : public vec<T, va_heap>
> > template itself.  Shouldn't that one have also the deleted
> > copy ctor/assignment operator and in addition to that maybe deleted
> > move ctor/move assignment operator?
>
> That might have some value as documentation for people reading the
> code, but it's not necessary. If vec has a deleted copy ctor and copy
> assignment then it has no implicitly-defined move ctor and move
> assignment. And the same goes for anything deriving from vec.

Oh sorry, I misread the first snippet.

So yes, it should probably be on both specializations. But deleting
the moves is not necessary.


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-18 10:38             ` Richard Biener
  2021-06-18 10:53               ` Jakub Jelinek
@ 2021-06-18 16:03               ` Martin Sebor
  2021-06-21  7:15                 ` Richard Biener
  1 sibling, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-18 16:03 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Biener via Gcc-patches, Trevor Saunders, Richard Sandiford

On 6/18/21 4:38 AM, Richard Biener wrote:
> On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 6/17/21 12:03 AM, Richard Biener wrote:
>>> On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
>>>>> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>>>>>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>>>>>>
>>>>>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>>>>>>>
>>>>>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>>>>>>
>>>>>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>>>>>>
>>>>>> OK.
>>>>>>
>>>>>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
>>>>>> excessive indent for
>>>>>>
>>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>> -                                    bbs.address (),
>>>>>> -                                    bbs.length ());
>>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>> +                                                          bbs.address (),
>>>>>> +                                                          bbs.length ());
>>>>>>
>>>>>> and just uses
>>>>>>
>>>>>>      auto dom_bbs = get_dominated_by_region (...
>>>>>>
>>>>>> Not asking you to do this, just a question for the audience.
>>>>>
>>>>> Personally I think this would be surprising for something that doesn't
>>>>> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
>>>>> FWIW, I agree not having copy semantics is probably the most practical
>>>>> way forward for now.)
>>>>
>>>> But you did open the door for me to reiterate my strong disagreement
>>>> with that.  The best C++ practice going back to the early 1990's is
>>>> to make types safely copyable and assignable.  It is the default for
>>>> all types, in both C++ and C, and so natural and expected.
>>>>
>>>> Preventing copying is appropriate in special and rare circumstances
>>>> (e.g, a mutex may not be copyable, or a file or iostream object may
>>>> not be because they represent a unique physical resource.)
>>>>
>>>> In the absence of such special circumstances preventing copying is
>>>> unexpected, and in the case of an essential building block such as
>>>> a container, makes the type difficult to use.
>>>>
>>>> The only argument for disabling copying that has been given is
>>>> that it could be surprising(*).  But because all types are copyable
>>>> by default the "surprise" is usually when one can't be.
>>>>
>>>> I think Richi's "surprising" has to do with the fact that it lets
>>>> one inadvertently copy a large amount of data, thus leading to
>>>> an inefficiency.  But by analogy, there are infinitely many ways
>>>> to end up with inefficient code (e.g., deep recursion, or heap
>>>> allocation in a loop), and they are not a reason to ban the coding
>>>> constructs that might lead to it.
>>>>
>>>> IIUC, Jason's comment about surprising effects was about implicit
>>>> conversion from auto_vec to vec.  I share that concern, and agree
>>>> that it should be addressed by preventing the conversion (as Jason
>>>> suggested).
>>>
>>> But fact is that how vec<> and auto_vec<> are used today in GCC
>>> do not favor that.  In fact your proposed vec<> would be quite radically
>>> different (and IMHO vec<> and auto_vec<> should be unified then to
>>> form your proposed new container).  auto_vec<> at the moment simply
>>> maintains ownership like a smart pointer - which is _also_ not copyable.
>>
>> Yes, as we discussed in the review below, vec is not a good model
>> because (as you note again above) it's constrained by its legacy
>> uses.  The best I think we can do for it is to make it safer to
>> use.
>> https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> 
> Which is what Trevors patches do by simply disallowing things
> that do not work at the moment.
> 
>> (Smart pointers don't rule out copying.  A std::unique_ptr does
>> and std::shared_ptr doesn't.  But vec and especially auto_vec
>> are designed to be containers, not "unique pointers" so any
>> relationship there is purely superficial and a distraction.)
>>
>> That auto_vec and vec share a name and an is-a relationship is
>> incidental, an implementation detail leaked into the API.  A better
>> name than vector is hard to come up with, but the public inheritance
>> is a design flaw, a bug waiting to be introduced due to the conversion
>> and the assumptions the base vec makes about POD-ness and shallow
>> copying.  Hindsight is always 20/20 but past mistakes should not
>> dictate the design of a general purpose vector-like container in
>> GCC.
> 
> That auto_vec<> "decays" to vec<> was on purpose design.
> 
> By-value passing of vec<> is also on purpose to avoid an extra
> pointer indirection on each access.

I think you may have misunderstood what I mean by is-a relationship.
It's fine to convert an auto_vec to another interface.  The danger
is in allowing that to happen implicitly because that tends to let
it happen even when it's not intended.  The usual way to avoid
that risk is to provide a conversion function, like
auto_vec::to_vec().  This is also why standard classes like
std::vector or std::string don't allow such implicit conversions
and instead provide member functions (see for example Stroustrup:
The C++ Programming Language).  So a safer auto_vec class would
not be publicly derived from vec but instead use the has-a design
(there are also ways to keep the derivation by deriving both from
from a limited, safe, interface, that each would extend as
appropriate).

To the point of by passing vec by value while allowing functions
to modify the argument: C and C++ have by-value semantics.  Every
C and C++ programmer knows and expect that.  Designing interfaces
that break this assumption is perverse, a sure recipe for bugs.
If you're concerned about intuitive semantics and surprises you
should want to avoid that.

> 
>> I fully support fixing or at least mitigating the problems with
>> the vec base class (unsafe copying, pass-by-value etc.).  As I
>> mentioned, I already started working on this cleanup.  I also
>> have no objection to introducing a non-copyable form of a vector
>> template (I offered one in my patch), or even to making auto_vec
>> non-copyable provided a copyable and assignable one is introduced
>> at the same time, under some other name.
> 
> Why at the same time?  I'm still not convinced we need another
> vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
> but then auto_vec<> doesn't bother to call the DTOR on its elements
> either (it's actually vec<> again here).  So auto_vec<> is _not_
> a fancier C++ vec<>, it's still just vec<> but with RAII for the container
> itself.

I don't follow what you're saying.  Either you agree that making
auto_vec suitable as its own element would be useful.  If you do,
it needs to be safely copyable and assignable.

The basic design principle of modern C++ containers is they store
their elements by value and make no further assumptions.  This means
that an int element is treated the same as int* element as a vec<int>
element: they're copied (or moved) by their ctors on insertion,
assigned when being replaced, and destroyed on removal.  Containers
themselves don't, as a rule, manage the resources owned by
the elements (like auto_delete_vec does).  The elements are
responsible for doing that, which is why they need to be safely
copyable and assignable.  vec meets these requirements because
it doesn't manage a resource (it's not a container).  Its memory
needs to be managed some other way.  auto_vec doesn't.  It is
designed to be a container but it's broken.  It won't become one
by deleting its copy ctor and assignment.

> 
>> Having said that, and although I don't mind the cleanup being taken
>> off my plate, I would have expected the courtesy of at least a heads
>> up first.  I do find it disrespectful for someone else involved in
>> the review of my work to at the same time submit a patch of their
>> own that goes in the opposite direction, and for you to unilaterally
>> approve it while the other review hasn't concluded yet.
> 
> Because the changes do not change anything as far as I understand.
> They make more use of auto_vec<> ownership similar to when
> I added the move ctor and adjusted a single loop API.  At the same
> time it completes the move stuff and plugs some holes.

The vast majority of Trevor's changes are improvements and I apprciate
them.  But the change to auto_vec goes against best C++ practices and
in the opposite direction of what I have been arguing for and what
I submitted a patch for in April.  The patch is still under discussion
that both you and Trevor, as well as Jason, have been participating in.
We have not concluded that discussion and it's in bad form to simply
disregard that and proceed in a different direction.  My understanding
from it so far is that

a) you're not opposed to adding the copy ctor:
    https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568827.html
b) Jason advises to prevent implicit by-value conversion from auto_vec
    to vec
    https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571628.html
c) I said I was working on it (and more, some of it likely now
    obviated by Trevor's changes):
    https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html

So would I ask you both to respect that and refrain from approving
and committing this change (i.e., leave auto_vec as is for now)
until I've had time to finish my work.

But checking the latest sources I see Trevor already committed
the change despite this.  That's in very poor form, and quite
disrespectful of both of you.

Martin

> 
> Richard.
> 
>> Martin
>>
>>>
>>> Richard.
>>>
>>>> Martin
>>>>
>>>>>
>>>>> Thanks,
>>>>> Richard
>>>>>
>>>>>> Thanks,
>>>>>> Richard.
>>>>>>
>>>>>>> gcc/ChangeLog:
>>>>>>>
>>>>>>>            * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
>>>>>>>            * dominance.h (get_dominated_by_region): Likewise.
>>>>>>>            * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
>>>>>>>            (gimple_duplicate_sese_tail): Likewise.
>>>>>>>            (move_sese_region_to_fn): Likewise.
>>>>>>> ---
>>>>>>>     gcc/dominance.c |  4 ++--
>>>>>>>     gcc/dominance.h |  2 +-
>>>>>>>     gcc/tree-cfg.c  | 18 +++++++-----------
>>>>>>>     3 files changed, 10 insertions(+), 14 deletions(-)
>>>>>>>
>>>>>>> diff --git a/gcc/dominance.c b/gcc/dominance.c
>>>>>>> index 0e464cb7282..4943102ff1d 100644
>>>>>>> --- a/gcc/dominance.c
>>>>>>> +++ b/gcc/dominance.c
>>>>>>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
>>>>>>>        direction DIR) by some block between N_REGION ones stored in REGION,
>>>>>>>        except for blocks in the REGION itself.  */
>>>>>>>
>>>>>>> -vec<basic_block>
>>>>>>> +auto_vec<basic_block>
>>>>>>>     get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>>>>>>>                             unsigned n_region)
>>>>>>>     {
>>>>>>>       unsigned i;
>>>>>>>       basic_block dom;
>>>>>>> -  vec<basic_block> doms = vNULL;
>>>>>>> +  auto_vec<basic_block> doms;
>>>>>>>
>>>>>>>       for (i = 0; i < n_region; i++)
>>>>>>>         region[i]->flags |= BB_DUPLICATED;
>>>>>>> diff --git a/gcc/dominance.h b/gcc/dominance.h
>>>>>>> index 515a369aacf..c74ad297c6a 100644
>>>>>>> --- a/gcc/dominance.h
>>>>>>> +++ b/gcc/dominance.h
>>>>>>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>>>>>>>     extern void set_immediate_dominator (enum cdi_direction, basic_block,
>>>>>>>                                         basic_block);
>>>>>>>     extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>>>>>>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>>>>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>>>>>                                                             basic_block *,
>>>>>>>                                                             unsigned);
>>>>>>>     extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>> index 6bdd1a561fd..c9403deed19 100644
>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>>>       bool free_region_copy = false, copying_header = false;
>>>>>>>       class loop *loop = entry->dest->loop_father;
>>>>>>>       edge exit_copy;
>>>>>>> -  vec<basic_block> doms = vNULL;
>>>>>>>       edge redirected;
>>>>>>>       profile_count total_count = profile_count::uninitialized ();
>>>>>>>       profile_count entry_count = profile_count::uninitialized ();
>>>>>>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>>>
>>>>>>>       /* Record blocks outside the region that are dominated by something
>>>>>>>          inside.  */
>>>>>>> +  auto_vec<basic_block> doms;
>>>>>>>       if (update_dominance)
>>>>>>>         {
>>>>>>> -      doms.create (0);
>>>>>>>           doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>>>>>         }
>>>>>>>
>>>>>>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>>>           set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
>>>>>>>           doms.safe_push (get_bb_original (entry->dest));
>>>>>>>           iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>>>>>> -      doms.release ();
>>>>>>>         }
>>>>>>>
>>>>>>>       /* Add the other PHI node arguments.  */
>>>>>>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>>>       class loop *loop = exit->dest->loop_father;
>>>>>>>       class loop *orig_loop = entry->dest->loop_father;
>>>>>>>       basic_block switch_bb, entry_bb, nentry_bb;
>>>>>>> -  vec<basic_block> doms;
>>>>>>>       profile_count total_count = profile_count::uninitialized (),
>>>>>>>                    exit_count = profile_count::uninitialized ();
>>>>>>>       edge exits[2], nexits[2], e;
>>>>>>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>>>
>>>>>>>       /* Record blocks outside the region that are dominated by something
>>>>>>>          inside.  */
>>>>>>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>>>>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
>>>>>>> +                                                       n_region);
>>>>>>>
>>>>>>>       total_count = exit->src->count;
>>>>>>>       exit_count = exit->count ();
>>>>>>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>>>       /* Anything that is outside of the region, but was dominated by something
>>>>>>>          inside needs to update dominance info.  */
>>>>>>>       iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>>>>>> -  doms.release ();
>>>>>>>       /* Update the SSA web.  */
>>>>>>>       update_ssa (TODO_update_ssa);
>>>>>>>
>>>>>>> @@ -7567,7 +7564,7 @@ basic_block
>>>>>>>     move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>>>                            basic_block exit_bb, tree orig_block)
>>>>>>>     {
>>>>>>> -  vec<basic_block> bbs, dom_bbs;
>>>>>>> +  vec<basic_block> bbs;
>>>>>>>       basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
>>>>>>>       basic_block after, bb, *entry_pred, *exit_succ, abb;
>>>>>>>       struct function *saved_cfun = cfun;
>>>>>>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>>>
>>>>>>>       /* The blocks that used to be dominated by something in BBS will now be
>>>>>>>          dominated by the new block.  */
>>>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>> -                                    bbs.address (),
>>>>>>> -                                    bbs.length ());
>>>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>> +                                                          bbs.address (),
>>>>>>> +                                                          bbs.length ());
>>>>>>>
>>>>>>>       /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
>>>>>>>          the predecessor edges to ENTRY_BB and the successor edges to
>>>>>>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>>>       set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
>>>>>>>       FOR_EACH_VEC_ELT (dom_bbs, i, abb)
>>>>>>>         set_immediate_dominator (CDI_DOMINATORS, abb, bb);
>>>>>>> -  dom_bbs.release ();
>>>>>>>
>>>>>>>       if (exit_bb)
>>>>>>>         {
>>>>>>> --
>>>>>>> 2.20.1
>>>>>>>
>>>>
>>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-18 16:03               ` Martin Sebor
@ 2021-06-21  7:15                 ` Richard Biener
  2021-06-22 20:01                   ` Martin Sebor
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-21  7:15 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Richard Biener via Gcc-patches, Trevor Saunders, Richard Sandiford

On Fri, Jun 18, 2021 at 6:03 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/18/21 4:38 AM, Richard Biener wrote:
> > On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
> >>
> >> On 6/17/21 12:03 AM, Richard Biener wrote:
> >>> On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
> >>>>
> >>>> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> >>>>> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> >>>>>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >>>>>>>
> >>>>>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
> >>>>>>>
> >>>>>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> >>>>>>>
> >>>>>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
> >>>>>>
> >>>>>> OK.
> >>>>>>
> >>>>>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> >>>>>> excessive indent for
> >>>>>>
> >>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>>>> -                                    bbs.address (),
> >>>>>> -                                    bbs.length ());
> >>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>>>> +                                                          bbs.address (),
> >>>>>> +                                                          bbs.length ());
> >>>>>>
> >>>>>> and just uses
> >>>>>>
> >>>>>>      auto dom_bbs = get_dominated_by_region (...
> >>>>>>
> >>>>>> Not asking you to do this, just a question for the audience.
> >>>>>
> >>>>> Personally I think this would be surprising for something that doesn't
> >>>>> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> >>>>> FWIW, I agree not having copy semantics is probably the most practical
> >>>>> way forward for now.)
> >>>>
> >>>> But you did open the door for me to reiterate my strong disagreement
> >>>> with that.  The best C++ practice going back to the early 1990's is
> >>>> to make types safely copyable and assignable.  It is the default for
> >>>> all types, in both C++ and C, and so natural and expected.
> >>>>
> >>>> Preventing copying is appropriate in special and rare circumstances
> >>>> (e.g, a mutex may not be copyable, or a file or iostream object may
> >>>> not be because they represent a unique physical resource.)
> >>>>
> >>>> In the absence of such special circumstances preventing copying is
> >>>> unexpected, and in the case of an essential building block such as
> >>>> a container, makes the type difficult to use.
> >>>>
> >>>> The only argument for disabling copying that has been given is
> >>>> that it could be surprising(*).  But because all types are copyable
> >>>> by default the "surprise" is usually when one can't be.
> >>>>
> >>>> I think Richi's "surprising" has to do with the fact that it lets
> >>>> one inadvertently copy a large amount of data, thus leading to
> >>>> an inefficiency.  But by analogy, there are infinitely many ways
> >>>> to end up with inefficient code (e.g., deep recursion, or heap
> >>>> allocation in a loop), and they are not a reason to ban the coding
> >>>> constructs that might lead to it.
> >>>>
> >>>> IIUC, Jason's comment about surprising effects was about implicit
> >>>> conversion from auto_vec to vec.  I share that concern, and agree
> >>>> that it should be addressed by preventing the conversion (as Jason
> >>>> suggested).
> >>>
> >>> But fact is that how vec<> and auto_vec<> are used today in GCC
> >>> do not favor that.  In fact your proposed vec<> would be quite radically
> >>> different (and IMHO vec<> and auto_vec<> should be unified then to
> >>> form your proposed new container).  auto_vec<> at the moment simply
> >>> maintains ownership like a smart pointer - which is _also_ not copyable.
> >>
> >> Yes, as we discussed in the review below, vec is not a good model
> >> because (as you note again above) it's constrained by its legacy
> >> uses.  The best I think we can do for it is to make it safer to
> >> use.
> >> https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> >
> > Which is what Trevors patches do by simply disallowing things
> > that do not work at the moment.
> >
> >> (Smart pointers don't rule out copying.  A std::unique_ptr does
> >> and std::shared_ptr doesn't.  But vec and especially auto_vec
> >> are designed to be containers, not "unique pointers" so any
> >> relationship there is purely superficial and a distraction.)
> >>
> >> That auto_vec and vec share a name and an is-a relationship is
> >> incidental, an implementation detail leaked into the API.  A better
> >> name than vector is hard to come up with, but the public inheritance
> >> is a design flaw, a bug waiting to be introduced due to the conversion
> >> and the assumptions the base vec makes about POD-ness and shallow
> >> copying.  Hindsight is always 20/20 but past mistakes should not
> >> dictate the design of a general purpose vector-like container in
> >> GCC.
> >
> > That auto_vec<> "decays" to vec<> was on purpose design.
> >
> > By-value passing of vec<> is also on purpose to avoid an extra
> > pointer indirection on each access.
>
> I think you may have misunderstood what I mean by is-a relationship.
> It's fine to convert an auto_vec to another interface.  The danger
> is in allowing that to happen implicitly because that tends to let
> it happen even when it's not intended.  The usual way to avoid
> that risk is to provide a conversion function, like
> auto_vec::to_vec().  This is also why standard classes like
> std::vector or std::string don't allow such implicit conversions
> and instead provide member functions (see for example Stroustrup:
> The C++ Programming Language).  So a safer auto_vec class would
> not be publicly derived from vec but instead use the has-a design
> (there are also ways to keep the derivation by deriving both from
> from a limited, safe, interface, that each would extend as
> appropriate).
>
> To the point of by passing vec by value while allowing functions
> to modify the argument: C and C++ have by-value semantics.  Every
> C and C++ programmer knows and expect that.  Designing interfaces
> that break this assumption is perverse, a sure recipe for bugs.
> If you're concerned about intuitive semantics and surprises you
> should want to avoid that.
>
> >
> >> I fully support fixing or at least mitigating the problems with
> >> the vec base class (unsafe copying, pass-by-value etc.).  As I
> >> mentioned, I already started working on this cleanup.  I also
> >> have no objection to introducing a non-copyable form of a vector
> >> template (I offered one in my patch), or even to making auto_vec
> >> non-copyable provided a copyable and assignable one is introduced
> >> at the same time, under some other name.
> >
> > Why at the same time?  I'm still not convinced we need another
> > vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
> > but then auto_vec<> doesn't bother to call the DTOR on its elements
> > either (it's actually vec<> again here).  So auto_vec<> is _not_
> > a fancier C++ vec<>, it's still just vec<> but with RAII for the container
> > itself.
>
> I don't follow what you're saying.  Either you agree that making
> auto_vec suitable as its own element would be useful.  If you do,
> it needs to be safely copyable and assignable.
>
> The basic design principle of modern C++ containers is they store
> their elements by value and make no further assumptions.  This means
> that an int element is treated the same as int* element as a vec<int>
> element: they're copied (or moved) by their ctors on insertion,
> assigned when being replaced, and destroyed on removal.  Containers
> themselves don't, as a rule, manage the resources owned by
> the elements (like auto_delete_vec does).  The elements are
> responsible for doing that, which is why they need to be safely
> copyable and assignable.  vec meets these requirements because
> it doesn't manage a resource (it's not a container).  Its memory
> needs to be managed some other way.  auto_vec doesn't.  It is
> designed to be a container but it's broken.  It won't become one
> by deleting its copy ctor and assignment.
>
> >
> >> Having said that, and although I don't mind the cleanup being taken
> >> off my plate, I would have expected the courtesy of at least a heads
> >> up first.  I do find it disrespectful for someone else involved in
> >> the review of my work to at the same time submit a patch of their
> >> own that goes in the opposite direction, and for you to unilaterally
> >> approve it while the other review hasn't concluded yet.
> >
> > Because the changes do not change anything as far as I understand.
> > They make more use of auto_vec<> ownership similar to when
> > I added the move ctor and adjusted a single loop API.  At the same
> > time it completes the move stuff and plugs some holes.
>
> The vast majority of Trevor's changes are improvements and I apprciate
> them.  But the change to auto_vec goes against best C++ practices and
> in the opposite direction of what I have been arguing for and what
> I submitted a patch for in April.  The patch is still under discussion
> that both you and Trevor, as well as Jason, have been participating in.
> We have not concluded that discussion and it's in bad form to simply
> disregard that and proceed in a different direction.  My understanding
> from it so far is that
>
> a) you're not opposed to adding the copy ctor:
>     https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568827.html
> b) Jason advises to prevent implicit by-value conversion from auto_vec
>     to vec
>     https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571628.html
> c) I said I was working on it (and more, some of it likely now
>     obviated by Trevor's changes):
>     https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
>
> So would I ask you both to respect that and refrain from approving
> and committing this change (i.e., leave auto_vec as is for now)
> until I've had time to finish my work.
>
> But checking the latest sources I see Trevor already committed
> the change despite this.  That's in very poor form, and quite
> disrespectful of both of you.

The change was needed to make the useful portions work as far
as I understood Trevor.  There's also nothing that prevents you
from resolving the conflicts and continue with your improvements.

But maybe I'm misunderstanding C++ too much :/

Well, I guess b) from above means auto_vec<> passing to
vec<> taking functions will need changes?

Richard.

> Martin
>
> >
> > Richard.
> >
> >> Martin
> >>
> >>>
> >>> Richard.
> >>>
> >>>> Martin
> >>>>
> >>>>>
> >>>>> Thanks,
> >>>>> Richard
> >>>>>
> >>>>>> Thanks,
> >>>>>> Richard.
> >>>>>>
> >>>>>>> gcc/ChangeLog:
> >>>>>>>
> >>>>>>>            * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
> >>>>>>>            * dominance.h (get_dominated_by_region): Likewise.
> >>>>>>>            * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
> >>>>>>>            (gimple_duplicate_sese_tail): Likewise.
> >>>>>>>            (move_sese_region_to_fn): Likewise.
> >>>>>>> ---
> >>>>>>>     gcc/dominance.c |  4 ++--
> >>>>>>>     gcc/dominance.h |  2 +-
> >>>>>>>     gcc/tree-cfg.c  | 18 +++++++-----------
> >>>>>>>     3 files changed, 10 insertions(+), 14 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/gcc/dominance.c b/gcc/dominance.c
> >>>>>>> index 0e464cb7282..4943102ff1d 100644
> >>>>>>> --- a/gcc/dominance.c
> >>>>>>> +++ b/gcc/dominance.c
> >>>>>>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
> >>>>>>>        direction DIR) by some block between N_REGION ones stored in REGION,
> >>>>>>>        except for blocks in the REGION itself.  */
> >>>>>>>
> >>>>>>> -vec<basic_block>
> >>>>>>> +auto_vec<basic_block>
> >>>>>>>     get_dominated_by_region (enum cdi_direction dir, basic_block *region,
> >>>>>>>                             unsigned n_region)
> >>>>>>>     {
> >>>>>>>       unsigned i;
> >>>>>>>       basic_block dom;
> >>>>>>> -  vec<basic_block> doms = vNULL;
> >>>>>>> +  auto_vec<basic_block> doms;
> >>>>>>>
> >>>>>>>       for (i = 0; i < n_region; i++)
> >>>>>>>         region[i]->flags |= BB_DUPLICATED;
> >>>>>>> diff --git a/gcc/dominance.h b/gcc/dominance.h
> >>>>>>> index 515a369aacf..c74ad297c6a 100644
> >>>>>>> --- a/gcc/dominance.h
> >>>>>>> +++ b/gcc/dominance.h
> >>>>>>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
> >>>>>>>     extern void set_immediate_dominator (enum cdi_direction, basic_block,
> >>>>>>>                                         basic_block);
> >>>>>>>     extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> >>>>>>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
> >>>>>>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
> >>>>>>>                                                             basic_block *,
> >>>>>>>                                                             unsigned);
> >>>>>>>     extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> >>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >>>>>>> index 6bdd1a561fd..c9403deed19 100644
> >>>>>>> --- a/gcc/tree-cfg.c
> >>>>>>> +++ b/gcc/tree-cfg.c
> >>>>>>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>>>>>       bool free_region_copy = false, copying_header = false;
> >>>>>>>       class loop *loop = entry->dest->loop_father;
> >>>>>>>       edge exit_copy;
> >>>>>>> -  vec<basic_block> doms = vNULL;
> >>>>>>>       edge redirected;
> >>>>>>>       profile_count total_count = profile_count::uninitialized ();
> >>>>>>>       profile_count entry_count = profile_count::uninitialized ();
> >>>>>>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>>>>>
> >>>>>>>       /* Record blocks outside the region that are dominated by something
> >>>>>>>          inside.  */
> >>>>>>> +  auto_vec<basic_block> doms;
> >>>>>>>       if (update_dominance)
> >>>>>>>         {
> >>>>>>> -      doms.create (0);
> >>>>>>>           doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> >>>>>>>         }
> >>>>>>>
> >>>>>>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> >>>>>>>           set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
> >>>>>>>           doms.safe_push (get_bb_original (entry->dest));
> >>>>>>>           iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> >>>>>>> -      doms.release ();
> >>>>>>>         }
> >>>>>>>
> >>>>>>>       /* Add the other PHI node arguments.  */
> >>>>>>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>>>>>       class loop *loop = exit->dest->loop_father;
> >>>>>>>       class loop *orig_loop = entry->dest->loop_father;
> >>>>>>>       basic_block switch_bb, entry_bb, nentry_bb;
> >>>>>>> -  vec<basic_block> doms;
> >>>>>>>       profile_count total_count = profile_count::uninitialized (),
> >>>>>>>                    exit_count = profile_count::uninitialized ();
> >>>>>>>       edge exits[2], nexits[2], e;
> >>>>>>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>>>>>
> >>>>>>>       /* Record blocks outside the region that are dominated by something
> >>>>>>>          inside.  */
> >>>>>>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> >>>>>>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
> >>>>>>> +                                                       n_region);
> >>>>>>>
> >>>>>>>       total_count = exit->src->count;
> >>>>>>>       exit_count = exit->count ();
> >>>>>>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> >>>>>>>       /* Anything that is outside of the region, but was dominated by something
> >>>>>>>          inside needs to update dominance info.  */
> >>>>>>>       iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> >>>>>>> -  doms.release ();
> >>>>>>>       /* Update the SSA web.  */
> >>>>>>>       update_ssa (TODO_update_ssa);
> >>>>>>>
> >>>>>>> @@ -7567,7 +7564,7 @@ basic_block
> >>>>>>>     move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>>>>>                            basic_block exit_bb, tree orig_block)
> >>>>>>>     {
> >>>>>>> -  vec<basic_block> bbs, dom_bbs;
> >>>>>>> +  vec<basic_block> bbs;
> >>>>>>>       basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
> >>>>>>>       basic_block after, bb, *entry_pred, *exit_succ, abb;
> >>>>>>>       struct function *saved_cfun = cfun;
> >>>>>>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>>>>>
> >>>>>>>       /* The blocks that used to be dominated by something in BBS will now be
> >>>>>>>          dominated by the new block.  */
> >>>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>>>>> -                                    bbs.address (),
> >>>>>>> -                                    bbs.length ());
> >>>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> >>>>>>> +                                                          bbs.address (),
> >>>>>>> +                                                          bbs.length ());
> >>>>>>>
> >>>>>>>       /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
> >>>>>>>          the predecessor edges to ENTRY_BB and the successor edges to
> >>>>>>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> >>>>>>>       set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
> >>>>>>>       FOR_EACH_VEC_ELT (dom_bbs, i, abb)
> >>>>>>>         set_immediate_dominator (CDI_DOMINATORS, abb, bb);
> >>>>>>> -  dom_bbs.release ();
> >>>>>>>
> >>>>>>>       if (exit_bb)
> >>>>>>>         {
> >>>>>>> --
> >>>>>>> 2.20.1
> >>>>>>>
> >>>>
> >>
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-21  7:15                 ` Richard Biener
@ 2021-06-22 20:01                   ` Martin Sebor
  2021-06-23  5:23                     ` Trevor Saunders
  0 siblings, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-22 20:01 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Biener via Gcc-patches, Trevor Saunders, Richard Sandiford

On 6/21/21 1:15 AM, Richard Biener wrote:
> On Fri, Jun 18, 2021 at 6:03 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 6/18/21 4:38 AM, Richard Biener wrote:
>>> On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 6/17/21 12:03 AM, Richard Biener wrote:
>>>>> On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>
>>>>>> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
>>>>>>> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>>>>>>>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>>>>>>>>
>>>>>>>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>>>>>>>>
>>>>>>>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>>>>>>>>
>>>>>>>> OK.
>>>>>>>>
>>>>>>>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
>>>>>>>> excessive indent for
>>>>>>>>
>>>>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>>> -                                    bbs.address (),
>>>>>>>> -                                    bbs.length ());
>>>>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>>> +                                                          bbs.address (),
>>>>>>>> +                                                          bbs.length ());
>>>>>>>>
>>>>>>>> and just uses
>>>>>>>>
>>>>>>>>       auto dom_bbs = get_dominated_by_region (...
>>>>>>>>
>>>>>>>> Not asking you to do this, just a question for the audience.
>>>>>>>
>>>>>>> Personally I think this would be surprising for something that doesn't
>>>>>>> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
>>>>>>> FWIW, I agree not having copy semantics is probably the most practical
>>>>>>> way forward for now.)
>>>>>>
>>>>>> But you did open the door for me to reiterate my strong disagreement
>>>>>> with that.  The best C++ practice going back to the early 1990's is
>>>>>> to make types safely copyable and assignable.  It is the default for
>>>>>> all types, in both C++ and C, and so natural and expected.
>>>>>>
>>>>>> Preventing copying is appropriate in special and rare circumstances
>>>>>> (e.g, a mutex may not be copyable, or a file or iostream object may
>>>>>> not be because they represent a unique physical resource.)
>>>>>>
>>>>>> In the absence of such special circumstances preventing copying is
>>>>>> unexpected, and in the case of an essential building block such as
>>>>>> a container, makes the type difficult to use.
>>>>>>
>>>>>> The only argument for disabling copying that has been given is
>>>>>> that it could be surprising(*).  But because all types are copyable
>>>>>> by default the "surprise" is usually when one can't be.
>>>>>>
>>>>>> I think Richi's "surprising" has to do with the fact that it lets
>>>>>> one inadvertently copy a large amount of data, thus leading to
>>>>>> an inefficiency.  But by analogy, there are infinitely many ways
>>>>>> to end up with inefficient code (e.g., deep recursion, or heap
>>>>>> allocation in a loop), and they are not a reason to ban the coding
>>>>>> constructs that might lead to it.
>>>>>>
>>>>>> IIUC, Jason's comment about surprising effects was about implicit
>>>>>> conversion from auto_vec to vec.  I share that concern, and agree
>>>>>> that it should be addressed by preventing the conversion (as Jason
>>>>>> suggested).
>>>>>
>>>>> But fact is that how vec<> and auto_vec<> are used today in GCC
>>>>> do not favor that.  In fact your proposed vec<> would be quite radically
>>>>> different (and IMHO vec<> and auto_vec<> should be unified then to
>>>>> form your proposed new container).  auto_vec<> at the moment simply
>>>>> maintains ownership like a smart pointer - which is _also_ not copyable.
>>>>
>>>> Yes, as we discussed in the review below, vec is not a good model
>>>> because (as you note again above) it's constrained by its legacy
>>>> uses.  The best I think we can do for it is to make it safer to
>>>> use.
>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
>>>
>>> Which is what Trevors patches do by simply disallowing things
>>> that do not work at the moment.
>>>
>>>> (Smart pointers don't rule out copying.  A std::unique_ptr does
>>>> and std::shared_ptr doesn't.  But vec and especially auto_vec
>>>> are designed to be containers, not "unique pointers" so any
>>>> relationship there is purely superficial and a distraction.)
>>>>
>>>> That auto_vec and vec share a name and an is-a relationship is
>>>> incidental, an implementation detail leaked into the API.  A better
>>>> name than vector is hard to come up with, but the public inheritance
>>>> is a design flaw, a bug waiting to be introduced due to the conversion
>>>> and the assumptions the base vec makes about POD-ness and shallow
>>>> copying.  Hindsight is always 20/20 but past mistakes should not
>>>> dictate the design of a general purpose vector-like container in
>>>> GCC.
>>>
>>> That auto_vec<> "decays" to vec<> was on purpose design.
>>>
>>> By-value passing of vec<> is also on purpose to avoid an extra
>>> pointer indirection on each access.
>>
>> I think you may have misunderstood what I mean by is-a relationship.
>> It's fine to convert an auto_vec to another interface.  The danger
>> is in allowing that to happen implicitly because that tends to let
>> it happen even when it's not intended.  The usual way to avoid
>> that risk is to provide a conversion function, like
>> auto_vec::to_vec().  This is also why standard classes like
>> std::vector or std::string don't allow such implicit conversions
>> and instead provide member functions (see for example Stroustrup:
>> The C++ Programming Language).  So a safer auto_vec class would
>> not be publicly derived from vec but instead use the has-a design
>> (there are also ways to keep the derivation by deriving both from
>> from a limited, safe, interface, that each would extend as
>> appropriate).
>>
>> To the point of by passing vec by value while allowing functions
>> to modify the argument: C and C++ have by-value semantics.  Every
>> C and C++ programmer knows and expect that.  Designing interfaces
>> that break this assumption is perverse, a sure recipe for bugs.
>> If you're concerned about intuitive semantics and surprises you
>> should want to avoid that.
>>
>>>
>>>> I fully support fixing or at least mitigating the problems with
>>>> the vec base class (unsafe copying, pass-by-value etc.).  As I
>>>> mentioned, I already started working on this cleanup.  I also
>>>> have no objection to introducing a non-copyable form of a vector
>>>> template (I offered one in my patch), or even to making auto_vec
>>>> non-copyable provided a copyable and assignable one is introduced
>>>> at the same time, under some other name.
>>>
>>> Why at the same time?  I'm still not convinced we need another
>>> vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
>>> but then auto_vec<> doesn't bother to call the DTOR on its elements
>>> either (it's actually vec<> again here).  So auto_vec<> is _not_
>>> a fancier C++ vec<>, it's still just vec<> but with RAII for the container
>>> itself.
>>
>> I don't follow what you're saying.  Either you agree that making
>> auto_vec suitable as its own element would be useful.  If you do,
>> it needs to be safely copyable and assignable.
>>
>> The basic design principle of modern C++ containers is they store
>> their elements by value and make no further assumptions.  This means
>> that an int element is treated the same as int* element as a vec<int>
>> element: they're copied (or moved) by their ctors on insertion,
>> assigned when being replaced, and destroyed on removal.  Containers
>> themselves don't, as a rule, manage the resources owned by
>> the elements (like auto_delete_vec does).  The elements are
>> responsible for doing that, which is why they need to be safely
>> copyable and assignable.  vec meets these requirements because
>> it doesn't manage a resource (it's not a container).  Its memory
>> needs to be managed some other way.  auto_vec doesn't.  It is
>> designed to be a container but it's broken.  It won't become one
>> by deleting its copy ctor and assignment.
>>
>>>
>>>> Having said that, and although I don't mind the cleanup being taken
>>>> off my plate, I would have expected the courtesy of at least a heads
>>>> up first.  I do find it disrespectful for someone else involved in
>>>> the review of my work to at the same time submit a patch of their
>>>> own that goes in the opposite direction, and for you to unilaterally
>>>> approve it while the other review hasn't concluded yet.
>>>
>>> Because the changes do not change anything as far as I understand.
>>> They make more use of auto_vec<> ownership similar to when
>>> I added the move ctor and adjusted a single loop API.  At the same
>>> time it completes the move stuff and plugs some holes.
>>
>> The vast majority of Trevor's changes are improvements and I apprciate
>> them.  But the change to auto_vec goes against best C++ practices and
>> in the opposite direction of what I have been arguing for and what
>> I submitted a patch for in April.  The patch is still under discussion
>> that both you and Trevor, as well as Jason, have been participating in.
>> We have not concluded that discussion and it's in bad form to simply
>> disregard that and proceed in a different direction.  My understanding
>> from it so far is that
>>
>> a) you're not opposed to adding the copy ctor:
>>      https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568827.html
>> b) Jason advises to prevent implicit by-value conversion from auto_vec
>>      to vec
>>      https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571628.html
>> c) I said I was working on it (and more, some of it likely now
>>      obviated by Trevor's changes):
>>      https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
>>
>> So would I ask you both to respect that and refrain from approving
>> and committing this change (i.e., leave auto_vec as is for now)
>> until I've had time to finish my work.
>>
>> But checking the latest sources I see Trevor already committed
>> the change despite this.  That's in very poor form, and quite
>> disrespectful of both of you.
> 
> The change was needed to make the useful portions work as far
> as I understood Trevor.  There's also nothing that prevents you
> from resolving the conflicts and continue with your improvements.

The change disables things that were previously possible (but
undefined).  It isn't relied on by anything.  The change is
also incomplete: it disables copying and assignment for
the auto_vec<T, 0> specialization but not for the primary
template.   Neither is safe to copy or assign.

I could still submit a patch to fix that and make all auto_vec
specializations safely copyable but why should I bother?  You
have made it abundantly clear that you don't support it and
several others have taken your position despite all the problems
I have repeatedly pointed out.

> 
> But maybe I'm misunderstanding C++ too much :/
> 
> Well, I guess b) from above means auto_vec<> passing to
> vec<> taking functions will need changes?

Converting an auto_vec object to a vec slices off its data members.
The auto_vec<T, 0> specialization has no data members so that's not
a bug in and of itself, but auto_vec<T, N> does have data members
so that would be a bug.  The risk is not just passing it to
functions by value but also returning it.  That risk was made
worse by the addition of the move ctor.

Even though it's not strictly a bug, passing an auto_vec<T, 0> to
a function that takes a vec could be surprising if the function
modifies the argument.

Martin

PS Looking at the auto_vec change (and the rest of the definition)
more closely, I note a couple of other questionable things.
The move assignment from vec (and the copy you added) is unsafe(*),
and the test for self-assignment in the move assignment operator
is not needed because an object cannot be moved to itself.

[*] E.g., it allows the following which crashes with a double free
error:

vec<int>
foo (vec<int> v)
{
   v.safe_push (2);
   v.safe_push (3);
   v.safe_push (4);
   return v;
}

void bar (auto_vec<int> v) { }

void foobar ()
{
   auto_vec<int> v;
   v.safe_push (1);
   bar (foo (v));
}

My point is not to pick on these other changes per se (I probably
wouldn't have noticed the problems if it wasn't for this discussion)
but to highlight that diverging from best practices tends to have
consequences beyond those we can at fist appreciate, especially if
we're not perfectly comfortable with the rules we're playing with.

> 
> Richard.
> 
>> Martin
>>
>>>
>>> Richard.
>>>
>>>> Martin
>>>>
>>>>>
>>>>> Richard.
>>>>>
>>>>>> Martin
>>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Richard
>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Richard.
>>>>>>>>
>>>>>>>>> gcc/ChangeLog:
>>>>>>>>>
>>>>>>>>>             * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
>>>>>>>>>             * dominance.h (get_dominated_by_region): Likewise.
>>>>>>>>>             * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
>>>>>>>>>             (gimple_duplicate_sese_tail): Likewise.
>>>>>>>>>             (move_sese_region_to_fn): Likewise.
>>>>>>>>> ---
>>>>>>>>>      gcc/dominance.c |  4 ++--
>>>>>>>>>      gcc/dominance.h |  2 +-
>>>>>>>>>      gcc/tree-cfg.c  | 18 +++++++-----------
>>>>>>>>>      3 files changed, 10 insertions(+), 14 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/gcc/dominance.c b/gcc/dominance.c
>>>>>>>>> index 0e464cb7282..4943102ff1d 100644
>>>>>>>>> --- a/gcc/dominance.c
>>>>>>>>> +++ b/gcc/dominance.c
>>>>>>>>> @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
>>>>>>>>>         direction DIR) by some block between N_REGION ones stored in REGION,
>>>>>>>>>         except for blocks in the REGION itself.  */
>>>>>>>>>
>>>>>>>>> -vec<basic_block>
>>>>>>>>> +auto_vec<basic_block>
>>>>>>>>>      get_dominated_by_region (enum cdi_direction dir, basic_block *region,
>>>>>>>>>                              unsigned n_region)
>>>>>>>>>      {
>>>>>>>>>        unsigned i;
>>>>>>>>>        basic_block dom;
>>>>>>>>> -  vec<basic_block> doms = vNULL;
>>>>>>>>> +  auto_vec<basic_block> doms;
>>>>>>>>>
>>>>>>>>>        for (i = 0; i < n_region; i++)
>>>>>>>>>          region[i]->flags |= BB_DUPLICATED;
>>>>>>>>> diff --git a/gcc/dominance.h b/gcc/dominance.h
>>>>>>>>> index 515a369aacf..c74ad297c6a 100644
>>>>>>>>> --- a/gcc/dominance.h
>>>>>>>>> +++ b/gcc/dominance.h
>>>>>>>>> @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
>>>>>>>>>      extern void set_immediate_dominator (enum cdi_direction, basic_block,
>>>>>>>>>                                          basic_block);
>>>>>>>>>      extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
>>>>>>>>> -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>>>>>>> +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
>>>>>>>>>                                                              basic_block *,
>>>>>>>>>                                                              unsigned);
>>>>>>>>>      extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>> index 6bdd1a561fd..c9403deed19 100644
>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>> @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>>>>>        bool free_region_copy = false, copying_header = false;
>>>>>>>>>        class loop *loop = entry->dest->loop_father;
>>>>>>>>>        edge exit_copy;
>>>>>>>>> -  vec<basic_block> doms = vNULL;
>>>>>>>>>        edge redirected;
>>>>>>>>>        profile_count total_count = profile_count::uninitialized ();
>>>>>>>>>        profile_count entry_count = profile_count::uninitialized ();
>>>>>>>>> @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>>>>>
>>>>>>>>>        /* Record blocks outside the region that are dominated by something
>>>>>>>>>           inside.  */
>>>>>>>>> +  auto_vec<basic_block> doms;
>>>>>>>>>        if (update_dominance)
>>>>>>>>>          {
>>>>>>>>> -      doms.create (0);
>>>>>>>>>            doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>>>>>>>          }
>>>>>>>>>
>>>>>>>>> @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
>>>>>>>>>            set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
>>>>>>>>>            doms.safe_push (get_bb_original (entry->dest));
>>>>>>>>>            iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>>>>>>>> -      doms.release ();
>>>>>>>>>          }
>>>>>>>>>
>>>>>>>>>        /* Add the other PHI node arguments.  */
>>>>>>>>> @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>>>>>        class loop *loop = exit->dest->loop_father;
>>>>>>>>>        class loop *orig_loop = entry->dest->loop_father;
>>>>>>>>>        basic_block switch_bb, entry_bb, nentry_bb;
>>>>>>>>> -  vec<basic_block> doms;
>>>>>>>>>        profile_count total_count = profile_count::uninitialized (),
>>>>>>>>>                     exit_count = profile_count::uninitialized ();
>>>>>>>>>        edge exits[2], nexits[2], e;
>>>>>>>>> @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>>>>>
>>>>>>>>>        /* Record blocks outside the region that are dominated by something
>>>>>>>>>           inside.  */
>>>>>>>>> -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
>>>>>>>>> +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
>>>>>>>>> +                                                       n_region);
>>>>>>>>>
>>>>>>>>>        total_count = exit->src->count;
>>>>>>>>>        exit_count = exit->count ();
>>>>>>>>> @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
>>>>>>>>>        /* Anything that is outside of the region, but was dominated by something
>>>>>>>>>           inside needs to update dominance info.  */
>>>>>>>>>        iterate_fix_dominators (CDI_DOMINATORS, doms, false);
>>>>>>>>> -  doms.release ();
>>>>>>>>>        /* Update the SSA web.  */
>>>>>>>>>        update_ssa (TODO_update_ssa);
>>>>>>>>>
>>>>>>>>> @@ -7567,7 +7564,7 @@ basic_block
>>>>>>>>>      move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>>>>>                             basic_block exit_bb, tree orig_block)
>>>>>>>>>      {
>>>>>>>>> -  vec<basic_block> bbs, dom_bbs;
>>>>>>>>> +  vec<basic_block> bbs;
>>>>>>>>>        basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
>>>>>>>>>        basic_block after, bb, *entry_pred, *exit_succ, abb;
>>>>>>>>>        struct function *saved_cfun = cfun;
>>>>>>>>> @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>>>>>
>>>>>>>>>        /* The blocks that used to be dominated by something in BBS will now be
>>>>>>>>>           dominated by the new block.  */
>>>>>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>>>> -                                    bbs.address (),
>>>>>>>>> -                                    bbs.length ());
>>>>>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>>>> +                                                          bbs.address (),
>>>>>>>>> +                                                          bbs.length ());
>>>>>>>>>
>>>>>>>>>        /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
>>>>>>>>>           the predecessor edges to ENTRY_BB and the successor edges to
>>>>>>>>> @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
>>>>>>>>>        set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
>>>>>>>>>        FOR_EACH_VEC_ELT (dom_bbs, i, abb)
>>>>>>>>>          set_immediate_dominator (CDI_DOMINATORS, abb, bb);
>>>>>>>>> -  dom_bbs.release ();
>>>>>>>>>
>>>>>>>>>        if (exit_bb)
>>>>>>>>>          {
>>>>>>>>> --
>>>>>>>>> 2.20.1
>>>>>>>>>
>>>>>>
>>>>
>>


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-22 20:01                   ` Martin Sebor
@ 2021-06-23  5:23                     ` Trevor Saunders
  2021-06-23  7:43                       ` Richard Biener
  2021-06-23 23:43                       ` Martin Sebor
  0 siblings, 2 replies; 51+ messages in thread
From: Trevor Saunders @ 2021-06-23  5:23 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Richard Biener, Richard Biener via Gcc-patches, Richard Sandiford

On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
> On 6/21/21 1:15 AM, Richard Biener wrote:
> > On Fri, Jun 18, 2021 at 6:03 PM Martin Sebor <msebor@gmail.com> wrote:
> > > 
> > > On 6/18/21 4:38 AM, Richard Biener wrote:
> > > > On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > 
> > > > > On 6/17/21 12:03 AM, Richard Biener wrote:
> > > > > > On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > 
> > > > > > > On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> > > > > > > > Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> > > > > > > > > On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > > > > > > > > > 
> > > > > > > > > > This makes it clear the caller owns the vector, and ensures it is cleaned up.
> > > > > > > > > > 
> > > > > > > > > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > > > > > > > > > 
> > > > > > > > > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > > > > > > > > 
> > > > > > > > > OK.
> > > > > > > > > 
> > > > > > > > > Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> > > > > > > > > excessive indent for
> > > > > > > > > 
> > > > > > > > > -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > > > > > > > > -                                    bbs.address (),
> > > > > > > > > -                                    bbs.length ());
> > > > > > > > > +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > > > > > > > > +                                                          bbs.address (),
> > > > > > > > > +                                                          bbs.length ());
> > > > > > > > > 
> > > > > > > > > and just uses
> > > > > > > > > 
> > > > > > > > >       auto dom_bbs = get_dominated_by_region (...
> > > > > > > > > 
> > > > > > > > > Not asking you to do this, just a question for the audience.
> > > > > > > > 
> > > > > > > > Personally I think this would be surprising for something that doesn't
> > > > > > > > have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> > > > > > > > FWIW, I agree not having copy semantics is probably the most practical
> > > > > > > > way forward for now.)
> > > > > > > 
> > > > > > > But you did open the door for me to reiterate my strong disagreement
> > > > > > > with that.  The best C++ practice going back to the early 1990's is
> > > > > > > to make types safely copyable and assignable.  It is the default for
> > > > > > > all types, in both C++ and C, and so natural and expected.
> > > > > > > 
> > > > > > > Preventing copying is appropriate in special and rare circumstances
> > > > > > > (e.g, a mutex may not be copyable, or a file or iostream object may
> > > > > > > not be because they represent a unique physical resource.)
> > > > > > > 
> > > > > > > In the absence of such special circumstances preventing copying is
> > > > > > > unexpected, and in the case of an essential building block such as
> > > > > > > a container, makes the type difficult to use.
> > > > > > > 
> > > > > > > The only argument for disabling copying that has been given is
> > > > > > > that it could be surprising(*).  But because all types are copyable
> > > > > > > by default the "surprise" is usually when one can't be.
> > > > > > > 
> > > > > > > I think Richi's "surprising" has to do with the fact that it lets
> > > > > > > one inadvertently copy a large amount of data, thus leading to
> > > > > > > an inefficiency.  But by analogy, there are infinitely many ways
> > > > > > > to end up with inefficient code (e.g., deep recursion, or heap
> > > > > > > allocation in a loop), and they are not a reason to ban the coding
> > > > > > > constructs that might lead to it.
> > > > > > > 
> > > > > > > IIUC, Jason's comment about surprising effects was about implicit
> > > > > > > conversion from auto_vec to vec.  I share that concern, and agree
> > > > > > > that it should be addressed by preventing the conversion (as Jason
> > > > > > > suggested).
> > > > > > 
> > > > > > But fact is that how vec<> and auto_vec<> are used today in GCC
> > > > > > do not favor that.  In fact your proposed vec<> would be quite radically
> > > > > > different (and IMHO vec<> and auto_vec<> should be unified then to
> > > > > > form your proposed new container).  auto_vec<> at the moment simply
> > > > > > maintains ownership like a smart pointer - which is _also_ not copyable.
> > > > > 
> > > > > Yes, as we discussed in the review below, vec is not a good model
> > > > > because (as you note again above) it's constrained by its legacy
> > > > > uses.  The best I think we can do for it is to make it safer to
> > > > > use.
> > > > > https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> > > > 
> > > > Which is what Trevors patches do by simply disallowing things
> > > > that do not work at the moment.
> > > > 
> > > > > (Smart pointers don't rule out copying.  A std::unique_ptr does
> > > > > and std::shared_ptr doesn't.  But vec and especially auto_vec
> > > > > are designed to be containers, not "unique pointers" so any
> > > > > relationship there is purely superficial and a distraction.)
> > > > > 
> > > > > That auto_vec and vec share a name and an is-a relationship is
> > > > > incidental, an implementation detail leaked into the API.  A better
> > > > > name than vector is hard to come up with, but the public inheritance
> > > > > is a design flaw, a bug waiting to be introduced due to the conversion
> > > > > and the assumptions the base vec makes about POD-ness and shallow
> > > > > copying.  Hindsight is always 20/20 but past mistakes should not
> > > > > dictate the design of a general purpose vector-like container in
> > > > > GCC.
> > > > 
> > > > That auto_vec<> "decays" to vec<> was on purpose design.
> > > > 
> > > > By-value passing of vec<> is also on purpose to avoid an extra
> > > > pointer indirection on each access.
> > > 
> > > I think you may have misunderstood what I mean by is-a relationship.
> > > It's fine to convert an auto_vec to another interface.  The danger
> > > is in allowing that to happen implicitly because that tends to let
> > > it happen even when it's not intended.  The usual way to avoid
> > > that risk is to provide a conversion function, like
> > > auto_vec::to_vec().  This is also why standard classes like
> > > std::vector or std::string don't allow such implicit conversions
> > > and instead provide member functions (see for example Stroustrup:
> > > The C++ Programming Language).  So a safer auto_vec class would
> > > not be publicly derived from vec but instead use the has-a design
> > > (there are also ways to keep the derivation by deriving both from
> > > from a limited, safe, interface, that each would extend as
> > > appropriate).
> > > 
> > > To the point of by passing vec by value while allowing functions
> > > to modify the argument: C and C++ have by-value semantics.  Every
> > > C and C++ programmer knows and expect that.  Designing interfaces
> > > that break this assumption is perverse, a sure recipe for bugs.
> > > If you're concerned about intuitive semantics and surprises you
> > > should want to avoid that.
> > > 
> > > > 
> > > > > I fully support fixing or at least mitigating the problems with
> > > > > the vec base class (unsafe copying, pass-by-value etc.).  As I
> > > > > mentioned, I already started working on this cleanup.  I also
> > > > > have no objection to introducing a non-copyable form of a vector
> > > > > template (I offered one in my patch), or even to making auto_vec
> > > > > non-copyable provided a copyable and assignable one is introduced
> > > > > at the same time, under some other name.
> > > > 
> > > > Why at the same time?  I'm still not convinced we need another
> > > > vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
> > > > but then auto_vec<> doesn't bother to call the DTOR on its elements
> > > > either (it's actually vec<> again here).  So auto_vec<> is _not_
> > > > a fancier C++ vec<>, it's still just vec<> but with RAII for the container
> > > > itself.
> > > 
> > > I don't follow what you're saying.  Either you agree that making
> > > auto_vec suitable as its own element would be useful.  If you do,
> > > it needs to be safely copyable and assignable.
> > > 
> > > The basic design principle of modern C++ containers is they store
> > > their elements by value and make no further assumptions.  This means
> > > that an int element is treated the same as int* element as a vec<int>
> > > element: they're copied (or moved) by their ctors on insertion,
> > > assigned when being replaced, and destroyed on removal.  Containers
> > > themselves don't, as a rule, manage the resources owned by
> > > the elements (like auto_delete_vec does).  The elements are
> > > responsible for doing that, which is why they need to be safely
> > > copyable and assignable.  vec meets these requirements because
> > > it doesn't manage a resource (it's not a container).  Its memory
> > > needs to be managed some other way.  auto_vec doesn't.  It is
> > > designed to be a container but it's broken.  It won't become one
> > > by deleting its copy ctor and assignment.
> > > 
> > > > 
> > > > > Having said that, and although I don't mind the cleanup being taken
> > > > > off my plate, I would have expected the courtesy of at least a heads
> > > > > up first.  I do find it disrespectful for someone else involved in
> > > > > the review of my work to at the same time submit a patch of their
> > > > > own that goes in the opposite direction, and for you to unilaterally
> > > > > approve it while the other review hasn't concluded yet.
> > > > 
> > > > Because the changes do not change anything as far as I understand.
> > > > They make more use of auto_vec<> ownership similar to when
> > > > I added the move ctor and adjusted a single loop API.  At the same
> > > > time it completes the move stuff and plugs some holes.
> > > 
> > > The vast majority of Trevor's changes are improvements and I apprciate
> > > them.  But the change to auto_vec goes against best C++ practices and
> > > in the opposite direction of what I have been arguing for and what
> > > I submitted a patch for in April.  The patch is still under discussion
> > > that both you and Trevor, as well as Jason, have been participating in.
> > > We have not concluded that discussion and it's in bad form to simply
> > > disregard that and proceed in a different direction.  My understanding
> > > from it so far is that
> > > 
> > > a) you're not opposed to adding the copy ctor:
> > >      https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568827.html
> > > b) Jason advises to prevent implicit by-value conversion from auto_vec
> > >      to vec
> > >      https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571628.html
> > > c) I said I was working on it (and more, some of it likely now
> > >      obviated by Trevor's changes):
> > >      https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> > > 
> > > So would I ask you both to respect that and refrain from approving
> > > and committing this change (i.e., leave auto_vec as is for now)
> > > until I've had time to finish my work.
> > > 
> > > But checking the latest sources I see Trevor already committed
> > > the change despite this.  That's in very poor form, and quite
> > > disrespectful of both of you.
> > 
> > The change was needed to make the useful portions work as far
> > as I understood Trevor.  There's also nothing that prevents you
> > from resolving the conflicts and continue with your improvements.
> 
> The change disables things that were previously possible (but
> undefined).  It isn't relied on by anything.  The change is
> also incomplete: it disables copying and assignment for
> the auto_vec<T, 0> specialization but not for the primary
> template.   Neither is safe to copy or assign.

I suppose its technically true that it disables things that were
possible, but for those things to work you'd have to jump through some
hoops to prevent it causing a double free, so in practice I don't think
you can really say it disables something, it just makes explicit what
was already the case.  Since the move constructors would have prevented
the compiler from providing a default definition of the copy
constructor, there deletion is essentially just documentation.  Later
patches in the series did depend on the move constructors to work
properly.  I would agree that the template with inline storage could use
with adjustment in this area, but I think its fine to handle it
separately per Richi's request, and further I suspect its much less
useful and likely to cause trouble, the main use case would be for
function location things, and returning such an object  or passing it by
value seems odd (not to say it is good the way it is, but that its of
less practical importance).

> I could still submit a patch to fix that and make all auto_vec
> specializations safely copyable but why should I bother?  You
> have made it abundantly clear that you don't support it and
> several others have taken your position despite all the problems
> I have repeatedly pointed out.

Well, personally if you wanted to define something like
template<typename T> T gcc::copy (const T &) = delete;  WIth
specializations for things that could be coppied including anything
that's POD, I think that might be reasonable, and much clearer than "="
that calls malloc, if your issue is that .copy () on vec isn't the same
as for other objects.  Personally I think its mostly YAGNI and there's
few enough places coppying things for it to be a real problem, but at
the same time I think there's no particular need .copy () is a member,
just that its use is more obvious to the author and reader than
"=".

> > 
> > But maybe I'm misunderstanding C++ too much :/
> > 
> > Well, I guess b) from above means auto_vec<> passing to
> > vec<> taking functions will need changes?
> 
> Converting an auto_vec object to a vec slices off its data members.
> The auto_vec<T, 0> specialization has no data members so that's not
> a bug in and of itself, but auto_vec<T, N> does have data members
> so that would be a bug.  The risk is not just passing it to
> functions by value but also returning it.  That risk was made
> worse by the addition of the move ctor.

I would agree that the conversion from auto_vec<> to vec<> is
questionable, and should get some work at some point, perhaps just
passingauto_vec references is good enough, or perhaps there is value in
some const_vec view to avoid having to rely on optimizations, I'm not
sure without looking more at the usage.  However I think that's a
separate issue and we can't and shouldn't fix everything at once.  As
for slicing auto_vec<T, N> I think that mostly "works" given the same
conditions as for auto_vec<T, 0> because the base that gets coppied is a
pointer to a valid embedded vec the same as in the source object.  So as
long as the source outlives the copy, and the operations on either
object do not trigger a resize you get away with it, as much as it is
playing with fire.  Returning a auto_vec<T, N> sounds like a bug to
begin with, even if it worked correctly, but that aside, you can't
convert from auto_vec<T, N> to auto_vec<T, M> for n != M, so if the
function returns auto_vec<T> you can implicitly convert to vec<T> in the
caller, but you can't slice away part of the source object.  Making more
things return auto_vec<T> certainly increases the number of places
conversions to vec<T> can take place and cause trouble, but you can't
fix everything at once, and its a preexisting issue, which would be the
same if the copy members were defined.

> Even though it's not strictly a bug, passing an auto_vec<T, 0> to
> a function that takes a vec could be surprising if the function
> modifies the argument.
> 
> Martin
> 
> PS Looking at the auto_vec change (and the rest of the definition)
> more closely, I note a couple of other questionable things.
> The move assignment from vec (and the copy you added) is unsafe(*),
> and the test for self-assignment in the move assignment operator
> is not needed because an object cannot be moved to itself.

Yes, I certainly misremembered the rules on self moves, though I'm not
quite sure if its worth removing the check, I imagine in most cases
optimization figures out they don't alias, and ending up with the
original vector might be more useful, but its certainly not necessary,
and self moves are kind of silly.

> [*] E.g., it allows the following which crashes with a double free
> error:
> 
> vec<int>
> foo (vec<int> v)
> {
>   v.safe_push (2);
>   v.safe_push (3);
>   v.safe_push (4);
>   return v;
> }
> 
> void bar (auto_vec<int> v) { }
> 
> void foobar ()
> {
>   auto_vec<int> v;
>   v.safe_push (1);
>   bar (foo (v));
> }

It looks to me like this is effects of implicit conversion to vec<T>,
and then the auto_vec(vec&&) constructor that was already there.  I can
see the value of that constructor perhaps (I haven't checked, but
perhaps after my patch it could be removed), but it does allow you to
shoot yourself in the foot too.

> My point is not to pick on these other changes per se (I probably
> wouldn't have noticed the problems if it wasn't for this discussion)
> but to highlight that diverging from best practices tends to have
> consequences beyond those we can at fist appreciate, especially if
> we're not perfectly comfortable with the rules we're playing with.

Personally what I take away from this is more that since of necessity
vec<T> is so loose about what it allows you can do some suprising things
with it, and that suggests being as strict as you can with what you
allow, and in particular outside of GC things only refering to auto_vec
so you don't have chances for strange conversions.

Thanks

Trev

> 
> > 
> > Richard.
> > 
> > > Martin
> > > 
> > > > 
> > > > Richard.
> > > > 
> > > > > Martin
> > > > > 
> > > > > > 
> > > > > > Richard.
> > > > > > 
> > > > > > > Martin
> > > > > > > 
> > > > > > > > 
> > > > > > > > Thanks,
> > > > > > > > Richard
> > > > > > > > 
> > > > > > > > > Thanks,
> > > > > > > > > Richard.
> > > > > > > > > 
> > > > > > > > > > gcc/ChangeLog:
> > > > > > > > > > 
> > > > > > > > > >             * dominance.c (get_dominated_by_region): Return auto_vec<basic_block>.
> > > > > > > > > >             * dominance.h (get_dominated_by_region): Likewise.
> > > > > > > > > >             * tree-cfg.c (gimple_duplicate_sese_region): Adjust.
> > > > > > > > > >             (gimple_duplicate_sese_tail): Likewise.
> > > > > > > > > >             (move_sese_region_to_fn): Likewise.
> > > > > > > > > > ---
> > > > > > > > > >      gcc/dominance.c |  4 ++--
> > > > > > > > > >      gcc/dominance.h |  2 +-
> > > > > > > > > >      gcc/tree-cfg.c  | 18 +++++++-----------
> > > > > > > > > >      3 files changed, 10 insertions(+), 14 deletions(-)
> > > > > > > > > > 
> > > > > > > > > > diff --git a/gcc/dominance.c b/gcc/dominance.c
> > > > > > > > > > index 0e464cb7282..4943102ff1d 100644
> > > > > > > > > > --- a/gcc/dominance.c
> > > > > > > > > > +++ b/gcc/dominance.c
> > > > > > > > > > @@ -906,13 +906,13 @@ get_dominated_by (enum cdi_direction dir, basic_block bb)
> > > > > > > > > >         direction DIR) by some block between N_REGION ones stored in REGION,
> > > > > > > > > >         except for blocks in the REGION itself.  */
> > > > > > > > > > 
> > > > > > > > > > -vec<basic_block>
> > > > > > > > > > +auto_vec<basic_block>
> > > > > > > > > >      get_dominated_by_region (enum cdi_direction dir, basic_block *region,
> > > > > > > > > >                              unsigned n_region)
> > > > > > > > > >      {
> > > > > > > > > >        unsigned i;
> > > > > > > > > >        basic_block dom;
> > > > > > > > > > -  vec<basic_block> doms = vNULL;
> > > > > > > > > > +  auto_vec<basic_block> doms;
> > > > > > > > > > 
> > > > > > > > > >        for (i = 0; i < n_region; i++)
> > > > > > > > > >          region[i]->flags |= BB_DUPLICATED;
> > > > > > > > > > diff --git a/gcc/dominance.h b/gcc/dominance.h
> > > > > > > > > > index 515a369aacf..c74ad297c6a 100644
> > > > > > > > > > --- a/gcc/dominance.h
> > > > > > > > > > +++ b/gcc/dominance.h
> > > > > > > > > > @@ -47,7 +47,7 @@ extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
> > > > > > > > > >      extern void set_immediate_dominator (enum cdi_direction, basic_block,
> > > > > > > > > >                                          basic_block);
> > > > > > > > > >      extern auto_vec<basic_block> get_dominated_by (enum cdi_direction, basic_block);
> > > > > > > > > > -extern vec<basic_block> get_dominated_by_region (enum cdi_direction,
> > > > > > > > > > +extern auto_vec<basic_block> get_dominated_by_region (enum cdi_direction,
> > > > > > > > > >                                                              basic_block *,
> > > > > > > > > >                                                              unsigned);
> > > > > > > > > >      extern vec<basic_block> get_dominated_to_depth (enum cdi_direction,
> > > > > > > > > > diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> > > > > > > > > > index 6bdd1a561fd..c9403deed19 100644
> > > > > > > > > > --- a/gcc/tree-cfg.c
> > > > > > > > > > +++ b/gcc/tree-cfg.c
> > > > > > > > > > @@ -6495,7 +6495,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> > > > > > > > > >        bool free_region_copy = false, copying_header = false;
> > > > > > > > > >        class loop *loop = entry->dest->loop_father;
> > > > > > > > > >        edge exit_copy;
> > > > > > > > > > -  vec<basic_block> doms = vNULL;
> > > > > > > > > >        edge redirected;
> > > > > > > > > >        profile_count total_count = profile_count::uninitialized ();
> > > > > > > > > >        profile_count entry_count = profile_count::uninitialized ();
> > > > > > > > > > @@ -6549,9 +6548,9 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> > > > > > > > > > 
> > > > > > > > > >        /* Record blocks outside the region that are dominated by something
> > > > > > > > > >           inside.  */
> > > > > > > > > > +  auto_vec<basic_block> doms;
> > > > > > > > > >        if (update_dominance)
> > > > > > > > > >          {
> > > > > > > > > > -      doms.create (0);
> > > > > > > > > >            doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> > > > > > > > > >          }
> > > > > > > > > > 
> > > > > > > > > > @@ -6596,7 +6595,6 @@ gimple_duplicate_sese_region (edge entry, edge exit,
> > > > > > > > > >            set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
> > > > > > > > > >            doms.safe_push (get_bb_original (entry->dest));
> > > > > > > > > >            iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> > > > > > > > > > -      doms.release ();
> > > > > > > > > >          }
> > > > > > > > > > 
> > > > > > > > > >        /* Add the other PHI node arguments.  */
> > > > > > > > > > @@ -6662,7 +6660,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> > > > > > > > > >        class loop *loop = exit->dest->loop_father;
> > > > > > > > > >        class loop *orig_loop = entry->dest->loop_father;
> > > > > > > > > >        basic_block switch_bb, entry_bb, nentry_bb;
> > > > > > > > > > -  vec<basic_block> doms;
> > > > > > > > > >        profile_count total_count = profile_count::uninitialized (),
> > > > > > > > > >                     exit_count = profile_count::uninitialized ();
> > > > > > > > > >        edge exits[2], nexits[2], e;
> > > > > > > > > > @@ -6705,7 +6702,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> > > > > > > > > > 
> > > > > > > > > >        /* Record blocks outside the region that are dominated by something
> > > > > > > > > >           inside.  */
> > > > > > > > > > -  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
> > > > > > > > > > +  auto_vec<basic_block> doms = get_dominated_by_region (CDI_DOMINATORS, region,
> > > > > > > > > > +                                                       n_region);
> > > > > > > > > > 
> > > > > > > > > >        total_count = exit->src->count;
> > > > > > > > > >        exit_count = exit->count ();
> > > > > > > > > > @@ -6785,7 +6783,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
> > > > > > > > > >        /* Anything that is outside of the region, but was dominated by something
> > > > > > > > > >           inside needs to update dominance info.  */
> > > > > > > > > >        iterate_fix_dominators (CDI_DOMINATORS, doms, false);
> > > > > > > > > > -  doms.release ();
> > > > > > > > > >        /* Update the SSA web.  */
> > > > > > > > > >        update_ssa (TODO_update_ssa);
> > > > > > > > > > 
> > > > > > > > > > @@ -7567,7 +7564,7 @@ basic_block
> > > > > > > > > >      move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> > > > > > > > > >                             basic_block exit_bb, tree orig_block)
> > > > > > > > > >      {
> > > > > > > > > > -  vec<basic_block> bbs, dom_bbs;
> > > > > > > > > > +  vec<basic_block> bbs;
> > > > > > > > > >        basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
> > > > > > > > > >        basic_block after, bb, *entry_pred, *exit_succ, abb;
> > > > > > > > > >        struct function *saved_cfun = cfun;
> > > > > > > > > > @@ -7599,9 +7596,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> > > > > > > > > > 
> > > > > > > > > >        /* The blocks that used to be dominated by something in BBS will now be
> > > > > > > > > >           dominated by the new block.  */
> > > > > > > > > > -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > > > > > > > > > -                                    bbs.address (),
> > > > > > > > > > -                                    bbs.length ());
> > > > > > > > > > +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > > > > > > > > > +                                                          bbs.address (),
> > > > > > > > > > +                                                          bbs.length ());
> > > > > > > > > > 
> > > > > > > > > >        /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
> > > > > > > > > >           the predecessor edges to ENTRY_BB and the successor edges to
> > > > > > > > > > @@ -7937,7 +7934,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
> > > > > > > > > >        set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
> > > > > > > > > >        FOR_EACH_VEC_ELT (dom_bbs, i, abb)
> > > > > > > > > >          set_immediate_dominator (CDI_DOMINATORS, abb, bb);
> > > > > > > > > > -  dom_bbs.release ();
> > > > > > > > > > 
> > > > > > > > > >        if (exit_bb)
> > > > > > > > > >          {
> > > > > > > > > > --
> > > > > > > > > > 2.20.1
> > > > > > > > > > 
> > > > > > > 
> > > > > 
> > > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23  5:23                     ` Trevor Saunders
@ 2021-06-23  7:43                       ` Richard Biener
  2021-06-23 10:22                         ` Richard Sandiford
  2021-06-23 22:56                         ` Martin Sebor
  2021-06-23 23:43                       ` Martin Sebor
  1 sibling, 2 replies; 51+ messages in thread
From: Richard Biener @ 2021-06-23  7:43 UTC (permalink / raw)
  To: Trevor Saunders
  Cc: Martin Sebor, Richard Biener via Gcc-patches, Richard Sandiford

On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
> > On 6/21/21 1:15 AM, Richard Biener wrote:
[...]
> > >
> > > But maybe I'm misunderstanding C++ too much :/
> > >
> > > Well, I guess b) from above means auto_vec<> passing to
> > > vec<> taking functions will need changes?
> >
> > Converting an auto_vec object to a vec slices off its data members.
> > The auto_vec<T, 0> specialization has no data members so that's not
> > a bug in and of itself, but auto_vec<T, N> does have data members
> > so that would be a bug.  The risk is not just passing it to
> > functions by value but also returning it.  That risk was made
> > worse by the addition of the move ctor.
>
> I would agree that the conversion from auto_vec<> to vec<> is
> questionable, and should get some work at some point, perhaps just
> passingauto_vec references is good enough, or perhaps there is value in
> some const_vec view to avoid having to rely on optimizations, I'm not
> sure without looking more at the usage.

We do need to be able to provide APIs that work with both auto_vec<>
and vec<>, I agree that those currently taking a vec<> by value are
fragile (and we've had bugs there before), but I'm not ready to say
that changing them all to [const] vec<>& is OK.  The alternative
would be passing a const_vec<> by value, passing that along to
const vec<>& APIs should be valid then (I can see quite some API
boundary cleanups being necessary here ...).

But with all this I don't know how to adjust auto_vec<> to no
longer "decay" to vec<> but still being able to pass it to vec<>&
and being able to call vec<> member functions w/o jumping through
hoops.  Any hints on that?  private inheritance achieves the first
but also hides all the API ...

> However I think that's a
> separate issue and we can't and shouldn't fix everything at once.  As
> for slicing auto_vec<T, N> I think that mostly "works" given the same
> conditions as for auto_vec<T, 0> because the base that gets coppied is a
> pointer to a valid embedded vec the same as in the source object.  So as
> long as the source outlives the copy, and the operations on either
> object do not trigger a resize you get away with it, as much as it is
> playing with fire.  Returning a auto_vec<T, N> sounds like a bug to
> begin with, even if it worked correctly, but that aside, you can't
> convert from auto_vec<T, N> to auto_vec<T, M> for n != M, so if the
> function returns auto_vec<T> you can implicitly convert to vec<T> in the
> caller, but you can't slice away part of the source object.  Making more
> things return auto_vec<T> certainly increases the number of places
> conversions to vec<T> can take place and cause trouble, but you can't
> fix everything at once, and its a preexisting issue, which would be the
> same if the copy members were defined.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23  7:43                       ` Richard Biener
@ 2021-06-23 10:22                         ` Richard Sandiford
  2021-06-24  9:20                           ` Richard Biener
  2021-06-23 22:56                         ` Martin Sebor
  1 sibling, 1 reply; 51+ messages in thread
From: Richard Sandiford @ 2021-06-23 10:22 UTC (permalink / raw)
  To: Richard Biener
  Cc: Trevor Saunders, Martin Sebor, Richard Biener via Gcc-patches

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>
>> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
>> > On 6/21/21 1:15 AM, Richard Biener wrote:
> [...]
>> > >
>> > > But maybe I'm misunderstanding C++ too much :/
>> > >
>> > > Well, I guess b) from above means auto_vec<> passing to
>> > > vec<> taking functions will need changes?
>> >
>> > Converting an auto_vec object to a vec slices off its data members.
>> > The auto_vec<T, 0> specialization has no data members so that's not
>> > a bug in and of itself, but auto_vec<T, N> does have data members
>> > so that would be a bug.  The risk is not just passing it to
>> > functions by value but also returning it.  That risk was made
>> > worse by the addition of the move ctor.
>>
>> I would agree that the conversion from auto_vec<> to vec<> is
>> questionable, and should get some work at some point, perhaps just
>> passingauto_vec references is good enough, or perhaps there is value in
>> some const_vec view to avoid having to rely on optimizations, I'm not
>> sure without looking more at the usage.
>
> We do need to be able to provide APIs that work with both auto_vec<>
> and vec<>, I agree that those currently taking a vec<> by value are
> fragile (and we've had bugs there before), but I'm not ready to say
> that changing them all to [const] vec<>& is OK.  The alternative
> would be passing a const_vec<> by value, passing that along to
> const vec<>& APIs should be valid then (I can see quite some API
> boundary cleanups being necessary here ...).

FWIW, as far as const_vec<> goes, we already have array_slice, which is
mostly a version of std::span.  (The only real reason for not using
std::span itself is that it requires a later version of C++.)

Taking those as arguments has the advantage that we can pass normal
arrays as well.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23  7:43                       ` Richard Biener
  2021-06-23 10:22                         ` Richard Sandiford
@ 2021-06-23 22:56                         ` Martin Sebor
  2021-06-24  9:27                           ` Richard Biener
  1 sibling, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-23 22:56 UTC (permalink / raw)
  To: Richard Biener, Trevor Saunders
  Cc: Richard Biener via Gcc-patches, Richard Sandiford

[-- Attachment #1: Type: text/plain, Size: 2703 bytes --]

On 6/23/21 1:43 AM, Richard Biener wrote:
> On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>
>> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
>>> On 6/21/21 1:15 AM, Richard Biener wrote:
> [...]
>>>>
>>>> But maybe I'm misunderstanding C++ too much :/
>>>>
>>>> Well, I guess b) from above means auto_vec<> passing to
>>>> vec<> taking functions will need changes?
>>>
>>> Converting an auto_vec object to a vec slices off its data members.
>>> The auto_vec<T, 0> specialization has no data members so that's not
>>> a bug in and of itself, but auto_vec<T, N> does have data members
>>> so that would be a bug.  The risk is not just passing it to
>>> functions by value but also returning it.  That risk was made
>>> worse by the addition of the move ctor.
>>
>> I would agree that the conversion from auto_vec<> to vec<> is
>> questionable, and should get some work at some point, perhaps just
>> passingauto_vec references is good enough, or perhaps there is value in
>> some const_vec view to avoid having to rely on optimizations, I'm not
>> sure without looking more at the usage.
> 
> We do need to be able to provide APIs that work with both auto_vec<>
> and vec<>, I agree that those currently taking a vec<> by value are
> fragile (and we've had bugs there before), but I'm not ready to say
> that changing them all to [const] vec<>& is OK.  The alternative
> would be passing a const_vec<> by value, passing that along to
> const vec<>& APIs should be valid then (I can see quite some API
> boundary cleanups being necessary here ...).
> 
> But with all this I don't know how to adjust auto_vec<> to no
> longer "decay" to vec<> but still being able to pass it to vec<>&
> and being able to call vec<> member functions w/o jumping through
> hoops.  Any hints on that?  private inheritance achieves the first
> but also hides all the API ...

The simplest way to do that is by preventing the implicit conversion
between the two types and adding a to_vec() member function to
auto_vec as Jason suggested.  This exposes the implicit conversions
to the base vec, forcing us to review each and "fix" it either by
changing the argument to either vec& or const vec&, or less often
to avoid the indirection if necessary, by converting the auto_vec
to vec explicitly by calling to_vec().  The attached diff shows
a very rough POC of what  that might look like.  A side benefit
is that it improves const-safety and makes the effects of functions
on their callers easier to understand.

But that's orthogonal to making auto_vec copy constructible and copy
assignable.  That change can be made independently and with much less
effort and no risk.

Martin

[-- Attachment #2: vec.diff --]
[-- Type: text/x-patch, Size: 13678 bytes --]

diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a671a3eb740..ab6db3860f5 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -759,8 +759,9 @@ extern tree c_finish_omp_clauses (tree, enum c_omp_region_type);
 extern tree c_build_va_arg (location_t, tree, location_t, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
-extern tree c_build_function_call_vec (location_t, vec<location_t>, tree,
-				       vec<tree, va_gc> *, vec<tree, va_gc> *);
+extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
+				       tree, vec<tree, va_gc> *,
+				       vec<tree, va_gc> *);
 extern tree c_omp_clause_copy_ctor (tree, tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/genautomata.c b/gcc/genautomata.c
index 6bbfc684afa..e488c5f28ef 100644
--- a/gcc/genautomata.c
+++ b/gcc/genautomata.c
@@ -6137,7 +6137,7 @@ evaluate_equiv_classes (automaton_t automaton, vec<state_t> *equiv_classes)
 
 /* The function merges equivalent states of AUTOMATON.  */
 static void
-merge_states (automaton_t automaton, vec<state_t> equiv_classes)
+merge_states (automaton_t automaton, const vec<state_t> &equiv_classes)
 {
   state_t curr_state;
   state_t new_state;
diff --git a/gcc/genextract.c b/gcc/genextract.c
index 6fe4a2524fc..3ed2f6846c9 100644
--- a/gcc/genextract.c
+++ b/gcc/genextract.c
@@ -214,7 +214,7 @@ VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
    to a NUL-terminated string in malloc memory.  */
 static char *
-VEC_char_to_string (vec<char> v)
+VEC_char_to_string (const vec<char> &v)
 {
   size_t n = v.length ();
   char *s = XNEWVEC (char, n + 1);
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 632947950e4..02ce068d9cf 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -2654,7 +2654,8 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
    go after the = _5 store and thus change behavior.  */
 
 static bool
-check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
+check_no_overlap (const vec<store_immediate_info *> &m_store_info,
+		  unsigned int i,
 		  bool all_integer_cst_p, unsigned int first_order,
 		  unsigned int last_order, unsigned HOST_WIDE_INT start,
 		  unsigned HOST_WIDE_INT end, unsigned int first_earlier,
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f1044e9c630..108daeda43b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -241,7 +241,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_vec (tree fn, vec<tree> args)
+gimple_build_call_vec (tree fn, const vec<tree> &args)
 {
   unsigned i;
   unsigned nargs = args.length ();
@@ -338,7 +338,7 @@ gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args)
+gimple_build_call_internal_vec (enum internal_fn fn, const vec<tree> &args)
 {
   unsigned i, nargs;
   gcall *call;
@@ -802,7 +802,7 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
    ARGS is a vector of labels excluding the default.  */
 
 gswitch *
-gimple_build_switch (tree index, tree default_label, vec<tree> args)
+gimple_build_switch (tree index, tree default_label, const vec<tree> &args)
 {
   unsigned i, nlabels = args.length ();
 
@@ -3049,7 +3049,7 @@ compare_case_labels (const void *p1, const void *p2)
 /* Sort the case labels in LABEL_VEC in place in ascending order.  */
 
 void
-sort_case_labels (vec<tree> label_vec)
+sort_case_labels (vec<tree> &label_vec)
 {
   label_vec.qsort (compare_case_labels);
 }
@@ -3074,7 +3074,7 @@ sort_case_labels (vec<tree> label_vec)
    found or not.  */
 
 void
-preprocess_case_label_vec_for_gimple (vec<tree> labels,
+preprocess_case_label_vec_for_gimple (vec<tree> &labels,
 				      tree index_type,
 				      tree *default_casep)
 {
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e7dc2a45a13..aabf68eaea0 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1516,11 +1516,11 @@ void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
-gcall *gimple_build_call_vec (tree, vec<tree> );
+gcall *gimple_build_call_vec (tree, const vec<tree> &);
 gcall *gimple_build_call (tree, unsigned, ...);
 gcall *gimple_build_call_valist (tree, unsigned, va_list);
 gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
-gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
+gcall *gimple_build_call_internal_vec (enum internal_fn, const vec<tree> &);
 gcall *gimple_build_call_from_tree (tree, tree);
 gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
@@ -1547,7 +1547,7 @@ gtry *gimple_build_try (gimple_seq, gimple_seq,
 gimple *gimple_build_wce (gimple_seq);
 gresx *gimple_build_resx (int);
 gswitch *gimple_build_switch_nlabels (unsigned, tree, tree);
-gswitch *gimple_build_switch (tree, tree, vec<tree> );
+gswitch *gimple_build_switch (tree, tree, const vec<tree> &);
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
@@ -1626,8 +1626,8 @@ extern bool nonbarrier_call_p (gimple *);
 extern bool infer_nonnull_range (gimple *, tree);
 extern bool infer_nonnull_range_by_dereference (gimple *, tree);
 extern bool infer_nonnull_range_by_attribute (gimple *, tree);
-extern void sort_case_labels (vec<tree>);
-extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
+extern void sort_case_labels (vec<tree> &);
+extern void preprocess_case_label_vec_for_gimple (vec<tree> &, tree, tree *);
 extern void gimple_seq_set_location (gimple_seq, location_t);
 extern void gimple_seq_discard (gimple_seq);
 extern void maybe_remove_unused_call_args (struct function *, gimple *);
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 9c88765d1fb..a166b706b8a 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -891,7 +891,7 @@ static void move_block_after_check (rtx_insn *);
 static void move_succs (vec<edge, va_gc> **, basic_block);
 static void sched_remove_insn (rtx_insn *);
 static void clear_priorities (rtx_insn *, rtx_vec_t *);
-static void calc_priorities (rtx_vec_t);
+static void calc_priorities (const rtx_vec_t &);
 static void add_jump_dependencies (rtx_insn *, rtx_insn *);
 
 #endif /* INSN_SCHEDULING */
@@ -7375,10 +7375,10 @@ haifa_sched_init (void)
     basic_block bb;
     FOR_EACH_BB_FN (bb, cfun)
       bbs.quick_push (bb);
-    sched_init_luids (bbs);
+    sched_init_luids (bbs.to_vec ());
     sched_deps_init (true);
     sched_extend_target ();
-    haifa_init_h_i_d (bbs);
+    haifa_init_h_i_d (bbs.to_vec ());
   }
 
   sched_init_only_bb = haifa_init_only_bb;
@@ -8923,7 +8923,7 @@ clear_priorities (rtx_insn *insn, rtx_vec_t *roots_ptr)
    changed.  ROOTS is a vector of instructions whose priority computation will
    trigger initialization of all cleared priorities.  */
 static void
-calc_priorities (rtx_vec_t roots)
+calc_priorities (const rtx_vec_t &roots)
 {
   int i;
   rtx_insn *insn;
@@ -8988,7 +8988,7 @@ sched_init_insn_luid (rtx_insn *insn)
    The hook common_sched_info->luid_for_non_insn () is used to determine
    if notes, labels, etc. need luids.  */
 void
-sched_init_luids (bb_vec_t bbs)
+sched_init_luids (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
@@ -9062,7 +9062,7 @@ init_h_i_d (rtx_insn *insn)
 
 /* Initialize haifa_insn_data for BBS.  */
 void
-haifa_init_h_i_d (bb_vec_t bbs)
+haifa_init_h_i_d (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 3d28a6e8640..511ec564846 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 4031ce18287..42120656366 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -1672,7 +1672,7 @@ finish_cost_vectors (void)
 
 static vec<ira_loop_tree_node_t>
 ira_loop_tree_body_rev_postorder (ira_loop_tree_node_t loop_node ATTRIBUTE_UNUSED,
-				  vec<ira_loop_tree_node_t> loop_preorder)
+				  const vec<ira_loop_tree_node_t> &loop_preorder)
 {
   vec<ira_loop_tree_node_t> topsort_nodes = vNULL;
   unsigned int n_loop_preorder;
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925402877ec..e9eb1049e37 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -937,7 +937,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	}
 
       if (oname)
-	add_overload_instance (oname, iterators, x);
+	add_overload_instance (oname, iterators.to_vec (), x);
 
       /* Add the new rtx to the end of the queue.  */
       queue->safe_push (x);
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..6c58395ee69 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -547,11 +547,7 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
    a vec instance, you can assign it the value vNULL.  This isn't
    needed for file-scope and function-local static vectors, which
    are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
+struct vnull { };
 extern vnull vNULL;
 
 
@@ -1431,10 +1427,25 @@ 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, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  vec () = default;
+  vec (const vec &) = default;
+  vec (vnull): m_vec () { }
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1533,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1560,13 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1620,13 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // You probably don't want to copy a vector, so these are deleted to prevent
   // unintentional use.  If you really need a copy of the vectors contents you
   // can use copy ().

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23  5:23                     ` Trevor Saunders
  2021-06-23  7:43                       ` Richard Biener
@ 2021-06-23 23:43                       ` Martin Sebor
  2021-06-28  7:01                         ` Trevor Saunders
  1 sibling, 1 reply; 51+ messages in thread
From: Martin Sebor @ 2021-06-23 23:43 UTC (permalink / raw)
  To: Trevor Saunders
  Cc: Richard Biener, Richard Biener via Gcc-patches, Richard Sandiford

On 6/22/21 11:23 PM, Trevor Saunders wrote:
> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
>> On 6/21/21 1:15 AM, Richard Biener wrote:
>>> On Fri, Jun 18, 2021 at 6:03 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 6/18/21 4:38 AM, Richard Biener wrote:
>>>>> On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>
>>>>>> On 6/17/21 12:03 AM, Richard Biener wrote:
>>>>>>> On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>>>
>>>>>>>> On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
>>>>>>>>> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>>>>>>>>>> On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>>>>>>>>>>
>>>>>>>>>>> This makes it clear the caller owns the vector, and ensures it is cleaned up.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
>>>>>>>>>>>
>>>>>>>>>>> bootstrapped and regtested on x86_64-linux-gnu, ok?
>>>>>>>>>>
>>>>>>>>>> OK.
>>>>>>>>>>
>>>>>>>>>> Btw, are "standard API" returns places we can use 'auto'?  That would avoid
>>>>>>>>>> excessive indent for
>>>>>>>>>>
>>>>>>>>>> -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>>>>> -                                    bbs.address (),
>>>>>>>>>> -                                    bbs.length ());
>>>>>>>>>> +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
>>>>>>>>>> +                                                          bbs.address (),
>>>>>>>>>> +                                                          bbs.length ());
>>>>>>>>>>
>>>>>>>>>> and just uses
>>>>>>>>>>
>>>>>>>>>>        auto dom_bbs = get_dominated_by_region (...
>>>>>>>>>>
>>>>>>>>>> Not asking you to do this, just a question for the audience.
>>>>>>>>>
>>>>>>>>> Personally I think this would be surprising for something that doesn't
>>>>>>>>> have copy semantics.  (Not that I'm trying to reopen that debate here :-)
>>>>>>>>> FWIW, I agree not having copy semantics is probably the most practical
>>>>>>>>> way forward for now.)
>>>>>>>>
>>>>>>>> But you did open the door for me to reiterate my strong disagreement
>>>>>>>> with that.  The best C++ practice going back to the early 1990's is
>>>>>>>> to make types safely copyable and assignable.  It is the default for
>>>>>>>> all types, in both C++ and C, and so natural and expected.
>>>>>>>>
>>>>>>>> Preventing copying is appropriate in special and rare circumstances
>>>>>>>> (e.g, a mutex may not be copyable, or a file or iostream object may
>>>>>>>> not be because they represent a unique physical resource.)
>>>>>>>>
>>>>>>>> In the absence of such special circumstances preventing copying is
>>>>>>>> unexpected, and in the case of an essential building block such as
>>>>>>>> a container, makes the type difficult to use.
>>>>>>>>
>>>>>>>> The only argument for disabling copying that has been given is
>>>>>>>> that it could be surprising(*).  But because all types are copyable
>>>>>>>> by default the "surprise" is usually when one can't be.
>>>>>>>>
>>>>>>>> I think Richi's "surprising" has to do with the fact that it lets
>>>>>>>> one inadvertently copy a large amount of data, thus leading to
>>>>>>>> an inefficiency.  But by analogy, there are infinitely many ways
>>>>>>>> to end up with inefficient code (e.g., deep recursion, or heap
>>>>>>>> allocation in a loop), and they are not a reason to ban the coding
>>>>>>>> constructs that might lead to it.
>>>>>>>>
>>>>>>>> IIUC, Jason's comment about surprising effects was about implicit
>>>>>>>> conversion from auto_vec to vec.  I share that concern, and agree
>>>>>>>> that it should be addressed by preventing the conversion (as Jason
>>>>>>>> suggested).
>>>>>>>
>>>>>>> But fact is that how vec<> and auto_vec<> are used today in GCC
>>>>>>> do not favor that.  In fact your proposed vec<> would be quite radically
>>>>>>> different (and IMHO vec<> and auto_vec<> should be unified then to
>>>>>>> form your proposed new container).  auto_vec<> at the moment simply
>>>>>>> maintains ownership like a smart pointer - which is _also_ not copyable.
>>>>>>
>>>>>> Yes, as we discussed in the review below, vec is not a good model
>>>>>> because (as you note again above) it's constrained by its legacy
>>>>>> uses.  The best I think we can do for it is to make it safer to
>>>>>> use.
>>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
>>>>>
>>>>> Which is what Trevors patches do by simply disallowing things
>>>>> that do not work at the moment.
>>>>>
>>>>>> (Smart pointers don't rule out copying.  A std::unique_ptr does
>>>>>> and std::shared_ptr doesn't.  But vec and especially auto_vec
>>>>>> are designed to be containers, not "unique pointers" so any
>>>>>> relationship there is purely superficial and a distraction.)
>>>>>>
>>>>>> That auto_vec and vec share a name and an is-a relationship is
>>>>>> incidental, an implementation detail leaked into the API.  A better
>>>>>> name than vector is hard to come up with, but the public inheritance
>>>>>> is a design flaw, a bug waiting to be introduced due to the conversion
>>>>>> and the assumptions the base vec makes about POD-ness and shallow
>>>>>> copying.  Hindsight is always 20/20 but past mistakes should not
>>>>>> dictate the design of a general purpose vector-like container in
>>>>>> GCC.
>>>>>
>>>>> That auto_vec<> "decays" to vec<> was on purpose design.
>>>>>
>>>>> By-value passing of vec<> is also on purpose to avoid an extra
>>>>> pointer indirection on each access.
>>>>
>>>> I think you may have misunderstood what I mean by is-a relationship.
>>>> It's fine to convert an auto_vec to another interface.  The danger
>>>> is in allowing that to happen implicitly because that tends to let
>>>> it happen even when it's not intended.  The usual way to avoid
>>>> that risk is to provide a conversion function, like
>>>> auto_vec::to_vec().  This is also why standard classes like
>>>> std::vector or std::string don't allow such implicit conversions
>>>> and instead provide member functions (see for example Stroustrup:
>>>> The C++ Programming Language).  So a safer auto_vec class would
>>>> not be publicly derived from vec but instead use the has-a design
>>>> (there are also ways to keep the derivation by deriving both from
>>>> from a limited, safe, interface, that each would extend as
>>>> appropriate).
>>>>
>>>> To the point of by passing vec by value while allowing functions
>>>> to modify the argument: C and C++ have by-value semantics.  Every
>>>> C and C++ programmer knows and expect that.  Designing interfaces
>>>> that break this assumption is perverse, a sure recipe for bugs.
>>>> If you're concerned about intuitive semantics and surprises you
>>>> should want to avoid that.
>>>>
>>>>>
>>>>>> I fully support fixing or at least mitigating the problems with
>>>>>> the vec base class (unsafe copying, pass-by-value etc.).  As I
>>>>>> mentioned, I already started working on this cleanup.  I also
>>>>>> have no objection to introducing a non-copyable form of a vector
>>>>>> template (I offered one in my patch), or even to making auto_vec
>>>>>> non-copyable provided a copyable and assignable one is introduced
>>>>>> at the same time, under some other name.
>>>>>
>>>>> Why at the same time?  I'm still not convinced we need another
>>>>> vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
>>>>> but then auto_vec<> doesn't bother to call the DTOR on its elements
>>>>> either (it's actually vec<> again here).  So auto_vec<> is _not_
>>>>> a fancier C++ vec<>, it's still just vec<> but with RAII for the container
>>>>> itself.
>>>>
>>>> I don't follow what you're saying.  Either you agree that making
>>>> auto_vec suitable as its own element would be useful.  If you do,
>>>> it needs to be safely copyable and assignable.
>>>>
>>>> The basic design principle of modern C++ containers is they store
>>>> their elements by value and make no further assumptions.  This means
>>>> that an int element is treated the same as int* element as a vec<int>
>>>> element: they're copied (or moved) by their ctors on insertion,
>>>> assigned when being replaced, and destroyed on removal.  Containers
>>>> themselves don't, as a rule, manage the resources owned by
>>>> the elements (like auto_delete_vec does).  The elements are
>>>> responsible for doing that, which is why they need to be safely
>>>> copyable and assignable.  vec meets these requirements because
>>>> it doesn't manage a resource (it's not a container).  Its memory
>>>> needs to be managed some other way.  auto_vec doesn't.  It is
>>>> designed to be a container but it's broken.  It won't become one
>>>> by deleting its copy ctor and assignment.
>>>>
>>>>>
>>>>>> Having said that, and although I don't mind the cleanup being taken
>>>>>> off my plate, I would have expected the courtesy of at least a heads
>>>>>> up first.  I do find it disrespectful for someone else involved in
>>>>>> the review of my work to at the same time submit a patch of their
>>>>>> own that goes in the opposite direction, and for you to unilaterally
>>>>>> approve it while the other review hasn't concluded yet.
>>>>>
>>>>> Because the changes do not change anything as far as I understand.
>>>>> They make more use of auto_vec<> ownership similar to when
>>>>> I added the move ctor and adjusted a single loop API.  At the same
>>>>> time it completes the move stuff and plugs some holes.
>>>>
>>>> The vast majority of Trevor's changes are improvements and I apprciate
>>>> them.  But the change to auto_vec goes against best C++ practices and
>>>> in the opposite direction of what I have been arguing for and what
>>>> I submitted a patch for in April.  The patch is still under discussion
>>>> that both you and Trevor, as well as Jason, have been participating in.
>>>> We have not concluded that discussion and it's in bad form to simply
>>>> disregard that and proceed in a different direction.  My understanding
>>>> from it so far is that
>>>>
>>>> a) you're not opposed to adding the copy ctor:
>>>>       https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568827.html
>>>> b) Jason advises to prevent implicit by-value conversion from auto_vec
>>>>       to vec
>>>>       https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571628.html
>>>> c) I said I was working on it (and more, some of it likely now
>>>>       obviated by Trevor's changes):
>>>>       https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
>>>>
>>>> So would I ask you both to respect that and refrain from approving
>>>> and committing this change (i.e., leave auto_vec as is for now)
>>>> until I've had time to finish my work.
>>>>
>>>> But checking the latest sources I see Trevor already committed
>>>> the change despite this.  That's in very poor form, and quite
>>>> disrespectful of both of you.
>>>
>>> The change was needed to make the useful portions work as far
>>> as I understood Trevor.  There's also nothing that prevents you
>>> from resolving the conflicts and continue with your improvements.
>>
>> The change disables things that were previously possible (but
>> undefined).  It isn't relied on by anything.  The change is
>> also incomplete: it disables copying and assignment for
>> the auto_vec<T, 0> specialization but not for the primary
>> template.   Neither is safe to copy or assign.
> 
> I suppose its technically true that it disables things that were
> possible, but for those things to work you'd have to jump through some
> hoops to prevent it causing a double free, so in practice I don't think
> you can really say it disables something, it just makes explicit what
> was already the case.  Since the move constructors would have prevented
> the compiler from providing a default definition of the copy
> constructor, there deletion is essentially just documentation.  Later
> patches in the series did depend on the move constructors to work
> properly.  I would agree that the template with inline storage could use
> with adjustment in this area, but I think its fine to handle it
> separately per Richi's request, and further I suspect its much less
> useful and likely to cause trouble, the main use case would be for
> function location things, and returning such an object  or passing it by
> value seems odd (not to say it is good the way it is, but that its of
> less practical importance).
> 
>> I could still submit a patch to fix that and make all auto_vec
>> specializations safely copyable but why should I bother?  You
>> have made it abundantly clear that you don't support it and
>> several others have taken your position despite all the problems
>> I have repeatedly pointed out.
> 
> Well, personally if you wanted to define something like
> template<typename T> T gcc::copy (const T &) = delete;  WIth
> specializations for things that could be coppied including anything
> that's POD, I think that might be reasonable, and much clearer than "="
> that calls malloc, if your issue is that .copy () on vec isn't the same
> as for other objects.  Personally I think its mostly YAGNI and there's
> few enough places coppying things for it to be a real problem, but at
> the same time I think there's no particular need .copy () is a member,
> just that its use is more obvious to the author and reader than
> "=".

auto_vec::copy() returns a vec so it's not the same thing as a copy
ctor/assignment.  vec happens to be convertible to auto_vec so it's
possible to copy auto_vec A to auto_vec B by B = A.copy() but that's
a convoluted way of copying or assigning one object to another.

Without looking up the types of the operands, the meaning of
B = A.copy() is certainly less obvious than that of B = A.  Same
for copy (B, A).  To those of us accustomed to basic C++ idioms,
it's unusual to have to call a named function to do what's
canonically accomplished by a native operator.  It raises
the question of what else the call might do that the expected
alternative wouldn't.  To Richi's concern about the inefficiency
of deep copies, forcing users to call A.copy() to make one runs
the risk that they will do it even when it's not necessary and
when the move ctor or assignment would be suitable.  It's much
better (and in line with the intended use of the feature) to
use the familiar initialization or assignment syntax and trust
the compiler make the right call whether to do a deep copy or
to move.

More generally, obviating the distinction between native types
and user-defined types is one of the most powerful features of
C++.  It makes it possible to write generic code: not just
templates but any piece of code that's agnostic of the types
it works with.  There are many benefits: code that uses common
idioms and operators is easier to understand, swapping one data
type for another becomes trivial, and similarities between
different pieces of code are more apparent, opening up
opportunities for reuse and refactoring.  Designing classes
to be gratuitously different means missing out on some of
the most valuable benefits of using the language.  But I'm
just paraphrasing arguments that have been made much more
convincingly by authors of the many excellent C++ books out
there (some of my favorites are Herb Sutter's Exceptional C++
series).

Martin

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23 10:22                         ` Richard Sandiford
@ 2021-06-24  9:20                           ` Richard Biener
  2021-06-24 16:28                             ` Richard Sandiford
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-24  9:20 UTC (permalink / raw)
  To: Richard Biener, Trevor Saunders, Martin Sebor,
	Richard Biener via Gcc-patches, Richard Sandiford

On Wed, Jun 23, 2021 at 12:22 PM Richard Sandiford
<richard.sandiford@arm.com> wrote:
>
> Richard Biener <richard.guenther@gmail.com> writes:
> > On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >>
> >> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
> >> > On 6/21/21 1:15 AM, Richard Biener wrote:
> > [...]
> >> > >
> >> > > But maybe I'm misunderstanding C++ too much :/
> >> > >
> >> > > Well, I guess b) from above means auto_vec<> passing to
> >> > > vec<> taking functions will need changes?
> >> >
> >> > Converting an auto_vec object to a vec slices off its data members.
> >> > The auto_vec<T, 0> specialization has no data members so that's not
> >> > a bug in and of itself, but auto_vec<T, N> does have data members
> >> > so that would be a bug.  The risk is not just passing it to
> >> > functions by value but also returning it.  That risk was made
> >> > worse by the addition of the move ctor.
> >>
> >> I would agree that the conversion from auto_vec<> to vec<> is
> >> questionable, and should get some work at some point, perhaps just
> >> passingauto_vec references is good enough, or perhaps there is value in
> >> some const_vec view to avoid having to rely on optimizations, I'm not
> >> sure without looking more at the usage.
> >
> > We do need to be able to provide APIs that work with both auto_vec<>
> > and vec<>, I agree that those currently taking a vec<> by value are
> > fragile (and we've had bugs there before), but I'm not ready to say
> > that changing them all to [const] vec<>& is OK.  The alternative
> > would be passing a const_vec<> by value, passing that along to
> > const vec<>& APIs should be valid then (I can see quite some API
> > boundary cleanups being necessary here ...).
>
> FWIW, as far as const_vec<> goes, we already have array_slice, which is
> mostly a version of std::span.  (The only real reason for not using
> std::span itself is that it requires a later version of C++.)
>
> Taking those as arguments has the advantage that we can pass normal
> arrays as well.

It's not really a "const" thing it seems though it certainly would not expose
any API that would reallocate the vector (which is the problematic part
of passing vec<> by value, not necessarily changing elements in-place).

Since array_slice doesn't inherit most of the vec<> API transforming an
API from vec<> to array_slice<> will be also quite some work.  But I
agree it might be useful for generic API stuff.

Richard.

> Thanks,
> Richard

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23 22:56                         ` Martin Sebor
@ 2021-06-24  9:27                           ` Richard Biener
  2021-06-24 15:01                             ` Martin Sebor
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Biener @ 2021-06-24  9:27 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Trevor Saunders, Richard Biener via Gcc-patches, Richard Sandiford

On Thu, Jun 24, 2021 at 12:56 AM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/23/21 1:43 AM, Richard Biener wrote:
> > On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >>
> >> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
> >>> On 6/21/21 1:15 AM, Richard Biener wrote:
> > [...]
> >>>>
> >>>> But maybe I'm misunderstanding C++ too much :/
> >>>>
> >>>> Well, I guess b) from above means auto_vec<> passing to
> >>>> vec<> taking functions will need changes?
> >>>
> >>> Converting an auto_vec object to a vec slices off its data members.
> >>> The auto_vec<T, 0> specialization has no data members so that's not
> >>> a bug in and of itself, but auto_vec<T, N> does have data members
> >>> so that would be a bug.  The risk is not just passing it to
> >>> functions by value but also returning it.  That risk was made
> >>> worse by the addition of the move ctor.
> >>
> >> I would agree that the conversion from auto_vec<> to vec<> is
> >> questionable, and should get some work at some point, perhaps just
> >> passingauto_vec references is good enough, or perhaps there is value in
> >> some const_vec view to avoid having to rely on optimizations, I'm not
> >> sure without looking more at the usage.
> >
> > We do need to be able to provide APIs that work with both auto_vec<>
> > and vec<>, I agree that those currently taking a vec<> by value are
> > fragile (and we've had bugs there before), but I'm not ready to say
> > that changing them all to [const] vec<>& is OK.  The alternative
> > would be passing a const_vec<> by value, passing that along to
> > const vec<>& APIs should be valid then (I can see quite some API
> > boundary cleanups being necessary here ...).
> >
> > But with all this I don't know how to adjust auto_vec<> to no
> > longer "decay" to vec<> but still being able to pass it to vec<>&
> > and being able to call vec<> member functions w/o jumping through
> > hoops.  Any hints on that?  private inheritance achieves the first
> > but also hides all the API ...
>
> The simplest way to do that is by preventing the implicit conversion
> between the two types and adding a to_vec() member function to
> auto_vec as Jason suggested.  This exposes the implicit conversions
> to the base vec, forcing us to review each and "fix" it either by
> changing the argument to either vec& or const vec&, or less often
> to avoid the indirection if necessary, by converting the auto_vec
> to vec explicitly by calling to_vec().  The attached diff shows
> a very rough POC of what  that might look like.  A side benefit
> is that it improves const-safety and makes the effects of functions
> on their callers easier to understand.
>
> But that's orthogonal to making auto_vec copy constructible and copy
> assignable.  That change can be made independently and with much less
> effort and no risk.

There's a bunch of stuff I can't review because of lack of C++ knowledge
(the vNULL changes).

I suppose that

+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;

still allows passing auto_vec<> to [const] vec<> & without the .to_vec so
it's just the by-value passing that becomes explicit?  If so then I agree
this is an improvement.  The patch is likely incomplete though or is
it really only so few signatures that need changing?

Thanks,
Richard.

> Martin

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-24  9:27                           ` Richard Biener
@ 2021-06-24 15:01                             ` Martin Sebor
  0 siblings, 0 replies; 51+ messages in thread
From: Martin Sebor @ 2021-06-24 15:01 UTC (permalink / raw)
  To: Richard Biener
  Cc: Trevor Saunders, Richard Biener via Gcc-patches, Richard Sandiford

On 6/24/21 3:27 AM, Richard Biener wrote:
> On Thu, Jun 24, 2021 at 12:56 AM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 6/23/21 1:43 AM, Richard Biener wrote:
>>> On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>>>
>>>> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
>>>>> On 6/21/21 1:15 AM, Richard Biener wrote:
>>> [...]
>>>>>>
>>>>>> But maybe I'm misunderstanding C++ too much :/
>>>>>>
>>>>>> Well, I guess b) from above means auto_vec<> passing to
>>>>>> vec<> taking functions will need changes?
>>>>>
>>>>> Converting an auto_vec object to a vec slices off its data members.
>>>>> The auto_vec<T, 0> specialization has no data members so that's not
>>>>> a bug in and of itself, but auto_vec<T, N> does have data members
>>>>> so that would be a bug.  The risk is not just passing it to
>>>>> functions by value but also returning it.  That risk was made
>>>>> worse by the addition of the move ctor.
>>>>
>>>> I would agree that the conversion from auto_vec<> to vec<> is
>>>> questionable, and should get some work at some point, perhaps just
>>>> passingauto_vec references is good enough, or perhaps there is value in
>>>> some const_vec view to avoid having to rely on optimizations, I'm not
>>>> sure without looking more at the usage.
>>>
>>> We do need to be able to provide APIs that work with both auto_vec<>
>>> and vec<>, I agree that those currently taking a vec<> by value are
>>> fragile (and we've had bugs there before), but I'm not ready to say
>>> that changing them all to [const] vec<>& is OK.  The alternative
>>> would be passing a const_vec<> by value, passing that along to
>>> const vec<>& APIs should be valid then (I can see quite some API
>>> boundary cleanups being necessary here ...).
>>>
>>> But with all this I don't know how to adjust auto_vec<> to no
>>> longer "decay" to vec<> but still being able to pass it to vec<>&
>>> and being able to call vec<> member functions w/o jumping through
>>> hoops.  Any hints on that?  private inheritance achieves the first
>>> but also hides all the API ...
>>
>> The simplest way to do that is by preventing the implicit conversion
>> between the two types and adding a to_vec() member function to
>> auto_vec as Jason suggested.  This exposes the implicit conversions
>> to the base vec, forcing us to review each and "fix" it either by
>> changing the argument to either vec& or const vec&, or less often
>> to avoid the indirection if necessary, by converting the auto_vec
>> to vec explicitly by calling to_vec().  The attached diff shows
>> a very rough POC of what  that might look like.  A side benefit
>> is that it improves const-safety and makes the effects of functions
>> on their callers easier to understand.
>>
>> But that's orthogonal to making auto_vec copy constructible and copy
>> assignable.  That change can be made independently and with much less
>> effort and no risk.
> 
> There's a bunch of stuff I can't review because of lack of C++ knowledge
> (the vNULL changes).
> 
> I suppose that
> 
> +  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
> +     instead.  */
> +  template <size_t N>
> +  vec (auto_vec<T, N> &) = delete;
> +
> +  template <size_t N>
> +  void operator= (auto_vec<T, N> &) = delete;
> 
> still allows passing auto_vec<> to [const] vec<> & without the .to_vec so
> it's just the by-value passing that becomes explicit?  If so then I agree
> this is an improvement.  The patch is likely incomplete though or is
> it really only so few signatures that need changing?

Yes, to both questions.

I just wanted to show how we might go about making this transition.
I converted a few files but many more remain.  I stopped when
changing a vec argument to const vec& started to cause errors due
to missing const down the line (e.g., assigning the address of a vec
element to an uqualified pointer).  I'll need to follow where that
pointer flows and see if it's used to modify the object or if it too
could be made const.  To me that seems worthwhile doing now but it
makes progress slow.

A separate question is whether the vec value arguments to functions
that modify them should be changed to references or pointers.  Both
kinds of APIs exist but the latter seems prevalent.  Changing them
to the latter means more churn.

Martin

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-24  9:20                           ` Richard Biener
@ 2021-06-24 16:28                             ` Richard Sandiford
  2021-06-25  8:29                               ` Richard Biener
  0 siblings, 1 reply; 51+ messages in thread
From: Richard Sandiford @ 2021-06-24 16:28 UTC (permalink / raw)
  To: Richard Biener via Gcc-patches
  Cc: Richard Biener, Trevor Saunders, Martin Sebor

Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> On Wed, Jun 23, 2021 at 12:22 PM Richard Sandiford
> <richard.sandiford@arm.com> wrote:
>>
>> Richard Biener <richard.guenther@gmail.com> writes:
>> > On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>> >>
>> >> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
>> >> > On 6/21/21 1:15 AM, Richard Biener wrote:
>> > [...]
>> >> > >
>> >> > > But maybe I'm misunderstanding C++ too much :/
>> >> > >
>> >> > > Well, I guess b) from above means auto_vec<> passing to
>> >> > > vec<> taking functions will need changes?
>> >> >
>> >> > Converting an auto_vec object to a vec slices off its data members.
>> >> > The auto_vec<T, 0> specialization has no data members so that's not
>> >> > a bug in and of itself, but auto_vec<T, N> does have data members
>> >> > so that would be a bug.  The risk is not just passing it to
>> >> > functions by value but also returning it.  That risk was made
>> >> > worse by the addition of the move ctor.
>> >>
>> >> I would agree that the conversion from auto_vec<> to vec<> is
>> >> questionable, and should get some work at some point, perhaps just
>> >> passingauto_vec references is good enough, or perhaps there is value in
>> >> some const_vec view to avoid having to rely on optimizations, I'm not
>> >> sure without looking more at the usage.
>> >
>> > We do need to be able to provide APIs that work with both auto_vec<>
>> > and vec<>, I agree that those currently taking a vec<> by value are
>> > fragile (and we've had bugs there before), but I'm not ready to say
>> > that changing them all to [const] vec<>& is OK.  The alternative
>> > would be passing a const_vec<> by value, passing that along to
>> > const vec<>& APIs should be valid then (I can see quite some API
>> > boundary cleanups being necessary here ...).
>>
>> FWIW, as far as const_vec<> goes, we already have array_slice, which is
>> mostly a version of std::span.  (The only real reason for not using
>> std::span itself is that it requires a later version of C++.)
>>
>> Taking those as arguments has the advantage that we can pass normal
>> arrays as well.
>
> It's not really a "const" thing it seems though it certainly would not expose
> any API that would reallocate the vector (which is the problematic part
> of passing vec<> by value, not necessarily changing elements in-place).
>
> Since array_slice doesn't inherit most of the vec<> API transforming an
> API from vec<> to array_slice<> will be also quite some work.  But I
> agree it might be useful for generic API stuff.

Which API functions would be the most useful ones to have?  We could
add them if necessary.

There again, for things like searching and sorting, I think it would
be better to use <algorithm> where possible.  It should usually be
more efficient than the void* callback approach that the C code tended
to use.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-24 16:28                             ` Richard Sandiford
@ 2021-06-25  8:29                               ` Richard Biener
  0 siblings, 0 replies; 51+ messages in thread
From: Richard Biener @ 2021-06-25  8:29 UTC (permalink / raw)
  To: Richard Biener via Gcc-patches, Richard Biener, Trevor Saunders,
	Martin Sebor, Richard Sandiford

On Thu, Jun 24, 2021 at 6:28 PM Richard Sandiford
<richard.sandiford@arm.com> wrote:
>
> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> > On Wed, Jun 23, 2021 at 12:22 PM Richard Sandiford
> > <richard.sandiford@arm.com> wrote:
> >>
> >> Richard Biener <richard.guenther@gmail.com> writes:
> >> > On Wed, Jun 23, 2021 at 7:23 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >> >>
> >> >> On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
> >> >> > On 6/21/21 1:15 AM, Richard Biener wrote:
> >> > [...]
> >> >> > >
> >> >> > > But maybe I'm misunderstanding C++ too much :/
> >> >> > >
> >> >> > > Well, I guess b) from above means auto_vec<> passing to
> >> >> > > vec<> taking functions will need changes?
> >> >> >
> >> >> > Converting an auto_vec object to a vec slices off its data members.
> >> >> > The auto_vec<T, 0> specialization has no data members so that's not
> >> >> > a bug in and of itself, but auto_vec<T, N> does have data members
> >> >> > so that would be a bug.  The risk is not just passing it to
> >> >> > functions by value but also returning it.  That risk was made
> >> >> > worse by the addition of the move ctor.
> >> >>
> >> >> I would agree that the conversion from auto_vec<> to vec<> is
> >> >> questionable, and should get some work at some point, perhaps just
> >> >> passingauto_vec references is good enough, or perhaps there is value in
> >> >> some const_vec view to avoid having to rely on optimizations, I'm not
> >> >> sure without looking more at the usage.
> >> >
> >> > We do need to be able to provide APIs that work with both auto_vec<>
> >> > and vec<>, I agree that those currently taking a vec<> by value are
> >> > fragile (and we've had bugs there before), but I'm not ready to say
> >> > that changing them all to [const] vec<>& is OK.  The alternative
> >> > would be passing a const_vec<> by value, passing that along to
> >> > const vec<>& APIs should be valid then (I can see quite some API
> >> > boundary cleanups being necessary here ...).
> >>
> >> FWIW, as far as const_vec<> goes, we already have array_slice, which is
> >> mostly a version of std::span.  (The only real reason for not using
> >> std::span itself is that it requires a later version of C++.)
> >>
> >> Taking those as arguments has the advantage that we can pass normal
> >> arrays as well.
> >
> > It's not really a "const" thing it seems though it certainly would not expose
> > any API that would reallocate the vector (which is the problematic part
> > of passing vec<> by value, not necessarily changing elements in-place).
> >
> > Since array_slice doesn't inherit most of the vec<> API transforming an
> > API from vec<> to array_slice<> will be also quite some work.  But I
> > agree it might be useful for generic API stuff.
>
> Which API functions would be the most useful ones to have?  We could
> add them if necessary.

I think we'll see when introducing uses.  I guess that vec<> to const vec<>&
changes will be mostly fine but for vec<> to vec<>& I might prefer
vec<> to array_slice<> since that makes clear the caller won't re-allocate.
We'll see what those APIs would require then.

> There again, for things like searching and sorting, I think it would
> be better to use <algorithm> where possible.  It should usually be
> more efficient than the void* callback approach that the C code tended
> to use.

Not sure whether <algorithm> really is better, we've specifically replaced
libc qsort calls with our own sort to avoid all sorts of host isues and
the vec<>::bsearch is inline and thus the callbacks can be inlined.

Richard.

> Thanks,
> Richard

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 5/6] make get_domminated_by_region return a auto_vec
  2021-06-23 23:43                       ` Martin Sebor
@ 2021-06-28  7:01                         ` Trevor Saunders
  0 siblings, 0 replies; 51+ messages in thread
From: Trevor Saunders @ 2021-06-28  7:01 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Richard Biener, Richard Biener via Gcc-patches, Richard Sandiford

On Wed, Jun 23, 2021 at 05:43:32PM -0600, Martin Sebor wrote:
> On 6/22/21 11:23 PM, Trevor Saunders wrote:
> > On Tue, Jun 22, 2021 at 02:01:24PM -0600, Martin Sebor wrote:
> > > On 6/21/21 1:15 AM, Richard Biener wrote:
> > > > On Fri, Jun 18, 2021 at 6:03 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > 
> > > > > On 6/18/21 4:38 AM, Richard Biener wrote:
> > > > > > On Thu, Jun 17, 2021 at 4:43 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > 
> > > > > > > On 6/17/21 12:03 AM, Richard Biener wrote:
> > > > > > > > On Wed, Jun 16, 2021 at 6:01 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > > > 
> > > > > > > > > On 6/16/21 6:46 AM, Richard Sandiford via Gcc-patches wrote:
> > > > > > > > > > Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> > > > > > > > > > > On Tue, Jun 15, 2021 at 8:02 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > This makes it clear the caller owns the vector, and ensures it is cleaned up.
> > > > > > > > > > > > 
> > > > > > > > > > > > Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
> > > > > > > > > > > > 
> > > > > > > > > > > > bootstrapped and regtested on x86_64-linux-gnu, ok?
> > > > > > > > > > > 
> > > > > > > > > > > OK.
> > > > > > > > > > > 
> > > > > > > > > > > Btw, are "standard API" returns places we can use 'auto'?  That would avoid
> > > > > > > > > > > excessive indent for
> > > > > > > > > > > 
> > > > > > > > > > > -  dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > > > > > > > > > > -                                    bbs.address (),
> > > > > > > > > > > -                                    bbs.length ());
> > > > > > > > > > > +  auto_vec<basic_block> dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
> > > > > > > > > > > +                                                          bbs.address (),
> > > > > > > > > > > +                                                          bbs.length ());
> > > > > > > > > > > 
> > > > > > > > > > > and just uses
> > > > > > > > > > > 
> > > > > > > > > > >        auto dom_bbs = get_dominated_by_region (...
> > > > > > > > > > > 
> > > > > > > > > > > Not asking you to do this, just a question for the audience.
> > > > > > > > > > 
> > > > > > > > > > Personally I think this would be surprising for something that doesn't
> > > > > > > > > > have copy semantics.  (Not that I'm trying to reopen that debate here :-)
> > > > > > > > > > FWIW, I agree not having copy semantics is probably the most practical
> > > > > > > > > > way forward for now.)
> > > > > > > > > 
> > > > > > > > > But you did open the door for me to reiterate my strong disagreement
> > > > > > > > > with that.  The best C++ practice going back to the early 1990's is
> > > > > > > > > to make types safely copyable and assignable.  It is the default for
> > > > > > > > > all types, in both C++ and C, and so natural and expected.
> > > > > > > > > 
> > > > > > > > > Preventing copying is appropriate in special and rare circumstances
> > > > > > > > > (e.g, a mutex may not be copyable, or a file or iostream object may
> > > > > > > > > not be because they represent a unique physical resource.)
> > > > > > > > > 
> > > > > > > > > In the absence of such special circumstances preventing copying is
> > > > > > > > > unexpected, and in the case of an essential building block such as
> > > > > > > > > a container, makes the type difficult to use.
> > > > > > > > > 
> > > > > > > > > The only argument for disabling copying that has been given is
> > > > > > > > > that it could be surprising(*).  But because all types are copyable
> > > > > > > > > by default the "surprise" is usually when one can't be.
> > > > > > > > > 
> > > > > > > > > I think Richi's "surprising" has to do with the fact that it lets
> > > > > > > > > one inadvertently copy a large amount of data, thus leading to
> > > > > > > > > an inefficiency.  But by analogy, there are infinitely many ways
> > > > > > > > > to end up with inefficient code (e.g., deep recursion, or heap
> > > > > > > > > allocation in a loop), and they are not a reason to ban the coding
> > > > > > > > > constructs that might lead to it.
> > > > > > > > > 
> > > > > > > > > IIUC, Jason's comment about surprising effects was about implicit
> > > > > > > > > conversion from auto_vec to vec.  I share that concern, and agree
> > > > > > > > > that it should be addressed by preventing the conversion (as Jason
> > > > > > > > > suggested).
> > > > > > > > 
> > > > > > > > But fact is that how vec<> and auto_vec<> are used today in GCC
> > > > > > > > do not favor that.  In fact your proposed vec<> would be quite radically
> > > > > > > > different (and IMHO vec<> and auto_vec<> should be unified then to
> > > > > > > > form your proposed new container).  auto_vec<> at the moment simply
> > > > > > > > maintains ownership like a smart pointer - which is _also_ not copyable.
> > > > > > > 
> > > > > > > Yes, as we discussed in the review below, vec is not a good model
> > > > > > > because (as you note again above) it's constrained by its legacy
> > > > > > > uses.  The best I think we can do for it is to make it safer to
> > > > > > > use.
> > > > > > > https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> > > > > > 
> > > > > > Which is what Trevors patches do by simply disallowing things
> > > > > > that do not work at the moment.
> > > > > > 
> > > > > > > (Smart pointers don't rule out copying.  A std::unique_ptr does
> > > > > > > and std::shared_ptr doesn't.  But vec and especially auto_vec
> > > > > > > are designed to be containers, not "unique pointers" so any
> > > > > > > relationship there is purely superficial and a distraction.)
> > > > > > > 
> > > > > > > That auto_vec and vec share a name and an is-a relationship is
> > > > > > > incidental, an implementation detail leaked into the API.  A better
> > > > > > > name than vector is hard to come up with, but the public inheritance
> > > > > > > is a design flaw, a bug waiting to be introduced due to the conversion
> > > > > > > and the assumptions the base vec makes about POD-ness and shallow
> > > > > > > copying.  Hindsight is always 20/20 but past mistakes should not
> > > > > > > dictate the design of a general purpose vector-like container in
> > > > > > > GCC.
> > > > > > 
> > > > > > That auto_vec<> "decays" to vec<> was on purpose design.
> > > > > > 
> > > > > > By-value passing of vec<> is also on purpose to avoid an extra
> > > > > > pointer indirection on each access.
> > > > > 
> > > > > I think you may have misunderstood what I mean by is-a relationship.
> > > > > It's fine to convert an auto_vec to another interface.  The danger
> > > > > is in allowing that to happen implicitly because that tends to let
> > > > > it happen even when it's not intended.  The usual way to avoid
> > > > > that risk is to provide a conversion function, like
> > > > > auto_vec::to_vec().  This is also why standard classes like
> > > > > std::vector or std::string don't allow such implicit conversions
> > > > > and instead provide member functions (see for example Stroustrup:
> > > > > The C++ Programming Language).  So a safer auto_vec class would
> > > > > not be publicly derived from vec but instead use the has-a design
> > > > > (there are also ways to keep the derivation by deriving both from
> > > > > from a limited, safe, interface, that each would extend as
> > > > > appropriate).
> > > > > 
> > > > > To the point of by passing vec by value while allowing functions
> > > > > to modify the argument: C and C++ have by-value semantics.  Every
> > > > > C and C++ programmer knows and expect that.  Designing interfaces
> > > > > that break this assumption is perverse, a sure recipe for bugs.
> > > > > If you're concerned about intuitive semantics and surprises you
> > > > > should want to avoid that.
> > > > > 
> > > > > > 
> > > > > > > I fully support fixing or at least mitigating the problems with
> > > > > > > the vec base class (unsafe copying, pass-by-value etc.).  As I
> > > > > > > mentioned, I already started working on this cleanup.  I also
> > > > > > > have no objection to introducing a non-copyable form of a vector
> > > > > > > template (I offered one in my patch), or even to making auto_vec
> > > > > > > non-copyable provided a copyable and assignable one is introduced
> > > > > > > at the same time, under some other name.
> > > > > > 
> > > > > > Why at the same time?  I'm still not convinced we need another
> > > > > > vector type here.  Yes, auto_vec<auto_vec<..> > would be convenient,
> > > > > > but then auto_vec<> doesn't bother to call the DTOR on its elements
> > > > > > either (it's actually vec<> again here).  So auto_vec<> is _not_
> > > > > > a fancier C++ vec<>, it's still just vec<> but with RAII for the container
> > > > > > itself.
> > > > > 
> > > > > I don't follow what you're saying.  Either you agree that making
> > > > > auto_vec suitable as its own element would be useful.  If you do,
> > > > > it needs to be safely copyable and assignable.
> > > > > 
> > > > > The basic design principle of modern C++ containers is they store
> > > > > their elements by value and make no further assumptions.  This means
> > > > > that an int element is treated the same as int* element as a vec<int>
> > > > > element: they're copied (or moved) by their ctors on insertion,
> > > > > assigned when being replaced, and destroyed on removal.  Containers
> > > > > themselves don't, as a rule, manage the resources owned by
> > > > > the elements (like auto_delete_vec does).  The elements are
> > > > > responsible for doing that, which is why they need to be safely
> > > > > copyable and assignable.  vec meets these requirements because
> > > > > it doesn't manage a resource (it's not a container).  Its memory
> > > > > needs to be managed some other way.  auto_vec doesn't.  It is
> > > > > designed to be a container but it's broken.  It won't become one
> > > > > by deleting its copy ctor and assignment.
> > > > > 
> > > > > > 
> > > > > > > Having said that, and although I don't mind the cleanup being taken
> > > > > > > off my plate, I would have expected the courtesy of at least a heads
> > > > > > > up first.  I do find it disrespectful for someone else involved in
> > > > > > > the review of my work to at the same time submit a patch of their
> > > > > > > own that goes in the opposite direction, and for you to unilaterally
> > > > > > > approve it while the other review hasn't concluded yet.
> > > > > > 
> > > > > > Because the changes do not change anything as far as I understand.
> > > > > > They make more use of auto_vec<> ownership similar to when
> > > > > > I added the move ctor and adjusted a single loop API.  At the same
> > > > > > time it completes the move stuff and plugs some holes.
> > > > > 
> > > > > The vast majority of Trevor's changes are improvements and I apprciate
> > > > > them.  But the change to auto_vec goes against best C++ practices and
> > > > > in the opposite direction of what I have been arguing for and what
> > > > > I submitted a patch for in April.  The patch is still under discussion
> > > > > that both you and Trevor, as well as Jason, have been participating in.
> > > > > We have not concluded that discussion and it's in bad form to simply
> > > > > disregard that and proceed in a different direction.  My understanding
> > > > > from it so far is that
> > > > > 
> > > > > a) you're not opposed to adding the copy ctor:
> > > > >       https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568827.html
> > > > > b) Jason advises to prevent implicit by-value conversion from auto_vec
> > > > >       to vec
> > > > >       https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571628.html
> > > > > c) I said I was working on it (and more, some of it likely now
> > > > >       obviated by Trevor's changes):
> > > > >       https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571622.html
> > > > > 
> > > > > So would I ask you both to respect that and refrain from approving
> > > > > and committing this change (i.e., leave auto_vec as is for now)
> > > > > until I've had time to finish my work.
> > > > > 
> > > > > But checking the latest sources I see Trevor already committed
> > > > > the change despite this.  That's in very poor form, and quite
> > > > > disrespectful of both of you.
> > > > 
> > > > The change was needed to make the useful portions work as far
> > > > as I understood Trevor.  There's also nothing that prevents you
> > > > from resolving the conflicts and continue with your improvements.
> > > 
> > > The change disables things that were previously possible (but
> > > undefined).  It isn't relied on by anything.  The change is
> > > also incomplete: it disables copying and assignment for
> > > the auto_vec<T, 0> specialization but not for the primary
> > > template.   Neither is safe to copy or assign.
> > 
> > I suppose its technically true that it disables things that were
> > possible, but for those things to work you'd have to jump through some
> > hoops to prevent it causing a double free, so in practice I don't think
> > you can really say it disables something, it just makes explicit what
> > was already the case.  Since the move constructors would have prevented
> > the compiler from providing a default definition of the copy
> > constructor, there deletion is essentially just documentation.  Later
> > patches in the series did depend on the move constructors to work
> > properly.  I would agree that the template with inline storage could use
> > with adjustment in this area, but I think its fine to handle it
> > separately per Richi's request, and further I suspect its much less
> > useful and likely to cause trouble, the main use case would be for
> > function location things, and returning such an object  or passing it by
> > value seems odd (not to say it is good the way it is, but that its of
> > less practical importance).
> > 
> > > I could still submit a patch to fix that and make all auto_vec
> > > specializations safely copyable but why should I bother?  You
> > > have made it abundantly clear that you don't support it and
> > > several others have taken your position despite all the problems
> > > I have repeatedly pointed out.
> > 
> > Well, personally if you wanted to define something like
> > template<typename T> T gcc::copy (const T &) = delete;  WIth
> > specializations for things that could be coppied including anything
> > that's POD, I think that might be reasonable, and much clearer than "="
> > that calls malloc, if your issue is that .copy () on vec isn't the same
> > as for other objects.  Personally I think its mostly YAGNI and there's
> > few enough places coppying things for it to be a real problem, but at
> > the same time I think there's no particular need .copy () is a member,
> > just that its use is more obvious to the author and reader than
> > "=".
> 
> auto_vec::copy() returns a vec so it's not the same thing as a copy
> ctor/assignment.  vec happens to be convertible to auto_vec so it's
> possible to copy auto_vec A to auto_vec B by B = A.copy() but that's
> a convoluted way of copying or assigning one object to another.

Well, it should definitly return an auto_vec, but other than that I'm
not sure what is so convoluted about it, other than preferences about
the way it looks.

> Without looking up the types of the operands, the meaning of
> B = A.copy() is certainly less obvious than that of B = A.  Same
> for copy (B, A).  To those of us accustomed to basic C++ idioms,
> it's unusual to have to call a named function to do what's
> canonically accomplished by a native operator.  It raises
> the question of what else the call might do that the expected

Really? if a function's name is copy, what can it reasonably do other
than produce a copy of its argument?

> alternative wouldn't.  To Richi's concern about the inefficiency
> of deep copies, forcing users to call A.copy() to make one runs
> the risk that they will do it even when it's not necessary and
> when the move ctor or assignment would be suitable.  It's much
> better (and in line with the intended use of the feature) to
> use the familiar initialization or assignment syntax and trust
> the compiler make the right call whether to do a deep copy or
> to move.

I suppose its theoretically possible someone could call copy() and it
not get questioned by a reviewer just like it is for any other function.
However there is a function call there to make the reviewer remember to
ask "wy?", rather than them needing to remember to ask at basically
every use of "=" "should there be a std::move() here?".  While it might
be nice if the compiler could actually handle all this itself, it can't,
and that isn't how the language works.  First lets consider some
examples.
{
	auto_vec<int> x;
	x.safe_push (1);
	auto_vec<int> y (x);
	auto_vec<int> z = y;
}

It should be obvious to a human that moves and no coppies would be fine here,
however the compiler can't figure out that the objects are dead after the
assignment, and so move candidates.  Or for a more real world case of the same sort of thing I saw the other day:

  gimple_poly_bb (basic_block bb, auto_vec<data_reference_p> drs,
                  auto_vec<scalar_use> reads, auto_vec<tree> writes) :
    bb (bb), pbb (nullptr), data_refs (drs),
    read_scalar_refs (reads),
    write_scalar_refs (writes) {}

Where its also completely clear the intention is to move the vectors,
but the compiler doesn't figure that out, and so I'd say its very useful
for people who aren't being watchful at every moment, that this simply
fails to compile, rather than generating horribly inefficient code.

Of course that is before we even start talking about cases where one
needs to understand the algorithm or think about more than one scope at
a time to realize the copy can be avoided, possibly by reorganizing
other code.

> More generally, obviating the distinction between native types
> and user-defined types is one of the most powerful features of
> C++.  It makes it possible to write generic code: not just
> templates but any piece of code that's agnostic of the types
> it works with.  There are many benefits: code that uses common
> idioms and operators is easier to understand, swapping one data
> type for another becomes trivial, and similarities between
> different pieces of code are more apparent, opening up
> opportunities for reuse and refactoring.  Designing classes
> to be gratuitously different means missing out on some of
> the most valuable benefits of using the language.  But I'm
> just paraphrasing arguments that have been made much more
> convincingly by authors of the many excellent C++ books out
> there (some of my favorites are Herb Sutter's Exceptional C++
> series).

Its certainly powerful, but with great power comes great responsibility,
and its certainly a double edged sword, that should be used with care.
While its certainly theoretically nice for everything to be uniform, and
it sometimes has benefits, an int and a hash table with millions of
elements are pretty different things and different operations make sense
for them.  Coppying one is pretty harmless, the other should involve
a serious search for alternatives, if performance is a concern.  So
while I can understand that legacy constrains the standard library to
just have one copy operation for everything, especially after C++11 I
think that is a mistake that should be avoided in the future.

Trev

> 
> Martin

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2021-06-28  7:01 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-15  5:59 [PATCH 1/6] auto_vec copy/move improvements Trevor Saunders
2021-06-15  5:59 ` [PATCH 2/6] return auto_vec from cgraph_node::collect_callers Trevor Saunders
2021-06-15  6:45   ` Richard Biener
2021-06-15  5:59 ` [PATCH 3/6] return auto_vec from get_loop_hot_path Trevor Saunders
2021-06-15  6:45   ` Richard Biener
2021-06-17 13:48     ` Christophe Lyon
2021-06-17 14:41       ` Trevor Saunders
2021-06-17 18:34         ` Christophe Lyon
2021-06-15  5:59 ` [PATCH 4/6] return auto_vec from get_dominated_by Trevor Saunders
2021-06-15  6:46   ` Richard Biener
2021-06-15 11:18     ` Bernhard Reutner-Fischer
2021-06-16  3:09       ` Trevor Saunders
2021-06-16  5:45         ` Bernhard Reutner-Fischer
2021-06-17  6:56           ` Trevor Saunders
2021-06-15  5:59 ` [PATCH 5/6] make get_domminated_by_region return a auto_vec Trevor Saunders
2021-06-15  6:49   ` Richard Biener
2021-06-16 12:46     ` Richard Sandiford
2021-06-16 16:01       ` Martin Sebor
2021-06-17  6:03         ` Richard Biener
2021-06-17  8:23           ` Trevor Saunders
2021-06-17 14:43           ` Martin Sebor
2021-06-18 10:38             ` Richard Biener
2021-06-18 10:53               ` Jakub Jelinek
2021-06-18 11:03                 ` Jonathan Wakely
2021-06-18 11:04                   ` Jonathan Wakely
2021-06-18 16:03               ` Martin Sebor
2021-06-21  7:15                 ` Richard Biener
2021-06-22 20:01                   ` Martin Sebor
2021-06-23  5:23                     ` Trevor Saunders
2021-06-23  7:43                       ` Richard Biener
2021-06-23 10:22                         ` Richard Sandiford
2021-06-24  9:20                           ` Richard Biener
2021-06-24 16:28                             ` Richard Sandiford
2021-06-25  8:29                               ` Richard Biener
2021-06-23 22:56                         ` Martin Sebor
2021-06-24  9:27                           ` Richard Biener
2021-06-24 15:01                             ` Martin Sebor
2021-06-23 23:43                       ` Martin Sebor
2021-06-28  7:01                         ` Trevor Saunders
2021-06-15  5:59 ` [PATCH 6/6] return auto_vec from more dominance functions Trevor Saunders
2021-06-15  6:50   ` Richard Biener
2021-06-15  6:42 ` [PATCH 1/6] auto_vec copy/move improvements Richard Biener
2021-06-15  7:04   ` Trevor Saunders
2021-06-15  7:11     ` Richard Biener
2021-06-15  7:57       ` Trevor Saunders
2021-06-15  9:36         ` Richard Biener
2021-06-16  3:17           ` [PATCH, V2] " Trevor Saunders
2021-06-16 10:13             ` Richard Biener
2021-06-16 17:01               ` Martin Sebor
2021-06-15 16:18 ` [PATCH 1/6] " Martin Sebor
2021-06-16  3:31   ` Trevor Saunders

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).