freedreno/ir3: clean up dangling false-dep's
authorRob Clark <robdclark@gmail.com>
Mon, 29 Jan 2018 20:59:55 +0000 (15:59 -0500)
committerRob Clark <robdclark@gmail.com>
Sat, 10 Feb 2018 19:54:58 +0000 (14:54 -0500)
Maybe there is a better way for this..  where it comes useful is "array"
loads, which end up as a false-dep for a later array store.

If all the uses of an array load are CP'd into their consumer, it still
leaves the dangling array load, leading to funny things like:

  mov.u32u32 r5.y, r0.y
  mov.u32u32 r5.y, r0.z

Signed-off-by: Rob Clark <robdclark@gmail.com>
src/gallium/drivers/freedreno/ir3/ir3.h
src/gallium/drivers/freedreno/ir3/ir3_cp.c

index 250d4672b6b44408548ccc35444ca995c6fe4216..776239707c771579729f89d9fa0fcde4bc9cb009 100644 (file)
@@ -360,6 +360,8 @@ struct ir3_instruction {
        /* Entry in ir3_block's instruction list: */
        struct list_head node;
 
+       int use_count;      /* currently just updated/used by cp */
+
 #ifdef DEBUG
        uint32_t serialno;
 #endif
index 11d39a4093e33a11f701c7e685e90df791195ec7..7713c645e08b1499a01fecb82de6cf3e9c355e16 100644 (file)
@@ -309,6 +309,26 @@ lower_immed(struct ir3_cp_ctx *ctx, struct ir3_register *reg, unsigned new_flags
        return reg;
 }
 
+static void
+unuse(struct ir3_instruction *instr)
+{
+       debug_assert(instr->use_count > 0);
+
+       if (--instr->use_count == 0) {
+               struct ir3_block *block = instr->block;
+
+               instr->barrier_class = 0;
+               instr->barrier_conflict = 0;
+
+               /* we don't want to remove anything in keeps (which could
+                * be things like array store's)
+                */
+               for (unsigned i = 0; i < block->keeps_count; i++) {
+                       debug_assert(block->keeps[i] != instr);
+               }
+       }
+}
+
 /**
  * Handle cp for a given src register.  This additionally handles
  * the cases of collapsing immedate/const (which replace the src
@@ -339,6 +359,8 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
 
                        instr->barrier_class |= src->barrier_class;
                        instr->barrier_conflict |= src->barrier_conflict;
+
+                       unuse(src);
                }
 
        } else if (is_same_type_mov(src) &&
@@ -558,6 +580,7 @@ instr_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr)
                        instr->regs[2] = cond->regs[2];
                        instr->barrier_class |= cond->barrier_class;
                        instr->barrier_conflict |= cond->barrier_conflict;
+                       unuse(cond);
                        break;
                default:
                        break;
@@ -573,6 +596,27 @@ ir3_cp(struct ir3 *ir, struct ir3_shader_variant *so)
                        .so = so,
        };
 
+       /* This is a bit annoying, and probably wouldn't be necessary if we
+        * tracked a reverse link from producing instruction to consumer.
+        * But we need to know when we've eliminated the last consumer of
+        * a mov, so we need to do a pass to first count consumers of a
+        * mov.
+        */
+       list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
+               list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node) {
+                       struct ir3_instruction *src;
+
+                       /* by the way, we don't acount for false-dep's, so the CP
+                        * pass should always happen before false-dep's are inserted
+                        */
+                       debug_assert(instr->deps_count == 0);
+
+                       foreach_ssa_src(src, instr) {
+                               src->use_count++;
+                       }
+               }
+       }
+
        ir3_clear_mark(ir);
 
        for (unsigned i = 0; i < ir->noutputs; i++) {