bool progress = false;
bool *used = calloc(c->num_temps, sizeof(bool));
- list_for_each_entry_safe_rev(struct qinst, inst, &c->instructions,
+ list_for_each_entry_safe_rev(struct qinst, inst,
+ &c->cur_block->instructions,
link) {
if ((inst->dst.file == QFILE_NULL ||
(inst->dst.file == QFILE_TEMP &&
/* Walk the block from bottom to top, tracking if the SF is used, and
* removing unused or repeated ones.
*/
- list_for_each_entry_rev(struct qinst, inst, &c->instructions, link) {
+ list_for_each_entry_rev(struct qinst, inst, &c->cur_block->instructions,
+ link) {
if (inst->sf) {
if (!sf_live) {
/* Our instruction's SF isn't read, so drop it.
void
qir_dump(struct vc4_compile *c)
{
- list_for_each_entry(struct qinst, inst, &c->instructions, link) {
- qir_dump_inst(c, inst);
- fprintf(stderr, "\n");
+ qir_for_each_block(block, c) {
+ fprintf(stderr, "BLOCK %d:\n", block->index);
+ qir_for_each_inst(inst, block) {
+ qir_dump_inst(c, inst);
+ fprintf(stderr, "\n");
+ }
}
}
static void
qir_emit(struct vc4_compile *c, struct qinst *inst)
{
- list_addtail(&inst->link, &c->instructions);
+ list_addtail(&inst->link, &c->cur_block->instructions);
}
/* Updates inst to write to a new temporary, emits it, and notes the def. */
return a.file == b.file && a.index == b.index && a.pack == b.pack;
}
+struct qblock *
+qir_new_block(struct vc4_compile *c)
+{
+ struct qblock *block = rzalloc(c, struct qblock);
+
+ list_inithead(&block->instructions);
+
+ block->predecessors = _mesa_set_create(block,
+ _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
+ block->index = c->next_block_index++;
+
+ return block;
+}
+
+void
+qir_set_emit_block(struct vc4_compile *c, struct qblock *block)
+{
+ c->cur_block = block;
+ list_addtail(&block->link, &c->blocks);
+}
+
+struct qblock *
+qir_entry_block(struct vc4_compile *c)
+{
+ return list_first_entry(&c->blocks, struct qblock, link);
+}
+
+struct qblock *
+qir_exit_block(struct vc4_compile *c)
+{
+ return list_last_entry(&c->blocks, struct qblock, link);
+}
+
+void
+qir_link_blocks(struct qblock *predecessor, struct qblock *successor)
+{
+ _mesa_set_add(successor->predecessors, predecessor);
+ if (predecessor->successors[0]) {
+ assert(!predecessor->successors[1]);
+ predecessor->successors[1] = successor;
+ } else {
+ predecessor->successors[0] = successor;
+ }
+}
+
struct vc4_compile *
qir_compile_init(void)
{
struct vc4_compile *c = rzalloc(NULL, struct vc4_compile);
- list_inithead(&c->instructions);
+ list_inithead(&c->blocks);
+ qir_set_emit_block(c, qir_new_block(c));
c->output_position_index = -1;
c->output_color_index = -1;
void
qir_compile_destroy(struct vc4_compile *c)
{
- while (!list_empty(&c->instructions)) {
- struct qinst *qinst =
- (struct qinst *)c->instructions.next;
- qir_remove_instruction(c, qinst);
+ qir_for_each_block(block, c) {
+ while (!list_empty(&block->instructions)) {
+ struct qinst *qinst =
+ list_first_entry(&block->instructions,
+ struct qinst, link);
+ qir_remove_instruction(c, qinst);
+ }
}
ralloc_free(c);
qir_SF(struct vc4_compile *c, struct qreg src)
{
struct qinst *last_inst = NULL;
- if (!list_empty(&c->instructions))
- last_inst = (struct qinst *)c->instructions.prev;
+
+ if (!list_empty(&c->cur_block->instructions))
+ last_inst = (struct qinst *)c->cur_block->instructions.prev;
/* We don't have any way to guess which kind of MOV is implied. */
assert(!src.pack);
!c->defs[src.index] ||
last_inst != c->defs[src.index]) {
last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src);
- last_inst = (struct qinst *)c->instructions.prev;
+ last_inst = (struct qinst *)c->cur_block->instructions.prev;
}
last_inst->sf = true;
}
bool clamp_color;
};
+/** A basic block of QIR intructions. */
+struct qblock {
+ struct list_head link;
+
+ struct list_head instructions;
+
+ struct set *predecessors;
+ struct qblock *successors[2];
+
+ int index;
+};
+
struct vc4_compile {
struct vc4_context *vc4;
nir_shader *s;
struct qreg undef;
enum qstage stage;
uint32_t num_temps;
- struct list_head instructions;
+
+ struct list_head blocks;
+ int next_block_index;
+ struct qblock *cur_block;
struct list_head qpu_inst_list;
uint64_t *qpu_insts;
struct vc4_compile *qir_compile_init(void);
void qir_compile_destroy(struct vc4_compile *c);
+struct qblock *qir_new_block(struct vc4_compile *c);
+void qir_set_emit_block(struct vc4_compile *c, struct qblock *block);
+void qir_link_blocks(struct qblock *predecessor, struct qblock *successor);
+struct qblock *qir_entry_block(struct vc4_compile *c);
+struct qblock *qir_exit_block(struct vc4_compile *c);
struct qinst *qir_inst(enum qop op, struct qreg dst,
struct qreg src0, struct qreg src1);
struct qinst *qir_inst4(enum qop op, struct qreg dst,
*payload = qir_get_temp(c); \
struct qinst *inst = qir_inst(QOP_##name, *payload, \
c->undef, c->undef); \
- list_add(&inst->link, &c->instructions); \
+ struct qblock *entry = qir_entry_block(c); \
+ list_add(&inst->link, &entry->instructions); \
c->defs[payload->index] = inst; \
return *payload; \
}
qir_reg(QFILE_LOAD_IMM, val), c->undef));
}
+#define qir_for_each_block(block, c) \
+ list_for_each_entry(struct qblock, block, &c->blocks, link)
+
+#define qir_for_each_block_rev(block, c) \
+ list_for_each_entry_rev(struct qblock, block, &c->blocks, link)
+
+/* Loop over the non-NULL members of the successors array. */
+#define qir_for_each_successor(succ, block) \
+ for (struct qblock *succ = block->successors[0]; \
+ succ != NULL; \
+ succ = (succ == block->successors[1] ? NULL : \
+ block->successors[1]))
+
+#define qir_for_each_inst(inst, block) \
+ list_for_each_entry(struct qinst, inst, &block->instructions, link)
+
+#define qir_for_each_inst_rev(inst, block) \
+ list_for_each_entry_rev(struct qinst, inst, &block->instructions, link)
+
+#define qir_for_each_inst_safe(inst, block) \
+ list_for_each_entry_safe(struct qinst, inst, &block->instructions, link)
+
#define qir_for_each_inst_inorder(inst, c) \
- list_for_each_entry(struct qinst, inst, &c->instructions, link)
+ qir_for_each_block(_block, c) \
+ qir_for_each_inst(inst, _block)
#endif /* VC4_QIR_H */
struct qreg temp = qir_get_temp(c);
struct qreg unif = qir_reg(QFILE_UNIF, max_index);
struct qinst *mov = qir_inst(QOP_MOV, temp, unif, c->undef);
- list_add(&mov->link, &c->instructions);
+ list_add(&mov->link, &c->cur_block->instructions);
c->defs[temp.index] = mov;
qir_for_each_inst_inorder(inst, c) {
uint32_t nsrc = qir_get_op_nsrc(inst->op);
/* Schedule this instruction back onto the QIR list. */
list_del(&chosen->link);
- list_add(&inst->link, &c->instructions);
+ list_add(&inst->link, &c->cur_block->instructions);
/* Now that we've scheduled a new instruction, some of its
* children can be promoted to the list of instructions ready to
list_inithead(&state.worklist);
/* Wrap each instruction in a scheduler structure. */
- list_for_each_entry_safe(struct qinst, inst, &c->instructions, link) {
+ list_for_each_entry_safe(struct qinst, inst,
+ &c->cur_block->instructions, link) {
struct schedule_node *n = rzalloc(mem_ctx, struct schedule_node);
n->inst = inst;