diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eae18834bd0..766f034ef60 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2015-11-25 Aditya Kumar + Sebastian Pop + + PR tree-optimization/68453 + * graphite-isl-ast-to-gimple.c (translate_isl_ast_for_loop): Do + not redirect edges already pointing to their destination. + (translate_isl_ast_node_for): Split edges after loops to create + basic blocks for close phi nodes. Save merge points at the end of + a loop guard. + (translate_isl_ast_node_if): Save merge points at the end of the + if region. + (add_close_phis_to_outer_loops): New. + (add_close_phis_to_merge_points): New. + (copy_loop_close_phi_args): Call add_close_phis_to_merge_points. + (copy_bb_and_scalar_dependences): Do not split basic blocks on + loop close phi locations. + 2015-11-25 Jan Hubicka * ipa-visibility.c (cgraph_externally_visible_p, diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c index 363fec70ffa..33423dd2bab 100644 --- a/gcc/graphite-isl-ast-to-gimple.c +++ b/gcc/graphite-isl-ast-to-gimple.c @@ -360,6 +360,15 @@ class translate_isl_ast_to_gimple bool copy_loop_phi_nodes (basic_block bb, basic_block new_bb); + /* Add phi nodes to all merge points of all the diamonds enclosing the loop of + the close phi node PHI. */ + + bool add_close_phis_to_merge_points (gphi *old_phi, gphi *new_phi, + tree default_value); + + tree add_close_phis_to_outer_loops (tree last_merge_name, edge merge_e, + gimple *old_close_phi); + /* Copy all the loop-close phi args from BB to NEW_BB. */ bool copy_loop_close_phi_args (basic_block old_bb, basic_block new_bb, @@ -471,11 +480,15 @@ class translate_isl_ast_to_gimple } private: + /* The region to be translated. */ sese_info_p region; /* This flag is set when an error occurred during the translation of ISL AST to Gimple. */ bool codegen_error; + + /* A vector of all the edges at if_condition merge points. */ + auto_vec merge_points; }; /* Return the tree variable that corresponds to the given isl ast identifier @@ -797,7 +810,8 @@ translate_isl_ast_for_loop (loop_p context_loop, if (!next_e || codegen_error_p ()) return NULL; - redirect_edge_succ_nodup (next_e, after); + if (next_e->dest != after) + redirect_edge_succ_nodup (next_e, after); set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src); if (flag_loop_parallelize_all) @@ -938,12 +952,21 @@ translate_isl_ast_node_for (loop_p context_loop, __isl_keep isl_ast_node *node, &lb, &ub, ip); if (last_e == next_e) - /* There was no guard generated. */ - return translate_isl_ast_for_loop (context_loop, node, last_e, - type, lb, ub, ip); + { + /* There was no guard generated. */ + last_e = single_succ_edge (split_edge (last_e)); + + translate_isl_ast_for_loop (context_loop, node, next_e, + type, lb, ub, ip); + return last_e; + } edge true_e = get_true_edge_from_guard_bb (next_e->dest); + merge_points.safe_push (last_e); + + last_e = single_succ_edge (split_edge (last_e)); translate_isl_ast_for_loop (context_loop, node, true_e, type, lb, ub, ip); + return last_e; } @@ -1081,8 +1104,9 @@ translate_isl_ast_node_if (loop_p context_loop, gcc_assert (isl_ast_node_get_type (node) == isl_ast_node_if); isl_ast_expr *if_cond = isl_ast_node_if_get_cond (node); edge last_e = graphite_create_new_guard (next_e, if_cond, ip); - edge true_e = get_true_edge_from_guard_bb (next_e->dest); + merge_points.safe_push (last_e); + isl_ast_node *then_node = isl_ast_node_if_get_then (node); translate_isl_ast (context_loop, then_node, true_e, ip); isl_ast_node_free (then_node); @@ -1091,6 +1115,7 @@ translate_isl_ast_node_if (loop_p context_loop, isl_ast_node *else_node = isl_ast_node_if_get_else (node); if (isl_ast_node_get_type (else_node) != isl_ast_node_error) translate_isl_ast (context_loop, else_node, false_e, ip); + isl_ast_node_free (else_node); return last_e; } @@ -1135,7 +1160,7 @@ translate_isl_ast_to_gimple::translate_isl_ast (loop_p context_loop, at the exit of loop which takes one argument that is the last value of the variable being used out of the loop. */ -bool +static bool bb_contains_loop_close_phi_nodes (basic_block bb) { return single_pred_p (bb) @@ -1145,7 +1170,7 @@ bb_contains_loop_close_phi_nodes (basic_block bb) /* Return true when BB contains loop phi nodes. A loop phi node is the loop header containing phi nodes which has one init-edge and one back-edge. */ -bool +static bool bb_contains_loop_phi_nodes (basic_block bb) { gcc_assert (EDGE_COUNT (bb->preds) <= 2); @@ -2050,6 +2075,114 @@ find_init_value_close_phi (gphi *phi) return find_init_value (def); } + +tree translate_isl_ast_to_gimple:: +add_close_phis_to_outer_loops (tree last_merge_name, edge last_e, + gimple *old_close_phi) +{ + sese_l &codegen_region = region->if_region->true_region->region; + gimple *stmt = SSA_NAME_DEF_STMT (last_merge_name); + basic_block bb = gimple_bb (stmt); + if (!bb_in_sese_p (bb, codegen_region)) + return last_merge_name; + + loop_p loop = bb->loop_father; + if (!loop_in_sese_p (loop, codegen_region)) + return last_merge_name; + + edge e = single_exit (loop); + + if (dominated_by_p (CDI_DOMINATORS, e->dest, last_e->src)) + return last_merge_name; + + tree old_name = gimple_phi_arg_def (old_close_phi, 0); + tree old_close_phi_name = gimple_phi_result (old_close_phi); + + bb = e->dest; + if (!bb_contains_loop_close_phi_nodes (bb) || !single_succ_p (bb)) + bb = split_edge (e); + + gphi *close_phi = create_phi_node (SSA_NAME_VAR (last_merge_name), bb); + tree res = create_new_def_for (last_merge_name, close_phi, + gimple_phi_result_ptr (close_phi)); + set_rename (old_close_phi_name, res); + add_phi_arg (close_phi, last_merge_name, e, get_loc (old_name)); + last_merge_name = res; + + return add_close_phis_to_outer_loops (last_merge_name, last_e, old_close_phi); +} + +/* Add phi nodes to all merge points of all the diamonds enclosing the loop of + the close phi node PHI. */ + +bool translate_isl_ast_to_gimple:: +add_close_phis_to_merge_points (gphi *old_close_phi, gphi *new_close_phi, + tree default_value) +{ + sese_l &codegen_region = region->if_region->true_region->region; + basic_block default_value_bb = get_entry_bb (codegen_region); + if (SSA_NAME == TREE_CODE (default_value)) + { + gimple *stmt = SSA_NAME_DEF_STMT (default_value); + if (!stmt || gimple_code (stmt) == GIMPLE_NOP) + return false; + default_value_bb = gimple_bb (stmt); + } + + basic_block new_close_phi_bb = gimple_bb (new_close_phi); + + tree old_close_phi_name = gimple_phi_result (old_close_phi); + tree new_close_phi_name = gimple_phi_result (new_close_phi); + tree last_merge_name = new_close_phi_name; + tree old_name = gimple_phi_arg_def (old_close_phi, 0); + + int i; + edge merge_e; + FOR_EACH_VEC_ELT_REVERSE (merge_points, i, merge_e) + { + basic_block new_merge_bb = merge_e->src; + if (!dominated_by_p (CDI_DOMINATORS, new_merge_bb, default_value_bb)) + continue; + + last_merge_name = add_close_phis_to_outer_loops (last_merge_name, merge_e, + old_close_phi); + + gphi *merge_phi = create_phi_node (SSA_NAME_VAR (old_close_phi_name), new_merge_bb); + tree merge_res = create_new_def_for (old_close_phi_name, merge_phi, + gimple_phi_result_ptr (merge_phi)); + set_rename (old_close_phi_name, merge_res); + + edge from_loop = NULL, from_default_value = NULL; + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, new_merge_bb->preds) + if (dominated_by_p (CDI_DOMINATORS, e->src, new_close_phi_bb)) + from_loop = e; + else + from_default_value = e; + + /* Because CDI_POST_DOMINATORS are not updated, we only rely on + CDI_DOMINATORS, which may not handle all cases where new_close_phi_bb + is contained in another condition. */ + if (!from_default_value || !from_loop) + return false; + + add_phi_arg (merge_phi, last_merge_name, from_loop, get_loc (old_name)); + add_phi_arg (merge_phi, default_value, from_default_value, get_loc (old_name)); + + if (dump_file) + { + fprintf (dump_file, "[codegen] Adding guard-phi: "); + print_gimple_stmt (dump_file, merge_phi, 0, 0); + } + + update_stmt (merge_phi); + last_merge_name = merge_res; + } + + return true; +} + /* Copy all the loop-close phi args from BB to NEW_BB. */ bool @@ -2057,15 +2190,11 @@ translate_isl_ast_to_gimple::copy_loop_close_phi_args (basic_block old_bb, basic_block new_bb, bool postpone) { - /* The successor of bb having close phi should be a merge of the diamond - inserted to guard the loop during codegen. */ - basic_block succ_new_bb = single_succ (new_bb); - for (gphi_iterator psi = gsi_start_phis (old_bb); !gsi_end_p (psi); gsi_next (&psi)) { - gphi *phi = psi.phi (); - tree res = gimple_phi_result (phi); + gphi *old_close_phi = psi.phi (); + tree res = gimple_phi_result (old_close_phi); if (virtual_operand_p (res)) continue; @@ -2073,12 +2202,12 @@ translate_isl_ast_to_gimple::copy_loop_close_phi_args (basic_block old_bb, /* Loop close phi nodes should not be scev_analyzable_p. */ gcc_unreachable (); - gphi *new_phi = create_phi_node (SSA_NAME_VAR (res), new_bb); - tree new_res = create_new_def_for (res, new_phi, - gimple_phi_result_ptr (new_phi)); + gphi *new_close_phi = create_phi_node (SSA_NAME_VAR (res), new_bb); + tree new_res = create_new_def_for (res, new_close_phi, + gimple_phi_result_ptr (new_close_phi)); set_rename (res, new_res); - tree old_name = gimple_phi_arg_def (phi, 0); + tree old_name = gimple_phi_arg_def (old_close_phi, 0); tree new_name = get_new_name (new_bb, old_name, old_bb, false); /* Predecessor basic blocks of a loop close phi should have been code @@ -2087,60 +2216,43 @@ translate_isl_ast_to_gimple::copy_loop_close_phi_args (basic_block old_bb, if (!new_name) return false; - add_phi_arg (new_phi, new_name, single_pred_edge (new_bb), + add_phi_arg (new_close_phi, new_name, single_pred_edge (new_bb), get_loc (old_name)); if (dump_file) { fprintf (dump_file, "[codegen] Adding loop-closed phi: "); - print_gimple_stmt (dump_file, new_phi, 0, 0); + print_gimple_stmt (dump_file, new_close_phi, 0, 0); } - update_stmt (new_phi); + update_stmt (new_close_phi); /* When there is no loop guard around this codegenerated loop, there is no need to collect the close-phi arg. */ - if (2 != EDGE_COUNT (succ_new_bb->preds) - || bb_contains_loop_phi_nodes (succ_new_bb)) + if (merge_points.is_empty ()) continue; /* Add a PHI in the succ_new_bb for each close phi of the loop. */ - tree init = find_init_value_close_phi (new_phi); + tree default_value = find_init_value_close_phi (new_close_phi); - /* A close phi must come from a loop-phi having an init value. */ - if (!init) + /* A close phi must come from a loop-phi having a default value. */ + if (!default_value) { if (!postpone) return false; - region->incomplete_phis.safe_push (std::make_pair (phi, new_phi)); + region->incomplete_phis.safe_push (std::make_pair (old_close_phi, + new_close_phi)); if (dump_file) { fprintf (dump_file, "[codegen] postpone close phi nodes: "); - print_gimple_stmt (dump_file, new_phi, 0, 0); + print_gimple_stmt (dump_file, new_close_phi, 0, 0); } continue; } - gphi *merge_phi = create_phi_node (SSA_NAME_VAR (res), succ_new_bb); - tree merge_res = create_new_def_for (res, merge_phi, - gimple_phi_result_ptr (merge_phi)); - set_rename (res, merge_res); - - edge from_loop = single_succ_edge (new_bb); - add_phi_arg (merge_phi, new_res, from_loop, get_loc (old_name)); - - /* The edge coming from loop guard. */ - edge other = from_loop == (*succ_new_bb->preds)[0] - ? (*succ_new_bb->preds)[1] : (*succ_new_bb->preds)[0]; - - add_phi_arg (merge_phi, init, other, get_loc (old_name)); - if (dump_file) - { - fprintf (dump_file, "[codegen] Adding guard-phi: "); - print_gimple_stmt (dump_file, merge_phi, 0, 0); - } - - update_stmt (new_phi); + if (!add_close_phis_to_merge_points (old_close_phi, new_close_phi, + default_value)) + return false; } return true; @@ -2651,31 +2763,8 @@ translate_isl_ast_to_gimple::copy_bb_and_scalar_dependences (basic_block bb, } } - basic_block new_bb = split_edge (next_e); - if (num_phis > 0 && bb_contains_loop_phi_nodes (bb)) - { - basic_block phi_bb = next_e->dest->loop_father->header; - - /* At this point we are unable to codegenerate by still preserving the SSA - structure because maybe the loop is completely unrolled and the PHIs - and cross-bb scalar dependencies are untrackable w.r.t. the original - code. See gfortran.dg/graphite/pr29832.f90. */ - if (EDGE_COUNT (bb->preds) != EDGE_COUNT (phi_bb->preds)) - { - codegen_error = true; - return NULL; - } - - if (dump_file) - fprintf (dump_file, "[codegen] bb_%d contains loop phi nodes.\n", - bb->index); - if (!copy_loop_phi_nodes (bb, phi_bb)) - { - codegen_error = true; - return NULL; - } - } - else if (bb_contains_loop_close_phi_nodes (bb)) + basic_block new_bb = NULL; + if (bb_contains_loop_close_phi_nodes (bb)) { if (dump_file) fprintf (dump_file, "[codegen] bb_%d contains close phi nodes.\n", @@ -2688,7 +2777,11 @@ translate_isl_ast_to_gimple::copy_bb_and_scalar_dependences (basic_block bb, return NULL; } - basic_block phi_bb = split_edge (e); + basic_block phi_bb = e->dest; + + if (!bb_contains_loop_close_phi_nodes (phi_bb) || !single_succ_p (phi_bb)) + phi_bb = split_edge (e); + gcc_assert (single_pred_edge (phi_bb)->src->loop_father != single_pred_edge (phi_bb)->dest->loop_father); @@ -2697,26 +2790,58 @@ translate_isl_ast_to_gimple::copy_bb_and_scalar_dependences (basic_block bb, codegen_error = true; return NULL; } + + if (e == next_e) + new_bb = phi_bb; + else + new_bb = split_edge (next_e); } - else if (num_phis > 0) + else { - if (dump_file) - fprintf (dump_file, "[codegen] bb_%d contains cond phi nodes.\n", - bb->index); - - basic_block phi_bb = single_pred (new_bb); - loop_p loop_father = new_bb->loop_father; - - /* Move back until we find the block with two predecessors. */ - while (single_pred_p (phi_bb)) - phi_bb = single_pred_edge (phi_bb)->src; - - /* If a corresponding merge-point was not found, then abort codegen. */ - if (phi_bb->loop_father != loop_father - || !copy_cond_phi_nodes (bb, phi_bb, iv_map)) + new_bb = split_edge (next_e); + if (num_phis > 0 && bb_contains_loop_phi_nodes (bb)) { - codegen_error = true; - return NULL; + basic_block phi_bb = next_e->dest->loop_father->header; + + /* At this point we are unable to codegenerate by still preserving the SSA + structure because maybe the loop is completely unrolled and the PHIs + and cross-bb scalar dependencies are untrackable w.r.t. the original + code. See gfortran.dg/graphite/pr29832.f90. */ + if (EDGE_COUNT (bb->preds) != EDGE_COUNT (phi_bb->preds)) + { + codegen_error = true; + return NULL; + } + + if (dump_file) + fprintf (dump_file, "[codegen] bb_%d contains loop phi nodes.\n", + bb->index); + if (!copy_loop_phi_nodes (bb, phi_bb)) + { + codegen_error = true; + return NULL; + } + } + else if (num_phis > 0) + { + if (dump_file) + fprintf (dump_file, "[codegen] bb_%d contains cond phi nodes.\n", + bb->index); + + basic_block phi_bb = single_pred (new_bb); + loop_p loop_father = new_bb->loop_father; + + /* Move back until we find the block with two predecessors. */ + while (single_pred_p (phi_bb)) + phi_bb = single_pred_edge (phi_bb)->src; + + /* If a corresponding merge-point was not found, then abort codegen. */ + if (phi_bb->loop_father != loop_father + || !copy_cond_phi_nodes (bb, phi_bb, iv_map)) + { + codegen_error = true; + return NULL; + } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 387a71f7dbc..41804b98efc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2015-11-25 Aditya Kumar + Sebastian Pop + + PR tree-optimization/68453 + * gfortran.dg/graphite/pr68453.f90: New. + 2015-11-25 Martin Sebor PR c/66516 diff --git a/gcc/testsuite/gfortran.dg/graphite/pr68453.f90 b/gcc/testsuite/gfortran.dg/graphite/pr68453.f90 new file mode 100644 index 00000000000..18bc593e2d3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/pr68453.f90 @@ -0,0 +1,24 @@ +! { dg-options "-floop-nest-optimize -O2" } + +MODULE dbcsr_geev + INTEGER, PARAMETER :: real_8=8 +CONTAINS + SUBROUTINE dbcsr_dgeev(jobvl,jobvr,matrix,ndim,evals,revec,levec) + CHARACTER(1) :: jobvl, jobvr + REAL(real_8), DIMENSION(:, :) :: matrix + INTEGER :: ndim + COMPLEX(real_8), DIMENSION(:) :: evals + COMPLEX(real_8), DIMENSION(:, :) :: revec, levec + INTEGER :: i, info, lwork + REAL(real_8) :: norm, tmp_array(ndim,ndim), & + work(20*ndim) + REAL(real_8), DIMENSION(ndim) :: eval1, eval2 + REAL(real_8), DIMENSION(ndim, ndim) :: evec_l, evec_r + DO WHILE (i.le.ndim) + IF(ABS(eval2(i)).LT.EPSILON(REAL(0.0,real_8)))THEN + norm=SQRT(SUM(evec_r(:,i)**2.0_real_8)+SUM(evec_r(:,i+1)**2.0_real_8)) + revec(:,i)=CMPLX(evec_r(:,i),evec_r(:,i+1),real_8)/norm + END IF + END DO + END SUBROUTINE dbcsr_dgeev +END MODULE dbcsr_geev