mesa: Fix the Mesa IR copy propagation to not read past writes to the reg.
authorEric Anholt <eric@anholt.net>
Fri, 4 Feb 2011 19:31:02 +0000 (13:31 -0600)
committerEric Anholt <eric@anholt.net>
Tue, 8 Feb 2011 19:42:35 +0000 (11:42 -0800)
Fixes glsl-vs-post-increment-01.

Reviewed-by: José Fonseca <jfonseca@vmware.com>
src/mesa/program/ir_to_mesa.cpp

index 3794c0de02af3746b2d77d52639bf349b49ae1cc..d0ec23fc857c8439f5b43af8134b64e14ffab4f4 100644 (file)
@@ -2742,13 +2742,46 @@ ir_to_mesa_visitor::copy_propagate(void)
         /* Continuing the block, clear any written channels from
          * the ACP.
          */
-        if (inst->dst_reg.file == PROGRAM_TEMPORARY) {
-           if (inst->dst_reg.reladdr) {
-              memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
-           } else {
-              for (int i = 0; i < 4; i++) {
-                 if (inst->dst_reg.writemask & (1 << i)) {
-                    acp[4 * inst->dst_reg.index + i] = NULL;
+        if (inst->dst_reg.file == PROGRAM_TEMPORARY && inst->dst_reg.reladdr) {
+           /* Any temporary might be written, so no copy propagation
+            * across this instruction.
+            */
+           memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
+        } else if (inst->dst_reg.file == PROGRAM_OUTPUT &&
+                   inst->dst_reg.reladdr) {
+           /* Any output might be written, so no copy propagation
+            * from outputs across this instruction.
+            */
+           for (int r = 0; r < this->next_temp; r++) {
+              for (int c = 0; c < 4; c++) {
+                 if (acp[4 * r + c]->src_reg[0].file == PROGRAM_OUTPUT)
+                    acp[4 * r + c] = NULL;
+              }
+           }
+        } else if (inst->dst_reg.file == PROGRAM_TEMPORARY ||
+                   inst->dst_reg.file == PROGRAM_OUTPUT) {
+           /* Clear where it's used as dst. */
+           if (inst->dst_reg.file == PROGRAM_TEMPORARY) {
+              for (int c = 0; c < 4; c++) {
+                 if (inst->dst_reg.writemask & (1 << c)) {
+                    acp[4 * inst->dst_reg.index + c] = NULL;
+                 }
+              }
+           }
+
+           /* Clear where it's used as src. */
+           for (int r = 0; r < this->next_temp; r++) {
+              for (int c = 0; c < 4; c++) {
+                 if (!acp[4 * r + c])
+                    continue;
+
+                 int src_chan = GET_SWZ(acp[4 * r + c]->src_reg[0].swizzle, c);
+
+                 if (acp[4 * r + c]->src_reg[0].file == inst->dst_reg.file &&
+                     acp[4 * r + c]->src_reg[0].index == inst->dst_reg.index &&
+                     inst->dst_reg.writemask & (1 << src_chan))
+                 {
+                    acp[4 * r + c] = NULL;
                  }
               }
            }