summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-06-23 14:51:14 -0700
committerIan Romanick <ian.d.romanick@intel.com>2010-06-23 15:20:29 -0700
commit2731a739d047e4aadc1cab4bcf8c01c1cf8e86db (patch)
tree58cba6d5734b5274ad622e6030f50608b8a4b9df
parent959a9ecdd8fbc3375e4149f2b44d253622ff12ee (diff)
Avoid using the RHS of an assignment twice.
This would fix double-evaluation of assignment RHS expressions, including possible side effects.
-rw-r--r--ast_to_hir.cpp22
1 files changed, 19 insertions, 3 deletions
diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp
index c059abb..61e0d01 100644
--- a/ast_to_hir.cpp
+++ b/ast_to_hir.cpp
@@ -509,10 +509,26 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
}
}
- ir_instruction *tmp = new ir_assignment(lhs, rhs, NULL);
- instructions->push_tail(tmp);
+ /* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
+ * but not post_inc) need the converted assigned value as an rvalue
+ * to handle things like:
+ *
+ * i = j += 1;
+ *
+ * So we always just store the computed value being assigned to a
+ * temporary and return a deref of that temporary. If the rvalue
+ * ends up not being used, the temp will get copy-propagated out.
+ */
+ ir_variable *var = new ir_variable(rhs->type, "assignment_tmp");
+ instructions->push_tail(new ir_assignment(new ir_dereference_variable(var),
+ rhs,
+ NULL));
+
+ instructions->push_tail(new ir_assignment(lhs,
+ new ir_dereference_variable(var),
+ NULL));
- return rhs;
+ return new ir_dereference_variable(var);
}