summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-05-16 01:47:44 -0700
committerEric Anholt <eric@anholt.net>2009-11-06 13:16:49 -0800
commite4e312d493847e07ced026b93d2b588b8036ae02 (patch)
tree818a1506a6d37fb672b2f16f18dfb27508d543f2
parentee0a9e6e10060287747d9dd4afead3cbbb168e09 (diff)
mesa: Add an optimization path to remove use of pointless MOVs.
GLSL code such as: vec4 result = {0, 1, 0, 0}; gl_FragColor = result; emits code like: 0: MOV TEMP[0], CONST[0]; 1: MOV OUTPUT[1], TEMP[0]; and this replaces it with: 0: MOV TEMP[0], CONST[0]; 1: MOV OUTPUT[1], CONST[0]; Even when the dead code eliminator fails to clean up a now-useless MOV instruction (since it doesn't do live/dead ranges), this should at reduce dependencies.
-rw-r--r--src/mesa/shader/prog_optimize.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/src/mesa/shader/prog_optimize.c b/src/mesa/shader/prog_optimize.c
index e627715b5a..5aff16be46 100644
--- a/src/mesa/shader/prog_optimize.c
+++ b/src/mesa/shader/prog_optimize.c
@@ -38,7 +38,6 @@
static GLboolean dbg = GL_FALSE;
-
/**
* In 'prog' remove instruction[i] if removeFlags[i] == TRUE.
* \return number of instructions removed
@@ -355,6 +354,87 @@ find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index)
/**
+ * Try to remove use of extraneous MOV instructions, to free them up for dead
+ * code removal.
+ */
+static void
+_mesa_remove_extra_move_use(struct gl_program *prog)
+{
+ GLuint i;
+
+ if (dbg) {
+ _mesa_printf("Optimize: Begin remove extra move use\n");
+ _mesa_print_program(prog);
+ }
+
+ /*
+ * Look for sequences such as this:
+ * MOV tmpX, arg0;
+ * FOO tmpY, tmpX, arg1;
+ * and convert into:
+ * MOV tmpX, arg0;
+ * FOO tmpY, arg0, arg1;
+ */
+
+ for (i = 0; i < prog->NumInstructions - 1; i++) {
+ const struct prog_instruction *mov = prog->Instructions + i;
+ struct prog_instruction *inst2 = prog->Instructions + i + 1;
+ int arg;
+
+ if (mov->Opcode != OPCODE_MOV ||
+ mov->DstReg.File != PROGRAM_TEMPORARY ||
+ mov->DstReg.RelAddr ||
+ mov->DstReg.CondMask != COND_TR ||
+ mov->SaturateMode != SATURATE_OFF)
+ continue;
+
+ for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
+ int comp;
+
+ if (inst2->SrcReg[arg].File != mov->DstReg.File ||
+ inst2->SrcReg[arg].Index != mov->DstReg.Index ||
+ inst2->SrcReg[arg].RelAddr ||
+ inst2->SrcReg[arg].Abs)
+ continue;
+
+ /* Check that all the sources for this arg of inst2 come from inst1
+ * or constants.
+ */
+ for (comp = 0; comp < 4; comp++) {
+ int src_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
+
+ /* If the MOV didn't write that channel, can't use it. */
+ if (src_swz <= SWIZZLE_W &&
+ (mov->DstReg.WriteMask & (1 << src_swz)) == 0)
+ break;
+ }
+ if (comp != 4)
+ continue;
+
+ /* Adjust the swizzles of inst2 to point at MOV's source */
+ for (comp = 0; comp < 4; comp++) {
+ int inst2_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
+
+ if (inst2_swz <= SWIZZLE_W) {
+ GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
+ inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
+ inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
+ inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
+ inst2_swz) & 0x1) << comp);
+ }
+ }
+ inst2->SrcReg[arg].File = mov->SrcReg[0].File;
+ inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
+ }
+ }
+
+ if (dbg) {
+ _mesa_printf("Optimize: End remove extra move use.\n");
+ /*_mesa_print_program(prog);*/
+ }
+}
+
+/**
* Try to remove extraneous MOV instructions from the given program.
*/
static void
@@ -851,6 +931,8 @@ _mesa_reallocate_registers(struct gl_program *prog)
void
_mesa_optimize_program(GLcontext *ctx, struct gl_program *program)
{
+ _mesa_remove_extra_move_use(program);
+
if (1)
_mesa_remove_dead_code(program);