/* Number of quadwords _actually_ emitted, as determined after scheduling */
unsigned quadword_count;
- /* Successors: always one forward (the block after us), maybe
- * one backwards (for a backward branch). No need for a second
- * forward, since graph traversal would get there eventually
- * anyway */
- struct midgard_block *successors[2];
+ /* Succeeding blocks. The compiler should not necessarily rely on
+ * source-order traversal */
+ struct midgard_block *successors[4];
unsigned nr_successors;
/* The successors pointer form a graph, and in the case of
int block_count;
struct list_head blocks;
- midgard_block *initial_block;
- midgard_block *previous_source_block;
- midgard_block *final_block;
-
/* List of midgard_instructions emitted for the current block */
midgard_block *current_block;
+ /* If there is a preset after block, use this, otherwise emit_block will create one if NULL */
+ midgard_block *after_block;
+
/* The current "depth" of the loop, for disambiguating breaks/continues
* when using nested loops */
int current_loop_depth;
static void
midgard_block_add_successor(midgard_block *block, midgard_block *successor)
{
+ assert(block);
+ assert(successor);
+
+ /* Deduplicate */
+ for (unsigned i = 0; i < block->nr_successors; ++i) {
+ if (block->successors[i] == successor)
+ return;
+ }
+
block->successors[block->nr_successors++] = successor;
assert(block->nr_successors <= ARRAY_SIZE(block->successors));
}
static midgard_block *
emit_block(compiler_context *ctx, nir_block *block)
{
- midgard_block *this_block = calloc(sizeof(midgard_block), 1);
+ midgard_block *this_block = ctx->after_block;
+ ctx->after_block = NULL;
+
+ if (!this_block)
+ this_block = calloc(sizeof(midgard_block), 1);
+
list_addtail(&this_block->link, &ctx->blocks);
this_block->is_scheduled = false;
ctx->texture_index[0] = -1;
ctx->texture_index[1] = -1;
- /* Add us as a successor to the block we are following */
- if (ctx->current_block)
- midgard_block_add_successor(ctx->current_block, this_block);
-
/* Set up current block */
list_inithead(&this_block->instructions);
ctx->current_block = this_block;
}
}
- if (block == nir_start_block(ctx->func->impl))
- ctx->initial_block = this_block;
-
- if (block == nir_impl_last_block(ctx->func->impl))
- ctx->final_block = this_block;
-
/* Allow the next control flow to access us retroactively, for
* branching etc */
ctx->current_block = this_block;
- /* Document the fallthrough chain */
- ctx->previous_source_block = this_block;
-
return this_block;
}
static void
emit_if(struct compiler_context *ctx, nir_if *nif)
{
+ midgard_block *before_block = ctx->current_block;
+
/* Conditional branches expect the condition in r31.w; emit a move for
* that in the _previous_ block (which is the current block). */
emit_condition(ctx, &nif->condition, true, COMPONENT_X);
EMIT(branch, true, true);
midgard_instruction *then_branch = mir_last_in_block(ctx->current_block);
- /* Emit the two subblocks */
+ /* Emit the two subblocks. */
midgard_block *then_block = emit_cf_list(ctx, &nif->then_list);
+ midgard_block *end_then_block = ctx->current_block;
/* Emit a jump from the end of the then block to the end of the else */
EMIT(branch, false, false);
int else_idx = ctx->block_count;
int count_in = ctx->instruction_count;
midgard_block *else_block = emit_cf_list(ctx, &nif->else_list);
+ midgard_block *end_else_block = ctx->current_block;
int after_else_idx = ctx->block_count;
/* Now that we have the subblocks emitted, fix up the branches */
then_branch->branch.target_block = else_idx;
then_exit->branch.target_block = after_else_idx;
}
+
+ /* Wire up the successors */
+
+ ctx->after_block = calloc(sizeof(midgard_block), 1);
+
+ midgard_block_add_successor(before_block, then_block);
+ midgard_block_add_successor(before_block, else_block);
+
+ midgard_block_add_successor(end_then_block, ctx->after_block);
+ midgard_block_add_successor(end_else_block, ctx->after_block);
}
static void
int start_idx = ctx->block_count;
/* Emit the body itself */
- emit_cf_list(ctx, &nloop->body);
+ midgard_block *loop_block = emit_cf_list(ctx, &nloop->body);
/* Branch back to loop back */
struct midgard_instruction br_back = v_branch(false, false);
br_back.branch.target_block = start_idx;
emit_mir_instruction(ctx, br_back);
- /* Mark down that branch in the graph. Note that we're really branching
- * to the block *after* we started in. TODO: Why doesn't the branch
- * itself have an off-by-one then...? */
- midgard_block_add_successor(ctx->current_block, start_block->successors[0]);
+ /* Mark down that branch in the graph. */
+ midgard_block_add_successor(start_block, loop_block);
+ midgard_block_add_successor(ctx->current_block, loop_block);
/* Find the index of the block about to follow us (note: we don't add
* one; blocks are 0-indexed so we get a fencepost problem) */
/* Fix up the break statements we emitted to point to the right place,
* now that we can allocate a block number for them */
+ ctx->after_block = calloc(sizeof(midgard_block), 1);
list_for_each_entry_from(struct midgard_block, block, start_block, &ctx->blocks, link) {
mir_foreach_instr_in_block(block, ins) {
ins->branch.target_type = TARGET_GOTO;
ins->branch.target_block = break_block_idx;
+
+ midgard_block_add_successor(block, ctx->after_block);
}
}