swap_tree_operands does not handle swapping operands in a_1 = x_2 + 1; very well as it keeps the use operand for x_2 pointing to its old slot and thus 1 after it finished. That's of course bad as no user of swap_tree_operands feels the need to update the statement - swap_tree_operands is after all exactly to avoid updating the statement (and eventually disrupting the operand list).
Fixed, thus. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2011-09-09 Richard Guenther <rguent...@suse.de> * tree-ssa-operands.c (swap_tree_operands): Always adjust existing operand positions. Index: gcc/tree-ssa-operands.c =================================================================== --- gcc/tree-ssa-operands.c (revision 178719) +++ gcc/tree-ssa-operands.c (working copy) @@ -1149,7 +1149,8 @@ swap_tree_operands (gimple stmt, tree *e /* If the operand cache is active, attempt to preserve the relative positions of these two operands in their respective immediate use - lists. */ + lists by adjusting their use pointer to point to the new + operand position. */ if (ssa_operands_active () && op0 != op1) { use_optype_p use0, use1, ptr; @@ -1170,14 +1171,12 @@ swap_tree_operands (gimple stmt, tree *e break; } - /* If both uses don't have operand entries, there isn't much we can do - at this point. Presumably we don't need to worry about it. */ - if (use0 && use1) - { - tree *tmp = USE_OP_PTR (use1)->use; - USE_OP_PTR (use1)->use = USE_OP_PTR (use0)->use; - USE_OP_PTR (use0)->use = tmp; - } + /* And adjust their location to point to the new position of the + operand. */ + if (use0) + USE_OP_PTR (use0)->use = exp1; + if (use1) + USE_OP_PTR (use1)->use = exp0; } /* Now swap the data. */