mesa: Fix up the remove_dead_code pass to operate on a channel basis.
authorEric Anholt <eric@anholt.net>
Fri, 12 Jun 2009 19:37:25 +0000 (12:37 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 6 Nov 2009 21:16:49 +0000 (13:16 -0800)
This cleans up a bunch of instructions in GLSL programs to have limited
writemasks, which would translate to wins in shaders that hit the i965
brw_wm_glsl.c path by depending less on in-driver optimizations.  It will
also help hit other optimization passes I'm looking at.

src/mesa/shader/prog_optimize.c

index 9d937488e37250a9b883d16b77e9e28fdbb99566..e627715b5a6c06b03fb17df16d45a448a6ac86f7 100644 (file)
@@ -187,11 +187,10 @@ _mesa_consolidate_registers(struct gl_program *prog)
 static void
 _mesa_remove_dead_code(struct gl_program *prog)
 {
-   GLboolean tempWritten[MAX_PROGRAM_TEMPS], tempRead[MAX_PROGRAM_TEMPS];
+   GLboolean tempRead[MAX_PROGRAM_TEMPS][4];
    GLboolean *removeInst; /* per-instruction removal flag */
-   GLuint i, rem;
+   GLuint i, rem = 0, comp;
 
-   memset(tempWritten, 0, sizeof(tempWritten));
    memset(tempRead, 0, sizeof(tempRead));
 
    if (dbg) {
@@ -217,11 +216,27 @@ _mesa_remove_dead_code(struct gl_program *prog)
             if (inst->SrcReg[j].RelAddr) {
                if (dbg)
                   _mesa_printf("abort remove dead code (indirect temp)\n");
-               _mesa_free(removeInst);
-               return;
+               goto done;
             }
 
-            tempRead[index] = GL_TRUE;
+           for (comp = 0; comp < 4; comp++) {
+              GLuint swz = (inst->SrcReg[j].Swizzle >> (3 * comp)) & 0x7;
+
+              switch (swz) {
+              case SWIZZLE_X:
+                 tempRead[index][0] = GL_TRUE;
+                 break;
+              case SWIZZLE_Y:
+                 tempRead[index][1] = GL_TRUE;
+                 break;
+              case SWIZZLE_Z:
+                 tempRead[index][2] = GL_TRUE;
+                 break;
+              case SWIZZLE_W:
+                 tempRead[index][3] = GL_TRUE;
+                 break;
+              }
+           }
          }
       }
 
@@ -233,50 +248,63 @@ _mesa_remove_dead_code(struct gl_program *prog)
          if (inst->DstReg.RelAddr) {
             if (dbg)
                _mesa_printf("abort remove dead code (indirect temp)\n");
-            _mesa_free(removeInst);
-            return;
+            goto done;
          }
 
-         tempWritten[index] = GL_TRUE;
          if (inst->CondUpdate) {
             /* If we're writing to this register and setting condition
              * codes we cannot remove the instruction.  Prevent removal
              * by setting the 'read' flag.
              */
-            tempRead[index] = GL_TRUE;
+            tempRead[index][0] = GL_TRUE;
+            tempRead[index][1] = GL_TRUE;
+            tempRead[index][2] = GL_TRUE;
+            tempRead[index][3] = GL_TRUE;
          }
       }
    }
 
-   if (dbg) {
-      for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
-         if (tempWritten[i] && !tempRead[i])
-            _mesa_printf("Remove writes to tmp %u\n", i);
-      }
-   }
-
    /* find instructions that write to dead registers, flag for removal */
    for (i = 0; i < prog->NumInstructions; i++) {
-      const struct prog_instruction *inst = prog->Instructions + i;
-      if (inst->DstReg.File == PROGRAM_TEMPORARY) {
-         GLint index = inst->DstReg.Index;
-         removeInst[i] = (tempWritten[index] && !tempRead[index]);
-         if (dbg && removeInst[i]) {
-            _mesa_printf("Remove inst %u: ", i);
-            _mesa_print_instruction(inst);
-         }
+      struct prog_instruction *inst = prog->Instructions + i;
+      const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode);
+
+      if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) {
+         GLint chan, index = inst->DstReg.Index;
+
+        for (chan = 0; chan < 4; chan++) {
+           if (!tempRead[index][chan] &&
+               inst->DstReg.WriteMask & (1 << chan)) {
+              if (dbg) {
+                 _mesa_printf("Remove writemask on %u.%c\n", i,
+                              chan == 3 ? 'w' : 'x' + chan);
+              }
+              inst->DstReg.WriteMask &= ~(1 << chan);
+              rem++;
+           }
+        }
+
+        if (inst->DstReg.WriteMask == 0) {
+           /* If we cleared all writes, the instruction can be removed. */
+           if (dbg)
+              _mesa_printf("Remove instruction %u: \n", i);
+           removeInst[i] = GL_TRUE;
+        }
       }
    }
 
    /* now remove the instructions which aren't needed */
    rem = remove_instructions(prog, removeInst);
 
-   _mesa_free(removeInst);
-
    if (dbg) {
-      _mesa_printf("Optimize: End dead code removal.  %u instructions removed\n", rem);
+      _mesa_printf("Optimize: End dead code removal.\n");
+      _mesa_printf("  %u channel writes removed\n", rem);
+      _mesa_printf("  %u instructions removed\n", rem);
       /*_mesa_print_program(prog);*/
    }
+
+done:
+   _mesa_free(removeInst);
 }