- /* If the statement uses inner loop ivs, we == screwed. */
- for (j = 1; VEC_iterate (tree, loopivs, j, iv); j++)
- if (stmt_uses_op (stmt, iv))
- goto fail;
-
- /* If this is a simple operation like a cast that is invariant
- in the inner loop, only used there, and we can place it
- there, then it's not going to hurt us.
- This means that we will propagate casts and other cheap
- invariant operations *back*
- into the inner loop if we can interchange the loop, on the
- theory that we are going to gain a lot more by interchanging
- the loop than we are by leaving some invariant code there for
- some other pass to clean up. */
- if (TREE_CODE (stmt) == MODIFY_EXPR
- && is_gimple_cast (TREE_OPERAND (stmt, 1))
- && can_put_in_inner_loop (loop->inner, stmt))
- continue;
+
+ /* If this is a scalar operation that can be put back
+ into the inner loop, or after the inner loop, through
+ copying, then do so. This works on the theory that
+ any amount of scalar code we have to reduplicate
+ into or after the loops is less expensive that the
+ win we get from rearranging the memory walk
+ the loop is doing so that it has better
+ cache behavior. */
+ if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+ {
+ use_operand_p use_a, use_b;
+ imm_use_iterator imm_iter;
+ ssa_op_iter op_iter, op_iter1;
+ tree op0 = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree scev = instantiate_parameters
+ (loop, analyze_scalar_evolution (loop, op0));
+
+ /* If the IV is simple, it can be duplicated. */
+ if (!automatically_generated_chrec_p (scev))
+ {
+ tree step = evolution_part_in_loop_num (scev, loop->num);
+ if (step && step != chrec_dont_know
+ && TREE_CODE (step) == INTEGER_CST)
+ continue;
+ }
+
+ /* The statement should not define a variable used
+ in the inner loop. */
+ if (TREE_CODE (op0) == SSA_NAME)
+ FOR_EACH_IMM_USE_FAST (use_a, imm_iter, op0)
+ if (bb_for_stmt (USE_STMT (use_a))->loop_father
+ == loop->inner)
+ goto fail;
+
+ FOR_EACH_SSA_USE_OPERAND (use_a, stmt, op_iter, SSA_OP_USE)
+ {
+ tree node, op = USE_FROM_PTR (use_a);
+
+ /* The variables should not be used in both loops. */
+ FOR_EACH_IMM_USE_FAST (use_b, imm_iter, op)
+ if (bb_for_stmt (USE_STMT (use_b))->loop_father
+ == loop->inner)
+ goto fail;
+
+ /* The statement should not use the value of a
+ scalar that was modified in the loop. */
+ node = SSA_NAME_DEF_STMT (op);
+ if (TREE_CODE (node) == PHI_NODE)
+ FOR_EACH_PHI_ARG (use_b, node, op_iter1, SSA_OP_USE)
+ {
+ tree arg = USE_FROM_PTR (use_b);
+
+ if (TREE_CODE (arg) == SSA_NAME)
+ {
+ tree arg_stmt = SSA_NAME_DEF_STMT (arg);
+
+ if (bb_for_stmt (arg_stmt)
+ && (bb_for_stmt (arg_stmt)->loop_father
+ == loop->inner))
+ goto fail;
+ }
+ }
+ }
+
+ if (can_put_in_inner_loop (loop->inner, stmt)
+ || can_put_after_inner_loop (loop, stmt))
+ continue;
+ }