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. > 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? > 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. > 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? > 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 > 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. > 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. Trev > Comments and feedback appreciated. > > Cheers, > Oleg > Index: gcc/coretypes.h > =================================================================== > --- gcc/coretypes.h (revision 205801) > +++ gcc/coretypes.h (working copy) > @@ -153,8 +153,8 @@ > typedef struct edge_def *edge; > typedef const struct edge_def *const_edge; > struct basic_block_def; > -typedef struct basic_block_def *basic_block; > -typedef const struct basic_block_def *const_basic_block; > +class basic_block; > +class const_basic_block; > > #define obstack_chunk_alloc ((void *(*) (long)) xmalloc) > #define obstack_chunk_free ((void (*) (void *)) free) > Index: gcc/tracer.c > =================================================================== > --- gcc/tracer.c (revision 205801) > +++ gcc/tracer.c (working copy) > @@ -102,7 +102,7 @@ > > /* A transaction is a single entry multiple exit region. It must be > duplicated in its entirety or not at all. */ > - g = last_stmt (CONST_CAST_BB (bb)); > + g = last_stmt (basic_block (bb)); > if (g && gimple_code (g) == GIMPLE_TRANSACTION) > return true; > > Index: gcc/emit-rtl.c > =================================================================== > --- gcc/emit-rtl.c (revision 205801) > +++ gcc/emit-rtl.c (working copy) > @@ -4446,7 +4446,7 @@ > emit_note_after (enum insn_note subtype, rtx after) > { > rtx note = make_note_raw (subtype); > - basic_block bb = BARRIER_P (after) ? NULL : BLOCK_FOR_INSN (after); > + basic_block bb = BARRIER_P (after) ? (basic_block_def*)NULL : > (basic_block_def*)BLOCK_FOR_INSN (after); > bool on_bb_boundary_p = (bb != NULL && BB_END (bb) == after); > > if (note_outside_basic_block_p (subtype, on_bb_boundary_p)) > @@ -4462,7 +4462,7 @@ > emit_note_before (enum insn_note subtype, rtx before) > { > rtx note = make_note_raw (subtype); > - basic_block bb = BARRIER_P (before) ? NULL : BLOCK_FOR_INSN (before); > + basic_block bb = BARRIER_P (before) ? (basic_block_def*)NULL : > (basic_block_def*)BLOCK_FOR_INSN (before); > bool on_bb_boundary_p = (bb != NULL && BB_HEAD (bb) == before); > > if (note_outside_basic_block_p (subtype, on_bb_boundary_p)) > Index: gcc/vec.h > =================================================================== > --- gcc/vec.h (revision 205801) > +++ 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]; } > + > /* vec class can access our internal data and functions. */ > template <typename, typename, typename> friend struct vec; > > Index: gcc/tree-cfg.c > =================================================================== > --- gcc/tree-cfg.c (revision 205801) > +++ gcc/tree-cfg.c (working copy) > @@ -7350,7 +7350,7 @@ > static bool > gimple_block_ends_with_condjump_p (const_basic_block bb) > { > - gimple stmt = last_stmt (CONST_CAST_BB (bb)); > + gimple stmt = last_stmt (basic_block (bb)); > return (stmt && gimple_code (stmt) == GIMPLE_COND); > } > > Index: gcc/tree-inline.h > =================================================================== > --- gcc/tree-inline.h (revision 205801) > +++ gcc/tree-inline.h (working copy) > @@ -117,7 +117,7 @@ > struct pointer_set_t *statements_to_fold; > > /* Entry basic block to currently copied body. */ > - basic_block entry_bb; > + basic_block_def* entry_bb; > > /* For partial function versioning, bitmap of bbs to be copied, > otherwise NULL. */ > Index: gcc/dominance.c > =================================================================== > --- gcc/dominance.c (revision 205801) > +++ gcc/dominance.c (working copy) > @@ -500,6 +500,8 @@ > TBB v, w, k, par; > basic_block en_block; > edge_iterator ei, einext; > + TBB k1; > + basic_block b; > > if (reverse) > en_block = EXIT_BLOCK_PTR_FOR_FN (cfun); > @@ -535,9 +537,6 @@ > semidominator. */ > while (!ei_end_p (ei)) > { > - TBB k1; > - basic_block b; > - > e = ei_edge (ei); > b = (reverse) ? e->dest : e->src; > einext = ei; > Index: gcc/basic-block.h > =================================================================== > --- gcc/basic-block.h (revision 205801) > +++ gcc/basic-block.h (working copy) > @@ -23,6 +23,7 @@ > #include "predict.h" > #include "vec.h" > #include "function.h" > +#include "basic-block2.h" > > /* Use gcov_type to hold basic block counters. Should be at least > 64bit. Although a counter cannot be negative, we use a signed > @@ -169,6 +170,12 @@ > vec<edge, va_gc> *preds; > vec<edge, va_gc> *succs; > > + vec<edge, va_gc>& pred_edges (void) { return *preds; } > + const vec<edge, va_gc>& pred_edges (void) const { return *preds; } > + > + vec<edge, va_gc>& succ_edges (void) { return *succs; } > + const vec<edge, va_gc>& succ_edges (void) const { return *succs; } > + > /* Auxiliary info specific to a pass. */ > PTR GTY ((skip (""))) aux; > > Index: gcc/config/sh/sh_optimize_sett_clrt.cc > =================================================================== > --- gcc/config/sh/sh_optimize_sett_clrt.cc (revision 205801) > +++ gcc/config/sh/sh_optimize_sett_clrt.cc (working copy) > @@ -390,10 +390,10 @@ > { > prev_visited_bb.push_back (bb); > > - for (edge_iterator ei = ei_start (bb->preds); !ei_end_p (ei); > - ei_next (&ei)) > + for (basic_block::edge_iterator ei = bb->pred_edges ().begin (); > + ei != bb->pred_edges ().end (); ++ei) > { > - basic_block pred_bb = ei_edge (ei)->src; > + basic_block pred_bb = (*ei)->src; > pred_bb_count += 1; > find_last_ccreg_values (BB_END (pred_bb), pred_bb, values_out, > prev_visited_bb); > Index: gcc/cfgloop.h > =================================================================== > --- gcc/cfgloop.h (revision 205801) > +++ gcc/cfgloop.h (working copy) > @@ -24,6 +24,7 @@ > #include "bitmap.h" > #include "sbitmap.h" > #include "function.h" > +#include "basic-block2.h" > > /* Structure to hold decision about unrolling/peeling. */ > enum lpt_dec > Index: gcc/dumpfile.c > =================================================================== > --- gcc/dumpfile.c (revision 205801) > +++ gcc/dumpfile.c (working copy) > @@ -25,6 +25,7 @@ > #include "tree.h" > #include "gimple-pretty-print.h" > #include "context.h" > +#include "basic-block2.h" > > /* If non-NULL, return one past-the-end of the matching SUBPART of > the WHOLE string. */ > Index: gcc/tree-ssa-strlen.c > =================================================================== > --- gcc/tree-ssa-strlen.c (revision 205801) > +++ gcc/tree-ssa-strlen.c (working copy) > @@ -2033,7 +2033,7 @@ > > bb->aux = stridx_to_strinfo; > if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ()) > - (*stridx_to_strinfo)[0] = (strinfo) bb; > + (*stridx_to_strinfo)[0] = (strinfo) bb.get (); > } > > /* Callback for walk_dominator_tree. Free strinfo vector if it is > @@ -2046,7 +2046,7 @@ > { > stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux); > if (vec_safe_length (stridx_to_strinfo) > - && (*stridx_to_strinfo)[0] == (strinfo) bb) > + && (*stridx_to_strinfo)[0] == (strinfo) bb.get ()) > { > unsigned int i; > strinfo si; > Index: gcc/rtl.h > =================================================================== > --- gcc/rtl.h (revision 205801) > +++ gcc/rtl.h (working copy) > @@ -29,6 +29,7 @@ > #include "alias.h" > #include "hashtab.h" > #include "flags.h" > +#include "basic-block2.h" > > /* Value used by some passes to "recognize" noop moves as valid > instructions. */ > @@ -193,7 +194,7 @@ > addr_diff_vec_flags rt_addr_diff_vec_flags; > struct cselib_val_struct *rt_cselib; > tree rt_tree; > - basic_block rt_bb; > + basic_block_in_union rt_bb; > mem_attrs *rt_mem; > reg_attrs *rt_reg; > struct constant_descriptor_rtx *rt_constant; > Index: gcc/df.h > =================================================================== > --- gcc/df.h (revision 205801) > +++ gcc/df.h (working copy) > @@ -392,7 +392,7 @@ > > /* Artificial refs do not have an insn, so to get the basic block, > it must be explicitly here. */ > - basic_block bb; > + basic_block_in_union bb; > }; > > > Index: gcc/ifcvt.c > =================================================================== > --- gcc/ifcvt.c (revision 205801) > +++ gcc/ifcvt.c (working copy) > @@ -65,7 +65,7 @@ > > #define IFCVT_MULTIPLE_DUMPS 1 > > -#define NULL_BLOCK ((basic_block) NULL) > +#define NULL_BLOCK (basic_block ((basic_block_def*) NULL)) > > /* True if after combine pass. */ > static bool ifcvt_after_combine;