+/* Returns true when LOOP contains vector phi nodes. */
+
+static bool
+loop_has_vector_phi_nodes (struct loop *loop ATTRIBUTE_UNUSED)
+{
+ unsigned i;
+ basic_block *bbs = get_loop_body_in_dom_order (loop);
+ gimple_stmt_iterator gsi;
+ bool res = true;
+
+ for (i = 0; i < loop->num_nodes; i++)
+ for (gsi = gsi_start_phis (bbs[i]); !gsi_end_p (gsi); gsi_next (&gsi))
+ if (TREE_CODE (TREE_TYPE (PHI_RESULT (gsi_stmt (gsi)))) == VECTOR_TYPE)
+ goto end;
+
+ res = false;
+ end:
+ free (bbs);
+ return res;
+}
+
+/* Create a reduction_info struct, initialize it with REDUC_STMT
+ and PHI, insert it to the REDUCTION_LIST. */
+
+static void
+build_new_reduction (htab_t reduction_list, gimple reduc_stmt, gimple phi)
+{
+ PTR *slot;
+ struct reduction_info *new_reduction;
+
+ gcc_assert (reduc_stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file,
+ "Detected reduction. reduction stmt is: \n");
+ print_gimple_stmt (dump_file, reduc_stmt, 0, 0);
+ fprintf (dump_file, "\n");
+ }
+
+ new_reduction = XCNEW (struct reduction_info);
+
+ new_reduction->reduc_stmt = reduc_stmt;
+ new_reduction->reduc_phi = phi;
+ new_reduction->reduc_version = SSA_NAME_VERSION (gimple_phi_result (phi));
+ new_reduction->reduction_code = gimple_assign_rhs_code (reduc_stmt);
+ slot = htab_find_slot (reduction_list, new_reduction, INSERT);
+ *slot = new_reduction;
+}
+
+/* Callback for htab_traverse. Sets gimple_uid of reduc_phi stmts. */
+
+static int
+set_reduc_phi_uids (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ struct reduction_info *const red = (struct reduction_info *) *slot;
+ gimple_set_uid (red->reduc_phi, red->reduc_version);
+ return 1;
+}
+
+/* Detect all reductions in the LOOP, insert them into REDUCTION_LIST. */
+
+static void
+gather_scalar_reductions (loop_p loop, htab_t reduction_list)
+{
+ gimple_stmt_iterator gsi;
+ loop_vec_info simple_loop_info;
+
+ vect_dump = NULL;
+ simple_loop_info = vect_analyze_loop_form (loop);
+
+ for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple phi = gsi_stmt (gsi);
+ affine_iv iv;
+ tree res = PHI_RESULT (phi);
+ bool double_reduc;
+
+ if (!is_gimple_reg (res))
+ continue;
+
+ if (!simple_iv (loop, loop, res, &iv, true)
+ && simple_loop_info)
+ {
+ gimple reduc_stmt = vect_force_simple_reduction (simple_loop_info,
+ phi, true,
+ &double_reduc);
+ if (reduc_stmt && !double_reduc)
+ build_new_reduction (reduction_list, reduc_stmt, phi);
+ }
+ }
+ destroy_loop_vec_info (simple_loop_info, true);
+
+ /* As gimple_uid is used by the vectorizer in between vect_analyze_loop_form
+ and destroy_loop_vec_info, we can set gimple_uid of reduc_phi stmts
+ only now. */
+ htab_traverse (reduction_list, set_reduc_phi_uids, NULL);
+}
+
+/* Try to initialize NITER for code generation part. */
+
+static bool
+try_get_loop_niter (loop_p loop, struct tree_niter_desc *niter)
+{
+ edge exit = single_dom_exit (loop);
+
+ gcc_assert (exit);
+
+ /* We need to know # of iterations, and there should be no uses of values
+ defined inside loop outside of it, unless the values are invariants of
+ the loop. */
+ if (!number_of_iterations_exit (loop, exit, niter, false))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " FAILED: number of iterations not known\n");
+ return false;
+ }
+
+ return true;
+}
+
+/* Try to initialize REDUCTION_LIST for code generation part.
+ REDUCTION_LIST describes the reductions. */
+
+static bool
+try_create_reduction_list (loop_p loop, htab_t reduction_list)
+{
+ edge exit = single_dom_exit (loop);
+ gimple_stmt_iterator gsi;
+
+ gcc_assert (exit);
+
+ gather_scalar_reductions (loop, reduction_list);
+
+
+ for (gsi = gsi_start_phis (exit->dest); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple phi = gsi_stmt (gsi);
+ struct reduction_info *red;
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ gimple reduc_phi;
+ tree val = PHI_ARG_DEF_FROM_EDGE (phi, exit);
+
+ if (is_gimple_reg (val))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "phi is ");
+ print_gimple_stmt (dump_file, phi, 0, 0);
+ fprintf (dump_file, "arg of phi to exit: value ");
+ print_generic_expr (dump_file, val, 0);
+ fprintf (dump_file, " used outside loop\n");
+ fprintf (dump_file,
+ " checking if it a part of reduction pattern: \n");
+ }
+ if (htab_elements (reduction_list) == 0)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ " FAILED: it is not a part of reduction.\n");
+ return false;
+ }
+ reduc_phi = NULL;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, val)
+ {
+ if (!gimple_debug_bind_p (USE_STMT (use_p))
+ && flow_bb_inside_loop_p (loop, gimple_bb (USE_STMT (use_p))))
+ {
+ reduc_phi = USE_STMT (use_p);
+ break;
+ }
+ }
+ red = reduction_phi (reduction_list, reduc_phi);
+ if (red == NULL)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ " FAILED: it is not a part of reduction.\n");
+ return false;
+ }
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "reduction phi is ");
+ print_gimple_stmt (dump_file, red->reduc_phi, 0, 0);
+ fprintf (dump_file, "reduction stmt is ");
+ print_gimple_stmt (dump_file, red->reduc_stmt, 0, 0);
+ }
+ }
+ }
+
+ /* The iterations of the loop may communicate only through bivs whose
+ iteration space can be distributed efficiently. */
+ for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple phi = gsi_stmt (gsi);
+ tree def = PHI_RESULT (phi);
+ affine_iv iv;
+
+ if (is_gimple_reg (def) && !simple_iv (loop, loop, def, &iv, true))
+ {
+ struct reduction_info *red;
+
+ red = reduction_phi (reduction_list, phi);
+ if (red == NULL)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ " FAILED: scalar dependency between iterations\n");
+ return false;
+ }
+ }
+ }
+
+
+ return true;
+}
+