Message ID | 20210615055922.27205-5-tbsaunde@tbsaunde.org |
---|---|
State | New |
Headers | show |
Series | [1/6] auto_vec copy/move improvements | expand |
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 >
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 >>
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 >>>
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 > >>> >
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 > > >>> > >
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 >>>>> >>
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 > >>>>> > >> >
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
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.
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.
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 >>>>>>> >>>> >>
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 > >>>>>>> > >>>> > >> >
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 >>>>>>>>> >>>>>> >>>> >>
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 > > > > > > > > > > > > > > > > > > > > > > > > > >
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.
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
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
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
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
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
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
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
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
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
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) {
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(-)