diff options
author | Eric Anholt <eric@anholt.net> | 2010-06-23 14:51:14 -0700 |
---|---|---|
committer | Ian Romanick <ian.d.romanick@intel.com> | 2010-06-23 15:20:29 -0700 |
commit | 2731a739d047e4aadc1cab4bcf8c01c1cf8e86db (patch) | |
tree | 58cba6d5734b5274ad622e6030f50608b8a4b9df | |
parent | 959a9ecdd8fbc3375e4149f2b44d253622ff12ee (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.cpp | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp index c059abbff6..61e0d01a90 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); } |