+/**
+ * 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)
+{
+ build_walker *w = (build_walker*)env;
+ bitset_t *bs;
+ int list_cnt;
+ int ref_cnt;
+ int edge_cnt;
+ size_t idx;
+ const struct list_head *head;
+ const struct list_head *pos;
+ ir_graph *irg;
+
+ if (IGNORE_NODE(irn))
+ return;
+
+ bs = (bitset_t*)get_irn_link(irn);
+ list_cnt = 0;
+ ref_cnt = 0;
+ edge_cnt = _get_irn_edge_info(irn, EDGE_KIND_NORMAL)->out_count;
+ head = _get_irn_outs_head(irn, EDGE_KIND_NORMAL);
+
+ /* We can iterate safely here, list heads have already been verified. */
+ list_for_each(pos, head) {
+ ++list_cnt;
+ }
+
+ /* check all nodes that reference us and count edges that point number
+ * of ins that actually point to us */
+ irg = get_irn_irg(irn);
+ ref_cnt = 0;
+ bitset_foreach(bs, idx) {
+ int i, arity;
+ ir_node *src = get_idx_irn(irg, idx);
+
+ arity = get_irn_arity(src);
+ for (i = 0; i < arity; ++i) {
+ ir_node *in = get_irn_n(src, i);
+ if (in == irn)
+ ++ref_cnt;
+ }
+ }
+
+ if (edge_cnt != list_cnt) {
+ w->problem_found = 1;
+ ir_fprintf(stderr, "Edge Verifier: edge count is %d, but %d edge(s) 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(s), but the list contains %d edge(s)\n",
+ irn, ref_cnt, list_cnt);
+ }
+
+ bitset_free(bs);
+}
+
+/**
+ * Verifies the out edges of an irg.
+ */
+int edges_verify(ir_graph *irg)
+{
+ struct build_walker w;
+ int problem_found = 0;
+
+ /* verify normal edges only */
+ problem_found = edges_verify_kind(irg, EDGE_KIND_NORMAL);
+
+ w.kind = EDGE_KIND_NORMAL;
+ w.problem_found = 0;
+
+ /* verify counter */
+ irg_walk_anchors(irg, clear_links, count_user, &w);
+ irg_walk_anchors(irg, NULL, verify_edge_counter, &w);
+
+ return problem_found ? 1 : w.problem_found;
+}
+
+typedef struct pass_t {
+ ir_graph_pass_t pass;
+ unsigned assert_on_problem;
+} pass_t;
+
+/**
+ * Wrapper to edges_verify to be run as an ir_graph pass.
+ */
+static int edges_verify_wrapper(ir_graph *irg, void *context)
+{
+ pass_t *pass = (pass_t*)context;
+ int problems_found = edges_verify(irg);
+ /* do NOT rerun the pass if verify is ok :-) */
+ assert(problems_found && pass->assert_on_problem);
+ return 0;
+}
+
+/* Creates an ir_graph pass for edges_verify(). */
+ir_graph_pass_t *irg_verify_edges_pass(const char *name, unsigned assert_on_problem)
+{
+ pass_t *pass = XMALLOCZ(pass_t);
+
+ def_graph_pass_constructor(
+ &pass->pass, name ? name : "edges_verify", edges_verify_wrapper);
+
+ /* neither dump nor verify */
+ pass->pass.dump_irg = (DUMP_ON_IRG_FUNC)ir_prog_no_dump;
+ pass->pass.verify_irg = (RUN_ON_IRG_FUNC)ir_prog_no_verify;
+
+ pass->assert_on_problem = assert_on_problem;
+ return &pass->pass;
+}
+