vc4: Create a basic block structure and move the instructions into it.
authorEric Anholt <eric@anholt.net>
Fri, 8 Jul 2016 22:42:15 +0000 (15:42 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 12 Jul 2016 22:47:26 +0000 (15:47 -0700)
The optimization passes and scheduling aren't actually ready for multiple
blocks with control flow yet (as seen by the "cur_block" references in
them instead of iterating over blocks), but this creates the structures
necessary for converting them.

src/gallium/drivers/vc4/vc4_opt_dead_code.c
src/gallium/drivers/vc4/vc4_opt_peephole_sf.c
src/gallium/drivers/vc4/vc4_qir.c
src/gallium/drivers/vc4/vc4_qir.h
src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c
src/gallium/drivers/vc4/vc4_qir_schedule.c

index 0256159fc691870422152a026c20306a79c23e02..26fa3ed5435ffe41e8b7e77214ddca264de93a2b 100644 (file)
@@ -83,7 +83,8 @@ qir_opt_dead_code(struct vc4_compile *c)
         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 &&
index 5536f8dd204e998970399013debb94307e28f581..414a9ef1eb30e073a7a75feabc396dbbd617ca82 100644 (file)
@@ -116,7 +116,8 @@ qir_opt_peephole_sf(struct vc4_compile *c)
         /* 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.
index 5d5ba1f0e13373936872b6f85138cf57c979679a..c23b3326f82930926c5ce83885029c58faa7869f 100644 (file)
@@ -314,9 +314,12 @@ qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
 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");
+                }
         }
 }
 
@@ -379,7 +382,7 @@ qir_inst4(enum qop op, struct qreg dst,
 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. */
@@ -415,12 +418,60 @@ qir_reg_equals(struct qreg a, struct qreg b)
         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;
@@ -466,10 +517,13 @@ qir_follow_movs(struct vc4_compile *c, struct qreg reg)
 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);
@@ -523,8 +577,9 @@ void
 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);
@@ -533,7 +588,7 @@ qir_SF(struct vc4_compile *c, struct qreg src)
             !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;
 }
index 315f403e43b07c63c9fa321a5331216739c6933b..f3e65756f6432334f0a54e50286b42c4763b2bbd 100644 (file)
@@ -343,6 +343,18 @@ struct vc4_vs_key {
         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;
@@ -424,7 +436,10 @@ struct vc4_compile {
         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;
@@ -450,6 +465,11 @@ struct vc4_compile {
 
 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,
@@ -587,7 +607,8 @@ qir_##name(struct vc4_compile *c)                                        \
         *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;                                                 \
 }
@@ -719,7 +740,30 @@ qir_LOAD_IMM(struct vc4_compile *c, uint32_t val)
                                         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 */
index 9f782dfc7df3c218e981014eb30a10b6c2dccebe..7c8cbd1466602209e14f4ecd44be2ceccfb1b8a4 100644 (file)
@@ -152,7 +152,7 @@ qir_lower_uniforms(struct vc4_compile *c)
                 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);
index c86df8359de4c23993eab04801e098c86a844946..d105ff45ce61930cddd7ee3dc96260c66b32a8e0 100644 (file)
@@ -546,7 +546,7 @@ schedule_instructions(struct vc4_compile *c, struct schedule_state *state)
 
                 /* 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
@@ -597,7 +597,8 @@ qir_schedule_instructions(struct vc4_compile *c)
         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;