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, 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; ... } The idea is to first make class vec look more like an STL container. This would also allow iterating it with std::for_each and use C++11 range based for loop (in a few years maybe). It would also make it easier to replace vec uses with STL containers if needed and vice versa. 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). 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 depends on the container type, which is vec<edge, ...>, and the container type is defined/selected by the basic_block class. 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*. 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. 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;