added edge verification routines
authorChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Tue, 13 Feb 2007 18:02:33 +0000 (18:02 +0000)
committerChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Tue, 13 Feb 2007 18:02:33 +0000 (18:02 +0000)
fixed indent

[r8637]

ir/ir/iredges.c
ir/ir/iredges.h
ir/ir/iredges_t.h

index 930dab4..ca0196b 100644 (file)
@@ -97,6 +97,11 @@ static int edges_used = 0;
 
 static int edges_private_size = 0;
 
+/**
+ * If set to 1, the list heads are checked every time an edge is changed.
+ */
+static int edges_dbg = 0;
+
 int edges_register_private_data(size_t n)
 {
        int res = edges_private_size;
@@ -115,9 +120,9 @@ static int edge_cmp(const void *p1, const void *p2, size_t len)
 {
        const ir_edge_t *e1 = p1;
        const ir_edge_t *e2 = p2;
-       int res = e1->src == e2->src && e1->pos == e2->pos;
+       int             res = e1->src == e2->src && e1->pos == e2->pos;
 
-       return !res;
+       return ! res;
 }
 
 #define edge_hash(edge) (TIMES37((edge)->pos) + HASH_PTR((edge)->src))
@@ -151,12 +156,13 @@ void edges_init_graph_kind(ir_graph *irg, ir_edge_kind_t kind)
  */
 const ir_edge_t *get_irn_edge_kind(ir_graph *irg, const ir_node *src, int pos, ir_edge_kind_t kind)
 {
-       if(edges_activated_kind(irg, kind)) {
+       if (edges_activated_kind(irg, kind)) {
                irg_edge_info_t *info = _get_irg_edge_info(irg, kind);
-               ir_edge_t key;
+               ir_edge_t       key;
 
-               key.src = (ir_node *) src;
+               key.src = (ir_node *)src;
                key.pos = pos;
+
                return set_find(info->edges, &key, sizeof(key), edge_hash(&key));
        }
 
@@ -171,6 +177,39 @@ static INLINE void edge_change_cnt(ir_node *tgt, ir_edge_kind_t kind, int ofs) {
        info->out_count += ofs;
 }
 
+/**
+ * Verify the edge list of a node, ie. ensure it's a loop:
+ * head -> e_1 -> ... -> e_n -> head
+ */
+static INLINE void vrfy_list_head(ir_node *irn, ir_edge_kind_t kind) {
+       int                    err       = 0;
+       int                    num       = 0;
+       pset                   *lh_set   = pset_new_ptr(16);
+       const struct list_head *head     = _get_irn_outs_head(irn, kind);
+       const struct list_head *pos;
+
+       list_for_each(pos, head) {
+               if (pset_find_ptr(lh_set, pos)) {
+                       const ir_edge_t *edge = list_entry(pos, ir_edge_t, list);
+
+                       ir_fprintf(stderr, "EDGE Verifier: edge list broken (self loop not to head) for %+F:\n", irn);
+                       fprintf(stderr, "- at list entry %d\n", num);
+                       if (edge->invalid)
+                               fprintf(stderr, "- edge is invalid\n");
+                       if (edge->src);
+                               ir_fprintf(stderr, "- edge %+F(%d)\n", edge->src, edge->pos);
+                       err = 1;
+                       break;
+               }
+               num++;
+               pset_insert_ptr(lh_set, pos);
+       }
+
+       del_pset(lh_set);
+
+       assert(err == 0);
+}
+
 /* The edge from (src, pos) -> old_tgt is redirected to tgt */
 void edges_notify_edge_kind(ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt, ir_edge_kind_t kind, ir_graph *irg)
 {
@@ -181,11 +220,11 @@ void edges_notify_edge_kind(ir_node *src, int pos, ir_node *tgt, ir_node *old_tg
        /*
         * Only do something, if the old and new target differ.
         */
-       if(tgt != old_tgt) {
-               irg_edge_info_t *info = _get_irg_edge_info(irg, kind);
-               set *edges            = info->edges;
-               ir_edge_t *templ      = alloca(sizeof(templ[0]));
-               ir_edge_t *edge;
+       if (tgt != old_tgt) {
+               irg_edge_info_t *info  = _get_irg_edge_info(irg, kind);
+               set             *edges = info->edges;
+               ir_edge_t       *templ = alloca(sizeof(templ[0]));
+               ir_edge_t       *edge;
 
                /* Initialize the edge template to search in the set. */
                memset(templ, 0, sizeof(templ[0]));
@@ -204,12 +243,13 @@ void edges_notify_edge_kind(ir_node *src, int pos, ir_node *tgt, ir_node *old_tg
                        edge = set_find(edges, templ, sizeof(templ[0]), edge_hash(templ));
 
                        /* mark the edge invalid if it was found */
-                       if(edge) {
+                       if (edge) {
                                msg = "deleting";
                                list_del(&edge->list);
                                edge->invalid = 1;
                                edge->pos = -2;
                                edge->src = NULL;
+                               edge_change_cnt(old_tgt, kind, -1);
                        }
 
                        /* If the edge was not found issue a warning on the debug stream */
@@ -230,18 +270,12 @@ void edges_notify_edge_kind(ir_node *src, int pos, ir_node *tgt, ir_node *old_tg
                        assert(head->next && head->prev &&
                                        "target list head must have been initialized");
 
-                       /*
-                        * insert the edge, if it is not yet in the set or return
-                        * the instance in the set.
-                        */
-                       edge = set_insert(edges, templ, sizeof(templ[0]), edge_hash(templ));
-
-#ifdef DEBUG_libfirm
-                       assert(!edge->invalid && "Invalid edge encountered");
-#endif
-
                        /* If the old target is not null, the edge is moved. */
-                       if(old_tgt) {
+                       if (old_tgt) {
+                               edge = set_find(edges, templ, sizeof(templ[0]), edge_hash(templ));
+                               assert(edge && "edge to redirect not found!");
+                               assert(! edge->invalid && "Invalid edge encountered");
+
                                msg = "redirecting";
 
                                list_move(&edge->list, head);
@@ -250,12 +284,26 @@ void edges_notify_edge_kind(ir_node *src, int pos, ir_node *tgt, ir_node *old_tg
 
                        /* The old target was null, thus, the edge is newly created. */
                        else {
+                               edge = set_insert(edges, templ, sizeof(templ[0]), edge_hash(templ));
+
+                               assert(! edge->invalid && "Freshly inserted edge is invalid?!?");
+                               assert(edge->list.next == NULL && edge->list.prev == NULL &&
+                                       "New edge must not have list head initialized");
+
                                msg = "adding";
                                list_add(&edge->list, head);
                        }
 
                        edge_change_cnt(tgt, kind, +1);
                } /* else */
+
+               /* verify list heads */
+               if (edges_dbg) {
+                       if (tgt)
+                               vrfy_list_head(tgt, kind);
+                       if (old_tgt)
+                               vrfy_list_head(old_tgt, kind);
+               }
        }
 
        /* If the target and the old target are equal, nothing is done. */
@@ -268,12 +316,12 @@ void edges_notify_edge(ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt, ir
                edges_notify_edge_kind(src, pos, tgt, old_tgt, EDGE_KIND_NORMAL, irg);
        }
 
-       if(edges_activated_kind(irg, EDGE_KIND_BLOCK) && is_Block(src)) {
+       if (edges_activated_kind(irg, EDGE_KIND_BLOCK) && is_Block(src)) {
                /* do not use get_nodes_block() here, it fails when running unpinned */
                ir_node *bl_old = old_tgt ? get_irn_n(skip_Proj(old_tgt), -1) : NULL;
                ir_node *bl_tgt = NULL;
 
-               if(tgt)
+               if (tgt)
                        bl_tgt = is_Bad(tgt) ? tgt : get_irn_n(skip_Proj(tgt), -1);
 
                edges_notify_edge_kind(src, pos, bl_tgt, bl_old, EDGE_KIND_BLOCK, irg);
@@ -297,8 +345,9 @@ void edges_node_deleted_kind(ir_node *old, ir_edge_kind_t kind, ir_graph *irg)
 }
 
 struct build_walker {
-       ir_graph *irg;
+       ir_graph       *irg;
        ir_edge_kind_t kind;
+       unsigned       problem_found;
 };
 
 /**
@@ -417,8 +466,8 @@ void edges_reroute_kind(ir_node *from, ir_node *to, ir_edge_kind_t kind, ir_grap
 
 static void verify_set_presence(ir_node *irn, void *data)
 {
-       struct build_walker *w = data;
-       set *edges             = _get_irg_edge_info(w->irg, w->kind)->edges;
+       struct build_walker *w     = data;
+       set                 *edges = _get_irg_edge_info(w->irg, w->kind)->edges;
        int i, n;
 
        foreach_tgt(irn, i, n, w->kind) {
@@ -428,36 +477,45 @@ static void verify_set_presence(ir_node *irn, void *data)
                templ.pos = i;
 
                e = set_find(edges, &templ, sizeof(templ), edge_hash(&templ));
-               if(e != NULL)
+               if (e != NULL)
                        e->present = 1;
-               else
-                       DBG((dbg, LEVEL_DEFAULT, "edge %+F,%d (kind: \"%s\") is missing\n", irn, i, get_kind_str(w->kind)));
+               else {
+                       w->problem_found = 1;
+                       ir_fprintf(stderr, "Edge Verifier: edge %+F,%d (kind: \"%s\") is missing\n", irn, i, get_kind_str(w->kind));
+               }
        }
 }
 
 static void verify_list_presence(ir_node *irn, void *data)
 {
        struct build_walker *w = data;
-       const ir_edge_t *e;
+       const ir_edge_t     *e;
+
+       /* check list heads */
+       vrfy_list_head(irn, w->kind);
 
        foreach_out_edge_kind(irn, e, w->kind) {
                ir_node *tgt = get_n(e->src, e->pos, w->kind);
-               if(irn != tgt)
-                       DBG((dbg, LEVEL_DEFAULT, "edge %+F,%d (kind \"%s\") is no out edge of %+F but of %+F\n", e->src, e->pos, get_kind_str(w->kind), irn, tgt));
+               if (irn != tgt) {
+                       w->problem_found = 1;
+                       ir_fprintf(stderr, "Edge Verifier: edge %+F,%d (kind \"%s\") is no out edge of %+F but of %+F\n",
+                               e->src, e->pos, get_kind_str(w->kind), irn, tgt);
+               }
        }
 }
 
-void edges_verify_kind(ir_graph *irg, ir_edge_kind_t kind)
+int edges_verify_kind(ir_graph *irg, ir_edge_kind_t kind)
 {
        struct build_walker w;
-       set *edges = _get_irg_edge_info(irg, kind)->edges;
-       ir_edge_t *e;
+       set                 *edges = _get_irg_edge_info(irg, kind)->edges;
+       ir_edge_t           *e;
 
-       w.irg  = irg;
-       w.kind = kind;
+       w.irg           = irg;
+       w.kind          = kind;
+       w.problem_found = 0;
 
        /* Clear the present bit in all edges available. */
-       for(e = set_first(edges); e; e = set_next(edges))
+       for (e = set_first(edges); e; e = set_next(edges))
                e->present = 0;
 
        irg_walk_graph(irg, verify_set_presence, verify_list_presence, &w);
@@ -467,18 +525,109 @@ void edges_verify_kind(ir_graph *irg, ir_edge_kind_t kind)
         * These edges are superfluous and their presence in the
         * edge set is wrong.
         */
-       for(e = set_first(edges); e; e = set_next(edges)) {
-               if(!e->invalid && !e->present)
-                       DBG((dbg, LEVEL_DEFAULT, "edge %+F,%d is superfluous\n", e->src, e->pos));
+       for (e = set_first(edges); e; e = set_next(edges)) {
+               if (! e->invalid && ! e->present) {
+                       w.problem_found = 1;
+                       ir_fprintf(stderr, "Edge Verifier: edge %+F,%d is superfluous\n", e->src, e->pos);
+               }
+       }
+
+       return w.problem_found;
+}
+
+/**
+ * Clear link field of all nodes.
+ */
+static void clear_links(ir_node *irn, void *env) {
+       if (is_Block(irn))
+               return;
+
+       set_irn_link(irn, 0);
+}
+
+/**
+ * Increases count (stored in link field) for all operands of a node.
+ */
+static void count_user(ir_node *irn, void *env) {
+       int i;
+
+       for (i = get_irn_arity(irn) - 1; i >= 0; --i) {
+               ir_node *op = get_irn_n(irn, i);
+               int     cnt = (int)get_irn_link(op);
+
+               cnt++;
+               set_irn_link(op, (void *)cnt);
+       }
+}
+
+/**
+ * Verifies if collected count, number of edges in list and stored edge count are in sync.
+ */
+static void verify_edge_counter(ir_node *irn, void *env) {
+       struct build_walker    *w       = env;
+       int                    list_cnt = 0;
+       int                    ref_cnt  = (int)get_irn_link(irn);
+       int                    edge_cnt = _get_irn_edge_info(irn, EDGE_KIND_NORMAL)->out_count;
+       const struct list_head *head    = _get_irn_outs_head(irn, EDGE_KIND_NORMAL);
+       const struct list_head *pos;
+
+       if (is_Block(irn))
+               return;
+
+       /* We can iterate safely here, list heads have already been verified. */
+       list_for_each(pos, head)
+               list_cnt++;
+
+       if (edge_cnt != list_cnt) {
+               w->problem_found = 1;
+               ir_fprintf(stderr, "Edge Verifier: edge count is %d, but %d edges are recorded in list at %+F\n",
+                       edge_cnt, list_cnt, irn);
+       }
+
+       if (ref_cnt != list_cnt) {
+               w->problem_found = 1;
+               ir_fprintf(stderr, "Edge Verifier: %+F reachable by %d node, but %d edges recorded in list\n",
+                       irn, ref_cnt, list_cnt);
        }
 }
 
+/**
+ * Verifies the out edges of an irg.
+ */
+int edges_verify(ir_graph *irg) {
+       int i;
+       struct build_walker w;
+       int problem_found = 0;
+
+       /* verify all edge kinds */
+//     for (i = 0; i < EDGE_KIND_LAST; ++i) {
+//             int res = edges_verify_kind(irg, i);
+//             problem_found = problem_found ? 1 : res;
+//     }
+//     problem_found = edges_verify_kind(irg, EDGE_KIND_NORMAL);
+
+       w.irg           = irg;
+       w.kind          = EDGE_KIND_NORMAL;
+       w.problem_found = 0;
+
+       /* verify counter */
+       irg_walk_graph(irg, clear_links, count_user, NULL);
+       irg_walk_anchors(irg, clear_links, count_user, NULL);
+       irg_walk_graph(irg, NULL, verify_edge_counter, &w);
+
+       return problem_found ? 1 : w.problem_found;
+}
+
 void init_edges(void)
 {
        FIRM_DBG_REGISTER(dbg, DBG_EDGES);
        /* firm_dbg_set_mask(dbg, -1); */
 }
 
+void edges_init_dbg(int do_dbg) {
+       edges_dbg = do_dbg;
+}
+
 void edges_activate(ir_graph *irg)
 {
        edges_activate_kind(irg, EDGE_KIND_NORMAL);
index 1b49d06..7b4eb73 100644 (file)
@@ -151,6 +151,11 @@ extern void edges_deactivate_kind(ir_graph *irg, ir_edge_kind_t kind);
 
 extern void edges_reroute_kind(ir_node *old, ir_node *nw, ir_edge_kind_t kind, ir_graph *irg);
 
+/**
+ * Verifies the out edges of graph @p irg.
+ * @return 1 if a problem was found, 0 otherwise
+ */
+int edges_verify(ir_graph *irg);
 
 /************************************************************************/
 /* Begin Old Interface                                                  */
index 572c0c1..9e887a1 100644 (file)
@@ -100,7 +100,7 @@ static INLINE int _get_irn_n_edges_kind(const ir_node *irn, int kind)
                res++;
        return res;
 #else
-       return _get_irn_edge_info(irn)->out_count;
+       return _get_irn_edge_info(irn, kind)->out_count;
 #endif
 }
 
@@ -172,6 +172,11 @@ static INLINE int _get_edge_src_pos(const ir_edge_t *edge)
 */
 extern void init_edges(void);
 
+/**
+ * Set dbg information for edges.
+ */
+void edges_init_dbg(int do_dbg);
+
 void edges_invalidate_all(ir_node *irn, ir_graph *irg);
 
 #define get_irn_n_edges_kind(irn, kind)   _get_irn_n_edges_kind(irn, kind)
@@ -181,19 +186,19 @@ void edges_invalidate_all(ir_node *irn, ir_graph *irg);
 #define get_irn_out_edge_next(irn, last)  _get_irn_out_edge_next(irn, last)
 
 #ifndef get_irn_n_edges
-#define get_irn_n_edges(irn)                            _get_irn_n_edges_kind(irn, EDGE_KIND_NORMAL)
+#define get_irn_n_edges(irn)              _get_irn_n_edges_kind(irn, EDGE_KIND_NORMAL)
 #endif
 
 #ifndef get_irn_out_edge_first
-#define get_irn_out_edge_first(irn)                     _get_irn_out_edge_first_kind(irn, EDGE_KIND_NORMAL)
+#define get_irn_out_edge_first(irn)       _get_irn_out_edge_first_kind(irn, EDGE_KIND_NORMAL)
 #endif
 
 #ifndef get_block_succ_first
-#define get_block_succ_first(irn)                       _get_irn_out_edge_first_kind(irn, EDGE_KIND_BLOCK)
+#define get_block_succ_first(irn)         _get_irn_out_edge_first_kind(irn, EDGE_KIND_BLOCK)
 #endif
 
 #ifndef get_block_succ_next
-#define get_block_succ_next(irn, last)                  _get_irn_out_edge_next(irn, last)
+#define get_block_succ_next(irn, last)    _get_irn_out_edge_next(irn, last)
 #endif