summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Fonseca <[email protected]>2011-02-17 09:48:17 +0000
committerJosé Fonseca <[email protected]>2011-02-17 15:29:30 +0000
commit8902c42db4fd72568cfa071987cfa10e7a366c2e (patch)
tree3a328999a9beda4133758d87e0dcf7ffe477b918
parent6c1fcf85838a4aa76bcb9f9ceb312f1772f1122e (diff)
mesa: Do copy propagation across if-else-endif.
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.
-rw-r--r--src/mesa/program/ir_to_mesa.cpp30
1 files changed, 28 insertions, 2 deletions
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 7f905ae5ce3..33c262f8ca4 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -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);
}