diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eefaa9a22d31..9baecb1796a8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2006-05-17 Sebastian Pop + + PR middle-end/20256 + PR middle-end/26435 + * tree-loop-linear.c (linear_transform_loops): Don't test perfect_nest_p. + Call rewrite_into_loop_closed_ssa only when something changed. + * lambda.h (gcc_loopnest_to_lambda_loopnest): Update declaration. + * lambda-code.c (can_convert_to_perfect_nest): Declared. + (gcc_loopnest_to_lambda_loopnest): Removed need_perfect_nest parameter. + Test for perfect_nest_p here. Fix formating. + (replace_uses_equiv_to_x_with_y): Fix formating. + (stmt_uses_op): Removed. + (can_convert_to_perfect_nest): Removed loopivs parameter. + Complete the test by checking the scalar dependences. + (perfect_nestify): Remove the test for can_convert_to_perfect_nest. + Fix formating. + 2005-05-17 Bernd Schmidt PR bootstrap/22541 diff --git a/gcc/lambda-code.c b/gcc/lambda-code.c index 3a28ee30c9da..60f1be209ce9 100644 --- a/gcc/lambda-code.c +++ b/gcc/lambda-code.c @@ -147,6 +147,7 @@ static lambda_lattice lambda_lattice_new (int, int); static lambda_lattice lambda_lattice_compute_base (lambda_loopnest); static tree find_induction_var_from_exit_cond (struct loop *); +static bool can_convert_to_perfect_nest (struct loop *); /* Create a new lambda body vector. */ @@ -1457,14 +1458,13 @@ DEF_VEC_ALLOC_P(lambda_loop,heap); lambda_loopnest gcc_loopnest_to_lambda_loopnest (struct loops *currloops, - struct loop * loop_nest, + struct loop *loop_nest, VEC(tree,heap) **inductionvars, - VEC(tree,heap) **invariants, - bool need_perfect_nest) + VEC(tree,heap) **invariants) { lambda_loopnest ret = NULL; - struct loop *temp; - int depth = 0; + struct loop *temp = loop_nest; + int depth = depth_of_nest (loop_nest); size_t i; VEC(lambda_loop,heap) *loops = NULL; VEC(tree,heap) *uboundvars = NULL; @@ -1472,9 +1472,11 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops, VEC(int,heap) *steps = NULL; lambda_loop newloop; tree inductionvar = NULL; - - depth = depth_of_nest (loop_nest); - temp = loop_nest; + bool perfect_nest = perfect_nest_p (loop_nest); + + if (!perfect_nest && !can_convert_to_perfect_nest (loop_nest)) + goto fail; + while (temp) { newloop = gcc_loop_to_lambda_loop (temp, depth, invariants, @@ -1482,12 +1484,14 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops, &lboundvars, &uboundvars, &steps); if (!newloop) - return NULL; + goto fail; + VEC_safe_push (tree, heap, *inductionvars, inductionvar); VEC_safe_push (lambda_loop, heap, loops, newloop); temp = temp->inner; } - if (need_perfect_nest) + + if (!perfect_nest) { if (!perfect_nestify (currloops, loop_nest, lboundvars, uboundvars, steps, *inductionvars)) @@ -1501,9 +1505,12 @@ gcc_loopnest_to_lambda_loopnest (struct loops *currloops, fprintf (dump_file, "Successfully converted loop nest to perfect loop nest.\n"); } + ret = lambda_loopnest_new (depth, 2 * depth); + for (i = 0; VEC_iterate (lambda_loop, loops, i, newloop); i++) LN_LOOPS (ret)[i] = newloop; + fail: VEC_free (lambda_loop, heap, loops); VEC_free (tree, heap, uboundvars); @@ -2110,13 +2117,12 @@ replace_uses_equiv_to_x_with_y (struct loop *loop, tree stmt, tree x, { tree use = USE_FROM_PTR (use_p); tree step = NULL_TREE; - tree access_fn = NULL_TREE; - - - access_fn = instantiate_parameters - (loop, analyze_scalar_evolution (loop, use)); - if (access_fn != NULL_TREE && access_fn != chrec_dont_know) - step = evolution_part_in_loop_num (access_fn, loop->num); + tree scev = instantiate_parameters (loop, + analyze_scalar_evolution (loop, use)); + + if (scev != NULL_TREE && scev != chrec_dont_know) + step = evolution_part_in_loop_num (scev, loop->num); + if ((step && step != chrec_dont_know && TREE_CODE (step) == INTEGER_CST && int_cst_value (step) == xstep) @@ -2125,22 +2131,6 @@ replace_uses_equiv_to_x_with_y (struct loop *loop, tree stmt, tree x, } } -/* Return TRUE if STMT uses tree OP in it's uses. */ - -static bool -stmt_uses_op (tree stmt, tree op) -{ - ssa_op_iter iter; - tree use; - - FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) - { - if (use == op) - return true; - } - return false; -} - /* Return true if STMT is an exit PHI for LOOP */ static bool @@ -2210,14 +2200,12 @@ can_put_after_inner_loop (struct loop *loop, tree stmt) -/* Return TRUE if LOOP is an imperfect nest that we can convert to a perfect - one. LOOPIVS is a vector of induction variables, one per loop. - ATM, we only handle imperfect nests of depth 2, where all of the statements - occur after the inner loop. */ +/* Return TRUE if LOOP is an imperfect nest that we can convert to a + perfect one. At the moment, we only handle imperfect nests of + depth 2, where all of the statements occur after the inner loop. */ static bool -can_convert_to_perfect_nest (struct loop *loop, - VEC(tree,heap) *loopivs) +can_convert_to_perfect_nest (struct loop *loop) { basic_block *bbs; tree exit_condition, phi; @@ -2237,19 +2225,13 @@ can_convert_to_perfect_nest (struct loop *loop, { for (bsi = bsi_start (bbs[i]); !bsi_end_p (bsi); bsi_next (&bsi)) { - size_t j; tree stmt = bsi_stmt (bsi); - tree iv; - + if (stmt == exit_condition || not_interesting_stmt (stmt) || stmt_is_bumper_for_loop (loop, stmt)) continue; - /* 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 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 @@ -2258,10 +2240,65 @@ can_convert_to_perfect_nest (struct loop *loop, win we get from rearranging the memory walk the loop is doing so that it has better cache behavior. */ - if (TREE_CODE (stmt) == MODIFY_EXPR - && (can_put_in_inner_loop (loop->inner, stmt) - || can_put_after_inner_loop (loop, stmt))) - continue; + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + use_operand_p use_a, use_b; + imm_use_iterator imm_iter; + ssa_op_iter op_iter, op_iter1; + tree op0 = TREE_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)->loop_father + == loop->inner) + goto fail; + } + } + } + + if (can_put_in_inner_loop (loop->inner, stmt) + || can_put_after_inner_loop (loop, stmt)) + continue; + } /* Otherwise, if the bb of a statement we care about isn't dominated by the header of the inner loop, then we can't @@ -2351,14 +2388,10 @@ perfect_nestify (struct loops *loops, tree stmt; tree oldivvar, ivvar, ivvarinced; VEC(tree,heap) *phis = NULL; - - if (!can_convert_to_perfect_nest (loop, loopivs)) - return false; - - /* Create the new loop */ - + + /* Create the new loop. */ olddest = loop->single_exit->dest; - preheaderbb = loop_split_edge_with (loop->single_exit, NULL); + preheaderbb = loop_split_edge_with (loop->single_exit, NULL); headerbb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb); /* Push the exit phi nodes that we are moving. */ @@ -2490,7 +2523,7 @@ perfect_nestify (struct loops *loops, } /* Make copies of this statement to put it back next - to its uses. */ + to its uses. */ FOR_EACH_IMM_USE_STMT (imm_stmt, imm_iter, TREE_OPERAND (stmt, 0)) { @@ -2506,8 +2539,10 @@ perfect_nestify (struct loops *loops, newname = SSA_NAME_VAR (newname); newname = make_ssa_name (newname, newstmt); TREE_OPERAND (newstmt, 0) = newname; + FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) SET_USE (use_p, newname); + bsi_insert_before (&tobsi, newstmt, BSI_SAME_STMT); update_stmt (newstmt); update_stmt (imm_stmt); @@ -2535,10 +2570,9 @@ perfect_nestify (struct loops *loops, continue; } - replace_uses_equiv_to_x_with_y (loop, stmt, - oldivvar, - VEC_index (int, steps, 0), - ivvar); + replace_uses_equiv_to_x_with_y + (loop, stmt, oldivvar, VEC_index (int, steps, 0), ivvar); + bsi_move_before (&bsi, &tobsi); /* If the statement has any virtual operands, they may diff --git a/gcc/lambda.h b/gcc/lambda.h index fc5679a57634..5eb63997c0d8 100644 --- a/gcc/lambda.h +++ b/gcc/lambda.h @@ -199,8 +199,7 @@ void print_lambda_body_vector (FILE *, lambda_body_vector); lambda_loopnest gcc_loopnest_to_lambda_loopnest (struct loops *, struct loop *, VEC(tree,heap) **, - VEC(tree,heap) **, - bool); + VEC(tree,heap) **); void lambda_loopnest_to_gcc_loopnest (struct loop *, VEC(tree,heap) *, VEC(tree,heap) *, lambda_loopnest, lambda_trans_matrix); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ltrans-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ltrans-1.c index a3a9975c51d8..736a4d95577a 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ltrans-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ltrans-1.c @@ -18,7 +18,6 @@ int foo(int N, int *res) } *res = sum + N; } -/* { dg-final { scan-tree-dump-times "converted loop nest to perfect - loop nest" 1 "ltrans"} } */ +/* { dg-final { scan-tree-dump-times "converted loop nest to perfect loop nest" 1 "ltrans"} } */ /* { dg-final { scan-tree-dump-times "transformed loop" 1 "ltrans"} } */ /* { dg-final { cleanup-tree-dump "ltrans" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20256.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20256.c new file mode 100644 index 000000000000..aa482edab636 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20256.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-loop-linear -fdump-tree-ltrans-all" } */ +/* { dg-require-effective-target size32plus } */ + +int foo() +{ + int x[2][2], y[2]; + int i, n, s; + + /* This is a reduction: there is a scalar dependence that cannot be + removed by rewriting IVs. This code cannot and should not be + transformed into a perfect loop. */ + for (n = 0; n < 2; n++) + { + s = 0; + for (i = 0; i < 2; i++) + s += x[n][i]*y[i]; + s += 1; + } + + return s; +} + +/* { dg-final { scan-tree-dump-times "converted loop nest to perfect loop nest" 0 "ltrans"} } */ +/* { dg-final { cleanup-tree-dump "ltrans" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr26435.c b/gcc/testsuite/gcc.dg/tree-ssa/pr26435.c new file mode 100644 index 000000000000..907c5d28dc45 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr26435.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-loop-linear -fdump-tree-ltrans-all" } */ +/* { dg-require-effective-target size32plus } */ + +int foo(int *p, int n) +{ + int i, j, k = 0; + + /* This is a reduction: there is a scalar dependence that cannot be + removed by rewriting IVs. This code cannot and should not be + transformed into a perfect loop. */ + for (i = 0; i < 2; ++i, p += n) + for (j = 0; j < 2; ++j) + k += p[j]; + + return k; +} + +/* { dg-final { scan-tree-dump-times "converted loop nest to perfect loop nest" 0 "ltrans"} } */ +/* { dg-final { cleanup-tree-dump "ltrans" } } */ diff --git a/gcc/tree-loop-linear.c b/gcc/tree-loop-linear.c index c648ef77c0db..e0f5bd2991bd 100644 --- a/gcc/tree-loop-linear.c +++ b/gcc/tree-loop-linear.c @@ -241,6 +241,7 @@ try_interchange_loops (lambda_trans_matrix trans, void linear_transform_loops (struct loops *loops) { + bool modified = false; unsigned int i; VEC(tree,heap) *oldivs = NULL; VEC(tree,heap) *invariants = NULL; @@ -255,7 +256,6 @@ linear_transform_loops (struct loops *loops) lambda_loopnest before, after; lambda_trans_matrix trans; bool problem = false; - bool need_perfect_nest = false; /* If it's not a loop nest, we don't want it. We also don't handle sibling loops properly, which are loops of the following form: @@ -319,13 +319,9 @@ linear_transform_loops (struct loops *loops) continue; } - if (!perfect_nest_p (loop_nest)) - need_perfect_nest = true; + before = gcc_loopnest_to_lambda_loopnest (loops, loop_nest, &oldivs, + &invariants); - before = gcc_loopnest_to_lambda_loopnest (loops, - loop_nest, &oldivs, - &invariants, - need_perfect_nest); if (!before) continue; @@ -345,6 +341,7 @@ linear_transform_loops (struct loops *loops) lambda_loopnest_to_gcc_loopnest (loop_nest, oldivs, invariants, after, trans); + modified = true; if (dump_file) fprintf (dump_file, "Successfully transformed loop.\n"); @@ -356,5 +353,7 @@ linear_transform_loops (struct loops *loops) VEC_free (tree, heap, oldivs); VEC_free (tree, heap, invariants); scev_reset (); - rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa_full_phi); + + if (modified) + rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa_full_phi); }