freedreno: small fix for flushing dependent batches
[mesa.git] / src / gallium / drivers / freedreno / ir3 / ir3_group.c
index d744477aad14b2f54dd819093464aa5ba4ebc6a5..fecb89ff34b827f12d6471ec5bafd9fb818da85b 100644 (file)
  * Find/group instruction neighbors:
  */
 
-/* stop condition for iteration: */
-static bool check_stop(struct ir3_instruction *instr)
-{
-       if (ir3_instr_check_mark(instr))
-               return true;
-
-       /* stay within the block.. don't try to operate across
-        * basic block boundaries or we'll have problems when
-        * dealing with multiple basic blocks:
-        */
-       if (is_meta(instr) && (instr->opc == OPC_META_INPUT))
-               return true;
-
-       return false;
-}
-
 /* bleh.. we need to do the same group_n() thing for both inputs/outputs
  * (where we have a simple instr[] array), and fanin nodes (where we have
  * an extra indirection via reg->instr).
@@ -79,14 +63,13 @@ static void arr_insert_mov_in(void *arr, int idx, struct ir3_instruction *instr)
 
        debug_assert(instr->regs_count == 1);
 
-       in = ir3_instr_create(instr->block, -1, OPC_META_INPUT);
+       in = ir3_instr_create(instr->block, OPC_META_INPUT);
        in->inout.block = instr->block;
        ir3_reg_create(in, instr->regs[0]->num, 0);
 
        /* create src reg for meta:in and fixup to now be a mov: */
        ir3_reg_create(instr, 0, IR3_REG_SSA)->instr = in;
-       instr->category = 1;
-       instr->opc = 0;
+       instr->opc = OPC_MOV;
        instr->cat1.src_type = TYPE_F32;
        instr->cat1.dst_type = TYPE_F32;
 
@@ -99,15 +82,35 @@ static struct ir3_instruction *instr_get(void *arr, int idx)
 {
        return ssa(((struct ir3_instruction *)arr)->regs[idx+1]);
 }
-static void instr_insert_mov(void *arr, int idx, struct ir3_instruction *instr)
+static void
+instr_insert_mov(void *arr, int idx, struct ir3_instruction *instr)
 {
        ((struct ir3_instruction *)arr)->regs[idx+1]->instr =
                        ir3_MOV(instr->block, instr, TYPE_F32);
 }
 static struct group_ops instr_ops = { instr_get, instr_insert_mov };
 
+/* verify that cur != instr, but cur is also not in instr's neighbor-list: */
+static bool
+in_neighbor_list(struct ir3_instruction *instr, struct ir3_instruction *cur, int pos)
+{
+       int idx = 0;
+
+       if (!instr)
+               return false;
 
-static void group_n(struct group_ops *ops, void *arr, unsigned n)
+       if (instr == cur)
+               return true;
+
+       for (instr = ir3_neighbor_first(instr); instr; instr = instr->cp.right)
+               if ((idx++ != pos) && (instr == cur))
+                       return true;
+
+       return false;
+}
+
+static void
+group_n(struct group_ops *ops, void *arr, unsigned n)
 {
        unsigned i, j;
 
@@ -130,9 +133,17 @@ restart:
                        conflict = conflicts(instr->cp.left, left) ||
                                conflicts(instr->cp.right, right);
 
+                       /* Mixing array elements and higher register classes
+                        * (ie. groups) doesn't really work out in RA.  See:
+                        *
+                        * https://trello.com/c/DqeDkeVf/156-bug-with-stk-70frag
+                        */
+                       if (instr->regs[0]->flags & IR3_REG_ARRAY)
+                               conflict = true;
+
                        /* we also can't have an instr twice in the group: */
                        for (j = i + 1; (j < n) && !conflict; j++)
-                               if (ops->get(arr, j) == instr)
+                               if (in_neighbor_list(ops->get(arr, j), instr, i))
                                        conflict = true;
 
                        if (conflict) {
@@ -170,14 +181,15 @@ restart:
        }
 }
 
-static void instr_find_neighbors(struct ir3_instruction *instr)
+static void
+instr_find_neighbors(struct ir3_instruction *instr)
 {
        struct ir3_instruction *src;
 
-       if (check_stop(instr))
+       if (ir3_instr_check_mark(instr))
                return;
 
-       if (is_meta(instr) && (instr->opc == OPC_META_FI))
+       if (instr->opc == OPC_META_FI)
                group_n(&instr_ops, instr, instr->regs_count - 1);
 
        foreach_ssa_src(src, instr)
@@ -189,7 +201,8 @@ static void instr_find_neighbors(struct ir3_instruction *instr)
  * we need to insert dummy/padding instruction for grouping, and
  * then take it back out again before anyone notices.
  */
-static void pad_and_group_input(struct ir3_instruction **input, unsigned n)
+static void
+pad_and_group_input(struct ir3_instruction **input, unsigned n)
 {
        int i, mask = 0;
        struct ir3_block *block = NULL;
@@ -214,7 +227,8 @@ static void pad_and_group_input(struct ir3_instruction **input, unsigned n)
        }
 }
 
-static void block_find_neighbors(struct ir3_block *block)
+static void
+find_neighbors(struct ir3 *ir)
 {
        unsigned i;
 
@@ -232,22 +246,29 @@ static void block_find_neighbors(struct ir3_block *block)
         * This logic won't quite cut it if we don't align smaller
         * on vec4 boundaries
         */
-       for (i = 0; i < block->ninputs; i += 4)
-               pad_and_group_input(&block->inputs[i], 4);
-       for (i = 0; i < block->noutputs; i += 4)
-               group_n(&arr_ops_out, &block->outputs[i], 4);
-
+       for (i = 0; i < ir->ninputs; i += 4)
+               pad_and_group_input(&ir->inputs[i], 4);
+       for (i = 0; i < ir->noutputs; i += 4)
+               group_n(&arr_ops_out, &ir->outputs[i], 4);
+
+       for (i = 0; i < ir->noutputs; i++) {
+               if (ir->outputs[i]) {
+                       struct ir3_instruction *instr = ir->outputs[i];
+                       instr_find_neighbors(instr);
+               }
+       }
 
-       for (i = 0; i < block->noutputs; i++) {
-               if (block->outputs[i]) {
-                       struct ir3_instruction *instr = block->outputs[i];
+       list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
+               for (i = 0; i < block->keeps_count; i++) {
+                       struct ir3_instruction *instr = block->keeps[i];
                        instr_find_neighbors(instr);
                }
        }
 }
 
-void ir3_block_group(struct ir3_block *block)
+void
+ir3_group(struct ir3 *ir)
 {
-       ir3_clear_mark(block->shader);
-       block_find_neighbors(block);
+       ir3_clear_mark(ir);
+       find_neighbors(ir);
 }