summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2011-02-04 13:31:02 -0600
committerEric Anholt <eric@anholt.net>2011-02-08 11:42:35 -0800
commit76857e8954484d5bf8758d7bfc87f264f95a0ebd (patch)
tree71c2a2ebfb980804487a93ee2c18e3178d184be5
parent60aab5f335537e5b6788132e2563865243483750 (diff)
mesa: Fix the Mesa IR copy propagation to not read past writes to the reg.
Fixes glsl-vs-post-increment-01. Reviewed-by: José Fonseca <jfonseca@vmware.com>
-rw-r--r--src/mesa/program/ir_to_mesa.cpp47
1 files changed, 40 insertions, 7 deletions
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 3794c0de02..d0ec23fc85 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -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;
}
}
}