From d9449c5201bf12130edac60c4249261c242e46bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Ondra=C4=8Dka?= Date: Wed, 9 Mar 2022 22:41:23 +0100 Subject: [PATCH] r300: optimize single write scenarios in rc_copy_output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now we always write to a temp and than emit movs to both POS and WPOS. When the result is trivial, like: MOV temp[0], in[0] MOV output[0], temp[0] MOV output[1], temp[0] the dataflow analysis passes can take care of it, this is however one of the last optimizations we need the pass for. Additionally it fails even for some still trivial cases like: MAD temp[2], const[3], temp[0].wwww, temp[1]; MOV output[0], temp[2]; MOV output[2], temp[2]; This patch will just duplicate the output instuction when there is only a single output write. The long-term plan would be to just trust NIR, do as little in the backend as possible and optimize the remaining backend passes to not need any additional cleanups. total instructions in shared programs: 105862 -> 105427 (-0.41%) instructions in affected programs: 20527 -> 20092 (-2.12%) total temps in shared programs: 14029 -> 13991 (-0.27%) temps in affected programs: 152 -> 114 (-25.00%) Signed-off-by: Pavel Ondračka Reviewed-by: Filip Gawin Part-of: --- .../drivers/r300/compiler/radeon_compiler.c | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/gallium/drivers/r300/compiler/radeon_compiler.c b/src/gallium/drivers/r300/compiler/radeon_compiler.c index 8bf09fe4558..47801ea31ca 100644 --- a/src/gallium/drivers/r300/compiler/radeon_compiler.c +++ b/src/gallium/drivers/r300/compiler/radeon_compiler.c @@ -144,9 +144,11 @@ void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_ou unsigned tempreg = rc_find_free_temporary(c); struct rc_instruction * inst; struct rc_instruction * insert_pos = c->Program.Instructions.Prev; + struct rc_instruction * last_write_inst = NULL; unsigned branch_depth = 0; unsigned loop_depth = 0; bool emit_after_control_flow = false; + unsigned num_writes = 0; for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); @@ -164,32 +166,50 @@ void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_ou if (opcode->HasDstReg) { if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) { + num_writes++; inst->U.I.DstReg.File = RC_FILE_TEMPORARY; inst->U.I.DstReg.Index = tempreg; insert_pos = inst; + last_write_inst = inst; if (loop_depth != 0 && branch_depth != 0) emit_after_control_flow = true; } } } - inst = rc_insert_new_instruction(c, insert_pos); - inst->U.I.Opcode = RC_OPCODE_MOV; - inst->U.I.DstReg.File = RC_FILE_OUTPUT; - inst->U.I.DstReg.Index = output; + /* If there is only a single write, just duplicate the whole instruction instead. + * We can do this even when the single write was is a control flow. + */ + if (num_writes == 1) { + last_write_inst->U.I.DstReg.File = RC_FILE_OUTPUT; + last_write_inst->U.I.DstReg.Index = output; - inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; - inst->U.I.SrcReg[0].Index = tempreg; - inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + inst = rc_insert_new_instruction(c, last_write_inst); + struct rc_instruction * prev = inst->Prev; + struct rc_instruction * next = inst->Next; + memcpy(inst, last_write_inst, sizeof(struct rc_instruction)); + inst->Prev = prev; + inst->Next = next; + inst->U.I.DstReg.Index = dup_output; + } else { + inst = rc_insert_new_instruction(c, insert_pos); + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.DstReg.File = RC_FILE_OUTPUT; + inst->U.I.DstReg.Index = output; - inst = rc_insert_new_instruction(c, inst); - inst->U.I.Opcode = RC_OPCODE_MOV; - inst->U.I.DstReg.File = RC_FILE_OUTPUT; - inst->U.I.DstReg.Index = dup_output; + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = tempreg; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; - inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; - inst->U.I.SrcReg[0].Index = tempreg; - inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + inst = rc_insert_new_instruction(c, inst); + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.DstReg.File = RC_FILE_OUTPUT; + inst->U.I.DstReg.Index = dup_output; + + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = tempreg; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + } c->Program.OutputsWritten |= 1U << dup_output; }