mesa: Do copy propagation across if-else-endif.
authorJosé Fonseca <jfonseca@vmware.com>
Thu, 17 Feb 2011 09:48:17 +0000 (09:48 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 17 Feb 2011 15:29:30 +0000 (15:29 +0000)
Addresses excessive TEMP allocation in vertex shaders where all CONSTs are
stored into TEMPS at the start, but copy propagation was failing due to
the presence of IFs.

We could do something about loops, but ifs are easy enough.

src/mesa/program/ir_to_mesa.cpp

index 7f905ae5ce342200582a4560c05ff5925d1516cc..33c262f8ca4cea2833bc838a80f9551020ed0a8d 100644 (file)
@@ -2670,6 +2670,8 @@ ir_to_mesa_visitor::copy_propagate(void)
    ir_to_mesa_instruction **acp = rzalloc_array(mem_ctx,
                                                    ir_to_mesa_instruction *,
                                                    this->next_temp * 4);
+   int *acp_level = rzalloc_array(mem_ctx, int, this->next_temp * 4);
+   int level = 0;
 
    foreach_iter(exec_list_iterator, iter, this->instructions) {
       ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
@@ -2700,6 +2702,8 @@ ir_to_mesa_visitor::copy_propagate(void)
               break;
            }
 
+           assert(acp_level[acp_base + src_chan] <= level);
+
            if (!first) {
               first = copy_chan;
            } else {
@@ -2732,12 +2736,32 @@ ir_to_mesa_visitor::copy_propagate(void)
       switch (inst->op) {
       case OPCODE_BGNLOOP:
       case OPCODE_ENDLOOP:
-      case OPCODE_ELSE:
-      case OPCODE_ENDIF:
         /* End of a basic block, clear the ACP entirely. */
         memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
         break;
 
+      case OPCODE_IF:
+        ++level;
+        break;
+
+      case OPCODE_ENDIF:
+      case OPCODE_ELSE:
+        /* Clear all channels written inside the block from the ACP, but
+         * leaving those that were not touched.
+         */
+        for (int r = 0; r < this->next_temp; r++) {
+           for (int c = 0; c < 4; c++) {
+              if (!acp[4 * r + c])
+                 continue;
+
+              if (acp_level[4 * r + c] >= level)
+                 acp[4 * r + c] = NULL;
+           }
+        }
+        if (inst->op == OPCODE_ENDIF)
+           --level;
+        break;
+
       default:
         /* Continuing the block, clear any written channels from
          * the ACP.
@@ -2802,11 +2826,13 @@ ir_to_mesa_visitor::copy_propagate(void)
         for (int i = 0; i < 4; i++) {
            if (inst->dst_reg.writemask & (1 << i)) {
               acp[4 * inst->dst_reg.index + i] = inst;
+              acp_level[4 * inst->dst_reg.index + i] = level;
            }
         }
       }
    }
 
+   ralloc_free(acp_level);
    ralloc_free(acp);
 }