summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2018-03-06 09:53:45 -0500
committerRob Clark <[email protected]>2018-03-31 15:11:46 -0400
commitbd2ca2bcddaf1d598dfa29a5bee661d7315e573a (patch)
treeb0e0ff4f0baaa976056e1572d0a66f31152cbe7d
parent4f783838099eec11d38a13dd021d500d812cf410 (diff)
freedreno/ir3: eliminate unused false-deps
Previously false-dependencies would get flagged as used, even if the only "use" was a false dep to (for example) prevent a load from being scheduled after a store. In addition to being pointless instructions, in some cases they can cause problems. For example, ldg (and similar instructions) depend on an immed arg getting CP'd into the instruction, but this doesn't happen if an instruction is otherwise unused. Which can result in undefined results (overwriting unintended registers). Signed-off-by: Rob Clark <[email protected]>
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3_cp.c2
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3_depth.c40
2 files changed, 31 insertions, 11 deletions
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_cp.c b/src/gallium/drivers/freedreno/ir3/ir3_cp.c
index 391e94ca44f..67a7714b9c5 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_cp.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_cp.c
@@ -607,7 +607,7 @@ ir3_cp(struct ir3 *ir, struct ir3_shader_variant *so)
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
+ /* by the way, we don't account for false-dep's, so the CP
* pass should always happen before false-dep's are inserted
*/
debug_assert(instr->deps_count == 0);
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_depth.c b/src/gallium/drivers/freedreno/ir3/ir3_depth.c
index 270d53dbed7..3ece13928f4 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_depth.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_depth.c
@@ -133,13 +133,18 @@ ir3_insert_by_depth(struct ir3_instruction *instr, struct list_head *list)
}
static void
-ir3_instr_depth(struct ir3_instruction *instr, unsigned boost)
+ir3_instr_depth(struct ir3_instruction *instr, unsigned boost, bool falsedep)
{
struct ir3_instruction *src;
/* if we've already visited this instruction, bail now: */
- if (ir3_instr_check_mark(instr))
+ if (falsedep) {
+ /* don't mark falsedep's as used, but process them normally: */
+ if (instr->flags & IR3_INSTR_MARK)
+ return;
+ } else if (ir3_instr_check_mark(instr)) {
return;
+ }
instr->depth = 0;
@@ -147,7 +152,7 @@ ir3_instr_depth(struct ir3_instruction *instr, unsigned boost)
unsigned sd;
/* visit child to compute it's depth: */
- ir3_instr_depth(src, boost);
+ ir3_instr_depth(src, boost, __is_false_dep(instr, i));
/* for array writes, no need to delay on previous write: */
if (i == 0)
@@ -165,9 +170,10 @@ ir3_instr_depth(struct ir3_instruction *instr, unsigned boost)
ir3_insert_by_depth(instr, &instr->block->instr_list);
}
-static void
+static bool
remove_unused_by_block(struct ir3_block *block)
{
+ bool progress = false;
list_for_each_entry_safe (struct ir3_instruction, instr, &block->instr_list, node) {
if (!ir3_instr_check_mark(instr)) {
if (instr->opc == OPC_END)
@@ -178,32 +184,35 @@ remove_unused_by_block(struct ir3_block *block)
instr->flags |= IR3_INSTR_UNUSED;
/* and remove from instruction list: */
list_delinit(&instr->node);
+ progress = true;
}
}
+ return progress;
}
-void
-ir3_depth(struct ir3 *ir)
+static bool
+compute_depth_and_remove_unused(struct ir3 *ir)
{
unsigned i;
+ bool progress = false;
ir3_clear_mark(ir);
for (i = 0; i < ir->noutputs; i++)
if (ir->outputs[i])
- ir3_instr_depth(ir->outputs[i], 0);
+ ir3_instr_depth(ir->outputs[i], 0, false);
list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
for (i = 0; i < block->keeps_count; i++)
- ir3_instr_depth(block->keeps[i], 0);
+ ir3_instr_depth(block->keeps[i], 0, false);
/* We also need to account for if-condition: */
if (block->condition)
- ir3_instr_depth(block->condition, 6);
+ ir3_instr_depth(block->condition, 6, false);
}
/* mark un-used instructions: */
list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
- remove_unused_by_block(block);
+ progress |= remove_unused_by_block(block);
}
/* note that we can end up with unused indirects, but we should
@@ -221,4 +230,15 @@ ir3_depth(struct ir3 *ir)
if (in && (in->flags & IR3_INSTR_UNUSED))
ir->inputs[i] = NULL;
}
+
+ return progress;
+}
+
+void
+ir3_depth(struct ir3 *ir)
+{
+ bool progress;
+ do {
+ progress = compute_depth_and_remove_unused(ir);
+ } while (progress);
}