On Sat, Dec 14, 2013 at 10:19:48AM +0100, Richard Biener wrote: > Oleg Endo <oleg.e...@t-online.de> wrote: > >On Thu, 2013-12-12 at 03:13 -0500, Trevor Saunders wrote: > >> On Wed, Dec 11, 2013 at 06:47:37PM +0100, Oleg Endo wrote: > >> > On Thu, 2013-11-21 at 00:04 +0100, Steven Bosscher wrote: > >> > > Declaring the edge_iterator inside the for() is not a good > >argument > >> > > against FOR_EACH_EDGE. Of course, brownie points are up for grabs > >for > >> > > the brave soul daring enough to make edge iterators be proper C++ > >> > > iterators... ;-) > >> > >> so, as a first question why do we have a special edge iterator at > >all? it > >> seems like we could just have a vec iterator and use that removing a > >> bunch of indirection that seems pretty useless. > > > >I don't know why it's there. Looks like a remainder from the pre-C++ > >code, as the conversion is being done step by step. > > The fact that we iterate over a vector is an implementation detail that > should be hidden.
presumably then c++ifying this stuff should result in the vectors being private to basic_block with accessors that return an iterator or something? btw what is the reason for it to be an implementation detail that basic block keeps edges in a vector instead it being the api that the accessor returns a vector of edges? Trev > > Richard. > > >> > >> > So, I gave it a try -- see the attached patch. > >> > It allows edge iteration to look more like STL container iteration: > >> > > >> > for (basic_block::edge_iterator ei = bb->pred_edges ().begin (); > >> > ei != bb->pred_edges ().end (); ++ei) > >> > { > >> > basic_block pred_bb = (*ei)->src; > >> > ... > >> > } > >> > >> personally I'm not really a fan of overloading ++ / * that way, but I > >> can't speak for anyone else. I'd prefer something like > >> > >> for (vec_iterator i = vec.forward_iterator (); !i.done (); i.next ()) > >> and > >> for (backward_vec_iterator i = vec.backward_iterator (); !i.done (); > >i.next ()) > >> > >> but that might break range base for loops? > > > >Right, that doesn't work with range-based for loops, since it doesn't > >follow the standard concept of iteration. For a more detailed > >explanation, see also for example > >http://www.codesynthesis.com/~boris/blog/2012/05/16/cxx11-range-based-for-loop/ > > > >BTW, if you look at the patch, I haven't overloaded any ++ operators: > > > >Index: gcc/vec.h > >=================================================================== > >--- gcc/vec.h (revision 205866) > >+++ gcc/vec.h (working copy) > >@@ -482,6 +482,15 @@ > > void quick_grow (unsigned len); > > void quick_grow_cleared (unsigned len); > > > >+ /* STL like iterator interface. */ > >+ typedef T* iterator; > >+ typedef const T* const_iterator; > >+ > >+ iterator begin (void) { return &m_vecdata[0]; } > >+ iterator end (void) { return &m_vecdata[m_vecpfx.m_num]; } > >+ const_iterator begin (void) const { return &m_vecdata[0]; } > >+ const_iterator end (void) const { &m_vecdata[m_vecpfx.m_num]; } > > > >This is because raw pointers can be used as random access iterators. > > > > > >> > Then the > >> > typedef struct basic_block_def* basic_block; > >> > > >> > is replaced with a wrapper class 'basic_block', which is just a > >simple > >> > POD wrapper around a basic_block_def*. There should be no > >penalties > >> > compared to passing/storing raw pointers. Because of the union > >with > >> > constructor restriction of C++98 an additional wrapper class > >> > 'basic_block_in_union' is required, which doesn't have any > >constructors > >> > defined. > >> > > >> > Having 'basic_block' as a class allows putting typedefs for the > >edge > >> > iterator types in there (initially I tried putting the typedefs > >into > >> > struct basic_block_def, but gengtype would bail out). > >> > >> namespacing like that seems a little messy, but so is vec_iterator or > >> such I guess. > > > >I'm not sure which part of the namespacing you're referring to exactly. > >The basic_block::edge_iterator thing? Usually the iterator type is > >defined in the container type. In this case it would be vec<edge, > >va_gc>. The choice of the container type for storing edges is done in > >basic_block_def. Thus, ideally the iterator type should be obtained > >from the basic_block_def class somehow. A more bureaucratic way would > >be to have a typedef inside basic_block_def (which is not possible > >because of gengtype as mentioned before, so let's assume it's in > >basic_block)... > > > >class basic_block > >{ > >public: > > typedef vec<edge, va_gc> edge_container; > > > > edge_container& pred_edges (void); > > edge_container& succ_edges (void); > > > >... > >}; > > > >and then access the iterator via > >for (basic_block::edge_container::iterator i = bb->bb->pred_edges > >().begin (); ...) > > > >Having to type out iterator types is a well known annoyance of C++98. > >Of course it's shorter to write > >for (edge_iterator i = ...) > > > >but that means, that there can be only one type of edge container ever. > > > > > >> > It would also be possible to have a free standing definition / > >typedef > >> > of edge_iterator, but it would conflict with the existing one and > >> > require too many changes at once. Moreover, the iterator type > >actually > >> > >> I bet it'll be a lot of work but changing everything seems nice so > >maybe > >> its worth just sitting down for a couple days and banging it out if > >it > >> gives nicer names? > > > >Nicer names than "edge_iterator" you mean? I can't think of any at the > >moment... > > > >> > >> > depends on the container type, which is vec<edge, ...>, and the > >> > container type is defined/selected by the basic_block class. > >> > >> I don't see how this is relevent > > > >I hope that the explanation above makes it somewhat clearer. > > > >> > >> > The following > >> > basic_block pred_bb = (*ei)->src; > >> > > >> > can also be written as > >> > basic_block pred_bb = ei->src; > >> > > >> > after converting the edge typedef to a wrapper of edge_def*. > >> > >> this is assuming you overload operator -> on the iterator? I'm a c++ > >guy > >> not a stl guy, but that seems pretty dubious to me. > > > >Yes, that requires overloading of "operator ->". However, in this case > >not in the iterator, but in the pointer wrapper as I've done it already > >in the patch for class basic_block (in the file basic_block2.h). This > >is common practice for pointer wrappers (see e.g. std::shared_ptr). > > > >Overloading "operator ->" is also required in iterators. See > >http://www.cplusplus.com/reference/iterator/ > >If raw pointers are used as iterators (as in my example patch), there's > >nothing to overload for those of course. > > > >> > The idea of the approach is to allow co-existence of the new > >> > edge_iterator and the old and thus be able to gradually convert > >code. > >> > The wrappers around raw pointers also helo encapsulating the > >underlying > >> > memory management issues. For example, it would be much easier to > >> > replace garbage collected objects with intrusive reference > >counting. > >> > >> I don't think there's actually a memory management issue here, > >> edge_iterator can only work if you allocate it on the stack since its > >> not marked for gty, and afaik ggc doesn't scan the stack so the > >> edge_iterator can't keep the vector alive. Now I think it would be > >nice > >> if these vectors moved out of gc memory, but I don't think this is > >> particularly helpful for that. > > > >Sorry, I think I caused a misunderstanding here. By "memory management > >issue" I just meant the way a container stores its objects, like > >whether > >it's storing pointers to garbage collected objects, smart pointers like > >shared_ptr<edge> or whatever. I didn't mean that the iterator should > >somehow influence the lifetime of the container. > > > >Cheers, > >Oleg > >