if (ins->type == BI_BRANCH) {
                 if (ins->branch.target)
-                        fprintf(fp, "-> block%u", ins->branch.target->name);
+                        fprintf(fp, "-> block%u", ins->branch.target->base.name);
                 else
                         fprintf(fp, "-> blockhole");
         }
 void
 bi_print_block(bi_block *block, FILE *fp)
 {
-        fprintf(fp, "block%u {\n", block->name);
+        fprintf(fp, "block%u {\n", block->base.name);
 
         if (block->scheduled) {
                 bi_foreach_clause_in_block(block, clause)
 
         fprintf(fp, "}");
 
-        if (block->successors[0]) {
+        if (block->base.successors[0]) {
                 fprintf(fp, " -> ");
 
-                for (unsigned i = 0; i < ARRAY_SIZE(block->successors); ++i) {
-                        if (block->successors[i])
-                                fprintf(fp, "block%u ", block->successors[i]->name);
-                }
+                pan_foreach_successor((&block->base), succ)
+                        fprintf(fp, "block%u ", succ->name);
         }
 
-        if (block->predecessors->entries) {
+        if (block->base.predecessors->entries) {
                 fprintf(fp, " from");
 
                 bi_foreach_predecessor(block, pred)
-                        fprintf(fp, " block%u", pred->name);
+                        fprintf(fp, " block%u", pred->base.name);
         }
 
         fprintf(fp, "\n\n");
 bi_print_shader(bi_context *ctx, FILE *fp)
 {
         bi_foreach_block(ctx, block)
-                bi_print_block(block, fp);
+                bi_print_block((bi_block *) block, fp);
 }
 
         bool is_first = true;
 
         bi_foreach_block(ctx, block) {
-                list_inithead(&block->clauses);
+                bi_block *bblock = (bi_block *) block;
 
-                bi_foreach_instr_in_block(block, ins) {
+                list_inithead(&bblock->clauses);
+
+                bi_foreach_instr_in_block(bblock, ins) {
                         unsigned props = bi_class_props[ins->type];
 
                         bi_clause *u = rzalloc(ctx, bi_clause);
                         u->constant_count = 1;
                         u->constants[0] = ins->constant.u64;
 
-                        list_addtail(&u->link, &block->clauses);
+                        list_addtail(&u->link, &bblock->clauses);
                 }
 
-                block->scheduled = true;
+                bblock->scheduled = true;
         }
 }
 
 
 static bi_block *emit_cf_list(bi_context *ctx, struct exec_list *list);
 static bi_instruction *bi_emit_branch(bi_context *ctx);
-static void bi_block_add_successor(bi_block *block, bi_block *successor);
 static void bi_schedule_barrier(bi_context *ctx);
 
 static void
                 unreachable("Unhandled jump type");
         }
 
-        bi_block_add_successor(ctx->current_block, branch->branch.target);
+        pan_block_add_successor(&ctx->current_block->base, &branch->branch.target->base);
 }
 
 /* Gets a bytemask for a complete vecN write */
 {
         bi_block *blk = rzalloc(ctx, bi_block);
 
-        blk->predecessors = _mesa_set_create(blk,
+        blk->base.predecessors = _mesa_set_create(blk,
                         _mesa_hash_pointer,
                         _mesa_key_pointer_equal);
 
-        blk->name = ctx->block_name_count++;
+        blk->base.name = ctx->block_name_count++;
 
         return blk;
 }
 
-static void
-bi_block_add_successor(bi_block *block, bi_block *successor)
-{
-        assert(block);
-        assert(successor);
-
-        for (unsigned i = 0; i < ARRAY_SIZE(block->successors); ++i) {
-                if (block->successors[i]) {
-                       if (block->successors[i] == successor)
-                               return;
-                       else
-                               continue;
-                }
-
-                block->successors[i] = successor;
-                _mesa_set_add(successor->predecessors, block);
-                return;
-        }
-
-        unreachable("Too many successors");
-}
-
 static void
 bi_schedule_barrier(bi_context *ctx)
 {
         bi_block *temp = ctx->after_block;
         ctx->after_block = create_empty_block(ctx);
-        list_addtail(&ctx->after_block->link, &ctx->blocks);
-        list_inithead(&ctx->after_block->instructions);
-        bi_block_add_successor(ctx->current_block, ctx->after_block);
+        list_addtail(&ctx->after_block->base.link, &ctx->blocks);
+        list_inithead(&ctx->after_block->base.instructions);
+        pan_block_add_successor(&ctx->current_block->base, &ctx->after_block->base);
         ctx->current_block = ctx->after_block;
         ctx->after_block = temp;
 }
                 ctx->current_block = create_empty_block(ctx);
         }
 
-        list_addtail(&ctx->current_block->link, &ctx->blocks);
-        list_inithead(&ctx->current_block->instructions);
+        list_addtail(&ctx->current_block->base.link, &ctx->blocks);
+        list_inithead(&ctx->current_block->base.instructions);
 
         nir_foreach_instr(instr, block) {
                 emit_instr(ctx, instr);
         } else {
                 then_branch->branch.target = else_block;
                 then_exit->branch.target = ctx->after_block;
-                bi_block_add_successor(end_then_block, then_exit->branch.target);
+                pan_block_add_successor(&end_then_block->base, &then_exit->branch.target->base);
         }
 
         /* Wire up the successors */
 
-        bi_block_add_successor(before_block, then_branch->branch.target); /* then_branch */
+        pan_block_add_successor(&before_block->base, &then_branch->branch.target->base); /* then_branch */
 
-        bi_block_add_successor(before_block, then_block); /* fallthrough */
-        bi_block_add_successor(end_else_block, ctx->after_block); /* fallthrough */
+        pan_block_add_successor(&before_block->base, &then_block->base); /* fallthrough */
+        pan_block_add_successor(&end_else_block->base, &ctx->after_block->base); /* fallthrough */
 }
 
 static void
         /* Branch back to loop back */
         bi_instruction *br_back = bi_emit_branch(ctx);
         br_back->branch.target = ctx->continue_block;
-        bi_block_add_successor(start_block, ctx->continue_block);
-        bi_block_add_successor(ctx->current_block, ctx->continue_block);
+        pan_block_add_successor(&start_block->base, &ctx->continue_block->base);
+        pan_block_add_successor(&ctx->current_block->base, &ctx->continue_block->base);
 
         ctx->after_block = ctx->break_block;
 
 
 } bi_clause;
 
 typedef struct bi_block {
-        struct list_head link; /* must be first */
-        unsigned name; /* Just for pretty-printing */
+        pan_block base; /* must be first */
 
         /* If true, uses clauses; if false, uses instructions */
         bool scheduled;
-        struct list_head instructions; /* pre-schedule, list of bi_instructions */
         struct list_head clauses; /* list of bi_clause */
-
-        /* Control flow graph */
-        struct set *predecessors;
-        struct bi_block *successors[2];
 } bi_block;
 
 typedef struct {
 {
         bi_instruction *u = rzalloc(ctx, bi_instruction);
         memcpy(u, &ins, sizeof(ins));
-        list_addtail(&u->link, &ctx->current_block->instructions);
+        list_addtail(&u->link, &ctx->current_block->base.instructions);
         return u;
 }
 
 /* Iterators for Bifrost IR */
 
 #define bi_foreach_block(ctx, v) \
-        list_for_each_entry(bi_block, v, &ctx->blocks, link)
+        list_for_each_entry(pan_block, v, &ctx->blocks, link)
 
 #define bi_foreach_block_from(ctx, from, v) \
-        list_for_each_entry_from(bi_block, v, from, &ctx->blocks, link)
+        list_for_each_entry_from(pan_block, v, from, &ctx->blocks, link)
 
 #define bi_foreach_instr_in_block(block, v) \
-        list_for_each_entry(bi_instruction, v, &block->instructions, link)
+        list_for_each_entry(bi_instruction, v, &block->base.instructions, link)
 
 #define bi_foreach_instr_in_block_rev(block, v) \
-        list_for_each_entry_rev(bi_instruction, v, &block->instructions, link)
+        list_for_each_entry_rev(bi_instruction, v, &block->base.instructions, link)
 
 #define bi_foreach_instr_in_block_safe(block, v) \
-        list_for_each_entry_safe(bi_instruction, v, &block->instructions, link)
+        list_for_each_entry_safe(bi_instruction, v, &block->base.instructions, link)
 
 #define bi_foreach_instr_in_block_safe_rev(block, v) \
-        list_for_each_entry_safe_rev(bi_instruction, v, &block->instructions, link)
+        list_for_each_entry_safe_rev(bi_instruction, v, &block->base.instructions, link)
 
 #define bi_foreach_instr_in_block_from(block, v, from) \
-        list_for_each_entry_from(bi_instruction, v, from, &block->instructions, link)
+        list_for_each_entry_from(bi_instruction, v, from, &block->base.instructions, link)
 
 #define bi_foreach_instr_in_block_from_rev(block, v, from) \
-        list_for_each_entry_from_rev(bi_instruction, v, from, &block->instructions, link)
+        list_for_each_entry_from_rev(bi_instruction, v, from, &block->base.instructions, link)
 
 #define bi_foreach_clause_in_block(block, v) \
         list_for_each_entry(bi_clause, v, &block->clauses, link)
 
 #define bi_foreach_instr_global(ctx, v) \
         bi_foreach_block(ctx, v_block) \
-                bi_foreach_instr_in_block(v_block, v)
+                bi_foreach_instr_in_block((pan_block *) v_block, v)
 
 #define bi_foreach_instr_global_safe(ctx, v) \
         bi_foreach_block(ctx, v_block) \
-                bi_foreach_instr_in_block_safe(v_block, v)
-
-#define bi_foreach_successor(blk, v) \
-        bi_block *v; \
-        bi_block **_v; \
-        for (_v = &blk->successors[0], \
-                v = *_v; \
-                v != NULL && _v < &blk->successors[2]; \
-                _v++, v = *_v) \
+                bi_foreach_instr_in_block_safe((pan_block *) v_block, v)
 
 /* Based on set_foreach, expanded with automatic type casts */
 
 #define bi_foreach_predecessor(blk, v) \
         struct set_entry *_entry_##v; \
         bi_block *v; \
-        for (_entry_##v = _mesa_set_next_entry(blk->predecessors, NULL), \
+        for (_entry_##v = _mesa_set_next_entry(blk->base.predecessors, NULL), \
                 v = (bi_block *) (_entry_##v ? _entry_##v->key : NULL);  \
                 _entry_##v != NULL; \
-                _entry_##v = _mesa_set_next_entry(blk->predecessors, _entry_##v), \
+                _entry_##v = _mesa_set_next_entry(blk->base.predecessors, _entry_##v), \
                 v = (bi_block *) (_entry_##v ? _entry_##v->key : NULL))
 
 #define bi_foreach_src(ins, v) \
 
         mir_foreach_block(ctx, v_block) \
                 mir_foreach_instr_in_block_safe(((midgard_block *) v_block), v)
 
-#define mir_foreach_successor(blk, v) \
-        struct midgard_block *v; \
-        struct midgard_block **_v; \
-        for (_v = &blk->base.successors[0], \
-                v = *_v; \
-                v != NULL && _v < &blk->base.successors[2]; \
-                _v++, v = *_v) \
-
 /* Based on set_foreach, expanded with automatic type casts */
 
 #define mir_foreach_predecessor(blk, v) \
 
         return blk;
 }
 
-static void
-pan_block_add_successor(pan_block *block, pan_block *successor)
-{
-        assert(block);
-        assert(successor);
-
-        /* Deduplicate */
-        for (unsigned i = 0; i < block->nr_successors; ++i) {
-                if ((pan_block *) block->successors[i] == successor)
-                        return;
-        }
-
-        block->successors[block->nr_successors++] = successor;
-        assert(block->nr_successors <= ARRAY_SIZE(block->successors));
-
-        /* Note the predecessor in the other direction */
-        _mesa_set_add(successor->predecessors, block);
-}
-
 static void
 schedule_barrier(compiler_context *ctx)
 {
 
 
         printf("}");
 
-        if (block->base.nr_successors) {
+        if (block->base.successors[0]) {
                 printf(" -> ");
-                for (unsigned i = 0; i < block->base.nr_successors; ++i) {
-                        printf("block%u%s", block->base.successors[i]->name,
-                                        (i + 1) != block->base.nr_successors ? ", " : "");
-                }
+                pan_foreach_successor((&block->base), succ)
+                        printf(" block%u ", succ->name);
         }
 
         printf(" from { ");
 
                 unreachable("Invalid register mode");
         }
 }
+
+void
+pan_block_add_successor(pan_block *block, pan_block *successor)
+{
+        assert(block);
+        assert(successor);
+
+        for (unsigned i = 0; i < ARRAY_SIZE(block->successors); ++i) {
+                if (block->successors[i]) {
+                       if (block->successors[i] == successor)
+                               return;
+                       else
+                               continue;
+                }
+
+                block->successors[i] = successor;
+                _mesa_set_add(successor->predecessors, block);
+                return;
+        }
+
+        unreachable("Too many successors");
+}
 
 
         /* Control flow graph */
         struct pan_block *successors[2];
-        unsigned nr_successors;
-
         struct set *predecessors;
 
         /* In liveness analysis, these are live masks (per-component) for
 uint16_t
 pan_to_bytemask(unsigned bytes, unsigned mask);
 
+void pan_block_add_successor(pan_block *block, pan_block *successor);
+
 #endif
 
 pan_exit_block(struct list_head *blocks)
 {
         pan_block *last = list_last_entry(blocks, pan_block, link);
-        assert(last->nr_successors == 0);
+        assert(!last->successors[0] && !last->successors[1]);
         return last;
 }