+
+ irg = get_irn_irg(irn);
+ bs = bitset_malloc(get_irg_last_idx(irg));
+ set_irn_link(irn, bs);
+}
+
+/**
+ * Increases count (stored in link field) for all operands of a node.
+ */
+static void count_user(ir_node *irn, void *env)
+{
+ int i;
+ int first;
+ (void) env;
+
+ first = is_Block(irn) ? 0 : -1;
+ for (i = get_irn_arity(irn) - 1; i >= first; --i) {
+ ir_node *op = get_irn_n(irn, i);
+ bitset_t *bs = (bitset_t*)get_irn_link(op);
+
+ if (bs)
+ bitset_set(bs, get_irn_idx(irn));
+ }
+}
+
+/**
+ * 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;