From 4cf02b5d4a649b9fe621e3ef855021389663222d Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 6 May 2020 15:36:38 -0400 Subject: [PATCH] pan/mdg: Optimize pipelining logic The test and rewrite were both accidentally O(N) to the shader size when they should be O(1), so overall this takes the pass from O(N^2) to O(N). Signed-off-by: Alyssa Rosenzweig Part-of: --- src/panfrost/midgard/compiler.h | 1 - src/panfrost/midgard/midgard_ra_pipeline.c | 42 +++++++++++++++------- src/panfrost/midgard/mir.c | 19 ---------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/panfrost/midgard/compiler.h b/src/panfrost/midgard/compiler.h index 67d56035a8b..618c0d79265 100644 --- a/src/panfrost/midgard/compiler.h +++ b/src/panfrost/midgard/compiler.h @@ -483,7 +483,6 @@ void mir_rewrite_index_src_swizzle(compiler_context *ctx, unsigned old, unsigned bool mir_single_use(compiler_context *ctx, unsigned value); bool mir_special_index(compiler_context *ctx, unsigned idx); unsigned mir_use_count(compiler_context *ctx, unsigned value); -bool mir_is_written_before(compiler_context *ctx, midgard_instruction *ins, unsigned node); uint16_t mir_bytemask_of_read_components(midgard_instruction *ins, unsigned node); uint16_t mir_bytemask_of_read_components_index(midgard_instruction *ins, unsigned i); midgard_reg_mode mir_typesize(midgard_instruction *ins); diff --git a/src/panfrost/midgard/midgard_ra_pipeline.c b/src/panfrost/midgard/midgard_ra_pipeline.c index 48f45cb9adb..1037d0645d9 100644 --- a/src/panfrost/midgard/midgard_ra_pipeline.c +++ b/src/panfrost/midgard/midgard_ra_pipeline.c @@ -47,18 +47,30 @@ mir_pipeline_ins( { midgard_instruction *ins = bundle->instructions[i]; - /* We could be pipelining a register, so we need to make sure that all - * of the components read in this bundle are written in this bundle, - * and that no components are written before this bundle */ + /* Our goal is to create a pipeline register. Pipeline registers are + * created at the start of the bundle and are destroyed at the end. So + * we conservatively require: + * + * 1. Each component read in the second stage is written in the first stage. + * 2. The index is not live after the bundle. + * 3. We're not a special index (writeout, conditionals, ..) + * + * Rationale: #1 ensures that there is no need to go before the + * creation of the bundle, so the pipeline register can exist. #2 is + * since the pipeline register will be destroyed at the end. This + * ensures that nothing will try to read/write the pipeline register + * once it is not live, and that there's no need to go earlier. */ unsigned node = ins->dest; unsigned read_mask = 0; + if (node >= SSA_FIXED_MINIMUM) + return false; + /* Analyze the bundle for a per-byte read mask */ for (unsigned j = 0; j < bundle->instruction_count; ++j) { midgard_instruction *q = bundle->instructions[j]; - read_mask |= mir_bytemask_of_read_components(q, node); /* The fragment colour can't be pipelined (well, it is * pipelined in r0, but this is a delicate dance with @@ -66,11 +78,15 @@ mir_pipeline_ins( if (q->compact_branch && q->writeout && mir_has_arg(q, node)) return false; + + if (q->unit < UNIT_VADD) continue; + read_mask |= mir_bytemask_of_read_components(q, node); } - /* Now analyze for a write mask */ + /* Now check what's written in the beginning stage */ for (unsigned j = 0; j < bundle->instruction_count; ++j) { midgard_instruction *q = bundle->instructions[j]; + if (q->unit >= UNIT_VADD) break; if (q->dest != node) continue; /* Remove the written mask from the read requirements */ @@ -81,12 +97,6 @@ mir_pipeline_ins( if (read_mask) return false; - /* Now, check outside the bundle */ - midgard_instruction *start = bundle->instructions[0]; - - if (mir_is_written_before(ctx, start, node)) - return false; - /* We want to know if we live after this bundle, so check if * we're live after the last instruction of the bundle */ @@ -97,8 +107,16 @@ mir_pipeline_ins( return false; /* We're only live in this bundle -- pipeline! */ + unsigned preg = SSA_FIXED_REGISTER(24 + pipeline_count); + + for (unsigned j = 0; j < bundle->instruction_count; ++j) { + midgard_instruction *q = bundle->instructions[j]; - mir_rewrite_index(ctx, node, SSA_FIXED_REGISTER(24 + pipeline_count)); + if (q->unit >= UNIT_VADD) + mir_rewrite_index_src_single(q, node, preg); + else + mir_rewrite_index_dst_single(q, node, preg); + } return true; } diff --git a/src/panfrost/midgard/mir.c b/src/panfrost/midgard/mir.c index 7dc357e62ac..68f6286c590 100644 --- a/src/panfrost/midgard/mir.c +++ b/src/panfrost/midgard/mir.c @@ -197,25 +197,6 @@ mir_special_index(compiler_context *ctx, unsigned idx) return false; } -/* Is a node written before a given instruction? */ - -bool -mir_is_written_before(compiler_context *ctx, midgard_instruction *ins, unsigned node) -{ - if (node >= SSA_FIXED_MINIMUM) - return true; - - mir_foreach_instr_global(ctx, q) { - if (q == ins) - break; - - if (q->dest == node) - return true; - } - - return false; -} - /* Grabs the type size. */ midgard_reg_mode -- 2.30.2