aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vect-loop.c
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2018-10-04 17:50:52 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2018-10-04 17:50:52 +0000
commitf4ebbd243f887b3c5e01c65ad80a8f64a8261e61 (patch)
treef76bbe59cb30638b7432efe17c3ddd67c6378b9d /gcc/tree-vect-loop.c
parent7db960c5b6adad2fd11789870aa514985ea0da04 (diff)
downloadgcc-f4ebbd243f887b3c5e01c65ad80a8f64a8261e61.zip
gcc-f4ebbd243f887b3c5e01c65ad80a8f64a8261e61.tar.gz
gcc-f4ebbd243f887b3c5e01c65ad80a8f64a8261e61.tar.bz2
Report vectorization problems via a new opt_problem class
This is v3 of the patch; previous versions were: v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html This patch introduces a class opt_problem, along with wrapper classes for bool (opt_result) and for pointers (e.g. opt_loop_vec_info for loop_vec_info). opt_problem instances are created when an optimization problem is encountered, but only if dump_enabled_p. They are manually propagated up the callstack, and are manually reported at the "top level" of an optimization if dumping is enabled, to give the user a concise summary of the problem *after* the failure is reported. In particular, the location of the problematic statement is captured and emitted, rather than just the loop's location. For example: no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__ __volatile__("" : : : "memory"); Changed in v3: * This version bootstraps and passes regression testing (on x86_64-pc-linux-gnu). * added selftests, to exercise the opt_problem machinery * removed the "bool to opt_result" ctor, so that attempts to use e.g. return a bool from an opt_result-returning function will fail at compile time * use formatted printing within opt_problem ctor to replace the various dump_printf_loc calls * dropped i18n * changed the sense of vect_analyze_data_ref_dependence's return value (see the ChangeLog) * add MSG_PRIORITY_REEMITTED, so that -fopt-info can show the messages, without them messing up the counts in scan-tree-dump-times in DejaGnu tests gcc/ChangeLog: * Makefile.in (OBJS): Add opt-problem.o. * dump-context.h: Include "selftest.h. (selftest::temp_dump_context): New forward decl. (class dump_context): Make friend of class selftest::temp_dump_context. (dump_context::dump_loc_immediate): New decl. (class dump_pretty_printer): Move here from dumpfile.c. (class temp_dump_context): Move to namespace selftest. (temp_dump_context::temp_dump_context): Add param "forcibly_enable_dumping". (selftest::verify_dumped_text): (ASSERT_DUMPED_TEXT_EQ): Move here from dumpfile.c. (selftest::verify_item): (ASSERT_IS_TEXT): Move here from dumpfile.c. (ASSERT_IS_TREE): Likewise. (ASSERT_IS_GIMPLE): Likewise. * dumpfile.c (dump_context::dump_loc): Move immediate dumping to... (dump_context::dump_loc_immediate): ...this new function. (class dump_pretty_printer): Move to dump-context.h. (dump_switch_p_1): Don't enable MSG_PRIORITY_REEMITTED. (opt_info_switch_p_1): Enable MSG_PRIORITY_REEMITTED. (temp_dump_context::temp_dump_context): Move to "selftest" namespace. Add param "forcibly_enable_dumping", and use it to conditionalize the use of m_pp; (selftest::verify_dumped_text): Make non-static. (ASSERT_DUMPED_TEXT_EQ): Move to dump-context.h. (selftest::verify_item): Make non-static. (ASSERT_IS_TEXT): Move to dump-context.h. (ASSERT_IS_TREE): Likewise. (ASSERT_IS_GIMPLE): Likewise. (selftest::test_capture_of_dump_calls): Pass "true" for new param of temp_dump_context. * dumpfile.h (enum dump_flag): Add MSG_PRIORITY_REEMITTED, adding it to MSG_ALL_PRIORITIES. Update values of TDF_COMPARE_DEBUG and TDF_COMPARE_DEBUG. * opt-problem.cc: New file. * opt-problem.h: New file. * optinfo-emit-json.cc (selftest::test_building_json_from_dump_calls): Pass "true" for new param of temp_dump_context. * optinfo.cc (optinfo_kind_to_dump_flag): New function. (optinfo::emit_for_opt_problem): New function. (optinfo::emit): Clarity which emit_item is used. * optinfo.h (optinfo::get_dump_location): New accessor. (optinfo::emit_for_opt_problem): New decl. (optinfo::emit): Make const. * selftest-run-tests.c (selftest::run_tests): Call selftest::opt_problem_cc_tests. * selftest.h (selftest::opt_problem_cc_tests): New decl. * tree-data-ref.c (dr_analyze_innermost): Convert return type from bool to opt_result, converting fprintf messages to opt_result::failure_at calls. Add "stmt" param for use by the failure_at calls. (create_data_ref): Pass "stmt" to the dr_analyze_innermost call. (runtime_alias_check_p): Convert return type from bool to opt_result, converting dump_printf calls to opt_result::failure_at, using the statement DDR_A for their location. (find_data_references_in_stmt): Convert return type from bool to opt_result, converting "return false" to opt_result::failure_at with a new message. * tree-data-ref.h: Include "opt-problem.h". (dr_analyze_innermost): Convert return type from bool to opt_result, and add a const gimple * param. (find_data_references_in_stmt): Convert return type from bool to opt_result. (runtime_alias_check_p): Likewise. * tree-predcom.c (find_looparound_phi): Pass "init_stmt" to dr_analyze_innermost. * tree-vect-data-refs.c (vect_mark_for_runtime_alias_test): Convert return type from bool to opt_result, adding a message for the PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS zero case. (vect_analyze_data_ref_dependence): Convert return type from bool to opt_result. Change sense of return type from "false" effectively meaning "no problems" to "false" meaning a problem, so that "return false" becomes "return opt_result::success". Convert "return true" calls to opt_result::failure_at, using the location of statement A rather than vect_location. (vect_analyze_data_ref_dependences): Convert return type from bool to opt_result. (verify_data_ref_alignment): Likewise, converting dump_printf_loc calls to opt_result::failure_at, using the stmt location rather than vect_location. (vect_verify_datarefs_alignment): Convert return type from bool to opt_result. (vect_enhance_data_refs_alignment): Likewise. Split local "stat" into multiple more-tightly-scoped copies. (vect_analyze_data_refs_alignment): Convert return type from bool to opt_result. (vect_analyze_data_ref_accesses): Likewise, converting a "return false" to a "return opt_result::failure_at", adding a new message. (vect_prune_runtime_alias_test_list): Convert return type from bool to opt_result, converting dump_printf_loc to opt_result::failure_at. Add a %G to show the pertinent statement, and use the stmt's location rather than vect_location. (vect_find_stmt_data_reference): Convert return type from bool to opt_result, converting dump_printf_loc to opt_result::failure_at, using stmt's location. (vect_analyze_data_refs): Convert return type from bool to opt_result. Convert "return false" to "return opt_result::failure_at", adding messages as needed. * tree-vect-loop.c (vect_determine_vf_for_stmt_1): Convert return type from bool to opt_result. (vect_determine_vf_for_stmt): Likewise. (vect_determine_vectorization_factor): Likewise, converting dump_printf_loc to opt_result::failure_at, using location of phi rather than vect_location. (vect_analyze_loop_form_1): Convert return type from bool to opt_result, converting dump_printf_loc calls, retaining the use of vect_location. (vect_analyze_loop_form): Convert return type from loop_vec_info to opt_loop_vec_info. (vect_analyze_loop_operations): Convert return type from bool to opt_result, converting dump_printf_loc calls, using the location of phi/stmt rather than vect_location where available. Convert various "return false" to "return opt_result::failure_at" with "unsupported phi" messages. (vect_get_datarefs_in_loop): Convert return type from bool to opt_result. Add a message for the PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS failure. (vect_analyze_loop_2): Convert return type from bool to opt_result. Ensure "ok" is set to a opt_result::failure_at before each "goto again;", adding new messages where needed. Add "unsupported grouped {store|load}" messages. (vect_analyze_loop): Convert return type from loop_vec_info to opt_loop_vec_info. * tree-vect-slp.c (vect_analyze_slp): Convert return type from bool to opt_result. * tree-vect-stmts.c (process_use): Likewise, converting dump_printf_loc call and using stmt location, rather than vect_location. (vect_mark_stmts_to_be_vectorized): Likeise. (vect_analyze_stmt): Likewise, adding a %G. (vect_get_vector_types_for_stmt): Convert return type from bool to opt_result, converting dump_printf_loc calls and using stmt location, rather than vect_location. (vect_get_mask_type_for_stmt): Convert return type from tree to opt_tree, converting dump_printf_loc calls and using stmt location. * tree-vectorizer.c: Include "opt-problem.h. (try_vectorize_loop_1): Flag "Analyzing loop at" dump message as MSG_PRIORITY_INTERNALS. Convert local "loop_vinfo" from loop_vec_info to opt_loop_vec_info. If if fails, and dumping is enabled, use it to report at the top level "couldn't vectorize loop" followed by the problem. * tree-vectorizer.h (opt_loop_vec_info): New typedef. (vect_mark_stmts_to_be_vectorized): Convert return type from bool to opt_result. (vect_analyze_stmt): Likewise. (vect_get_vector_types_for_stmt): Likewise. (tree vect_get_mask_type_for_stmt): Likewise. (vect_analyze_data_ref_dependences): Likewise. (vect_enhance_data_refs_alignment): Likewise. (vect_analyze_data_refs_alignment): Likewise. (vect_verify_datarefs_alignment): Likewise. (vect_analyze_data_ref_accesses): Likewise. (vect_prune_runtime_alias_test_list): Likewise. (vect_find_stmt_data_reference): Likewise. (vect_analyze_data_refs): Likewise. (vect_analyze_loop): Convert return type from loop_vec_info to opt_loop_vec_info. (vect_analyze_loop_form): Likewise. (vect_analyze_slp): Convert return type from bool to opt_result. gcc/testsuite/ChangeLog: * gcc.dg/vect/nodump-vect-opt-info-2.c: New test. * gcc.dg/vect/vect-alias-check-4.c: Add "-fopt-info-vec-all" to dg-additional-options. Add dg-message and dg-missed directives to verify that -fopt-info messages are written at the correct locations. From-SVN: r264852
Diffstat (limited to 'gcc/tree-vect-loop.c')
-rw-r--r--gcc/tree-vect-loop.c442
1 files changed, 195 insertions, 247 deletions
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index fdac10b..6ea1e77 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -159,7 +159,7 @@ static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
statement. VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE
may already be set for general statements (not just data refs). */
-static bool
+static opt_result
vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
bool vectype_maybe_set_p,
poly_uint64 *vf,
@@ -173,13 +173,14 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
{
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location, "skip.\n");
- return true;
+ return opt_result::success ();
}
tree stmt_vectype, nunits_vectype;
- if (!vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
- &nunits_vectype))
- return false;
+ opt_result res = vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
+ &nunits_vectype);
+ if (!res)
+ return res;
if (stmt_vectype)
{
@@ -199,7 +200,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
if (nunits_vectype)
vect_update_max_nunits (vf, nunits_vectype);
- return true;
+ return opt_result::success ();
}
/* Subroutine of vect_determine_vectorization_factor. Set the vector
@@ -209,7 +210,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
add them to MASK_PRODUCERS. Return true on success or false if
something prevented vectorization. */
-static bool
+static opt_result
vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
vec<stmt_vec_info > *mask_producers)
{
@@ -217,8 +218,10 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
stmt_info->stmt);
- if (!vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers))
- return false;
+ opt_result res
+ = vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers);
+ if (!res)
+ return res;
if (STMT_VINFO_IN_PATTERN_P (stmt_info)
&& STMT_VINFO_RELATED_STMT (stmt_info))
@@ -237,18 +240,22 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
def_stmt_info->stmt);
if (!vect_determine_vf_for_stmt_1 (def_stmt_info, true,
vf, mask_producers))
- return false;
+ res = vect_determine_vf_for_stmt_1 (def_stmt_info, true,
+ vf, mask_producers);
+ if (!res)
+ return res;
}
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"==> examining pattern statement: %G",
stmt_info->stmt);
- if (!vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers))
- return false;
+ res = vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers);
+ if (!res)
+ return res;
}
- return true;
+ return opt_result::success ();
}
/* Function vect_determine_vectorization_factor
@@ -276,7 +283,7 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
}
*/
-static bool
+static opt_result
vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -320,14 +327,10 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
vectype = get_vectype_for_scalar_type (scalar_type);
if (!vectype)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported "
- "data-type %T\n",
- scalar_type);
- return false;
- }
+ return opt_result::failure_at (phi,
+ "not vectorized: unsupported "
+ "data-type %T\n",
+ scalar_type);
STMT_VINFO_VECTYPE (stmt_info) = vectype;
if (dump_enabled_p ())
@@ -349,9 +352,11 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
gsi_next (&si))
{
stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
- if (!vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
- &mask_producers))
- return false;
+ opt_result res
+ = vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
+ &mask_producers);
+ if (!res)
+ return res;
}
}
@@ -364,24 +369,20 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
}
if (known_le (vectorization_factor, 1U))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported data-type\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized: unsupported data-type\n");
LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
for (i = 0; i < mask_producers.length (); i++)
{
stmt_info = mask_producers[i];
- tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
+ opt_tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
if (!mask_type)
- return false;
+ return opt_result::propagate_failure (mask_type);
STMT_VINFO_VECTYPE (stmt_info) = mask_type;
}
- return true;
+ return opt_result::success ();
}
@@ -1145,7 +1146,7 @@ vect_compute_single_scalar_iteration_cost (loop_vec_info loop_vinfo)
- the number of iterations can be analyzed, i.e, a countable loop. The
niter could be analyzed under some assumptions. */
-bool
+opt_result
vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
tree *assumptions, tree *number_of_iterationsm1,
tree *number_of_iterations, gcond **inner_loop_cond)
@@ -1171,20 +1172,13 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
(exit-bb) */
if (loop->num_nodes != 2)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: control flow in loop.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " control flow in loop.\n");
if (empty_block_p (loop->header))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: empty loop.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized: empty loop.\n");
}
else
{
@@ -1209,75 +1203,60 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
as described above. */
if ((loop->inner)->inner || (loop->inner)->next)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: multiple nested loops.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " multiple nested loops.\n");
if (loop->num_nodes != 5)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: control flow in loop.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " control flow in loop.\n");
entryedge = loop_preheader_edge (innerloop);
if (entryedge->src != loop->header
|| !single_exit (innerloop)
|| single_exit (innerloop)->dest != EDGE_PRED (loop->latch, 0)->src)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported outerloop form.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " unsupported outerloop form.\n");
/* Analyze the inner-loop. */
tree inner_niterm1, inner_niter, inner_assumptions;
- if (! vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
- &inner_assumptions, &inner_niterm1,
- &inner_niter, NULL)
- /* Don't support analyzing niter under assumptions for inner
- loop. */
- || !integer_onep (inner_assumptions))
+ opt_result res
+ = vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
+ &inner_assumptions, &inner_niterm1,
+ &inner_niter, NULL);
+ if (!res)
{
if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"not vectorized: Bad inner loop.\n");
- return false;
+ return res;
}
+ /* Don't support analyzing niter under assumptions for inner
+ loop. */
+ if (!integer_onep (inner_assumptions))
+ return opt_result::failure_at (vect_location,
+ "not vectorized: Bad inner loop.\n");
+
if (!expr_invariant_in_loop_p (loop, inner_niter))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: inner-loop count not"
- " invariant.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized: inner-loop count not"
+ " invariant.\n");
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"Considering outer-loop vectorization.\n");
}
- if (!single_exit (loop)
- || EDGE_COUNT (loop->header->preds) != 2)
- {
- if (dump_enabled_p ())
- {
- if (!single_exit (loop))
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: multiple exits.\n");
- else if (EDGE_COUNT (loop->header->preds) != 2)
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: too many incoming edges.\n");
- }
- return false;
- }
+ if (!single_exit (loop))
+ return opt_result::failure_at (vect_location,
+ "not vectorized: multiple exits.\n");
+ if (EDGE_COUNT (loop->header->preds) != 2)
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " too many incoming edges.\n");
/* We assume that the loop exit condition is at the end of the loop. i.e,
that the loop is represented as a do-while (with a proper if-guard
@@ -1285,67 +1264,52 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
executable statements, and the latch is empty. */
if (!empty_block_p (loop->latch)
|| !gimple_seq_empty_p (phi_nodes (loop->latch)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: latch block not empty.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized: latch block not empty.\n");
/* Make sure the exit is not abnormal. */
edge e = single_exit (loop);
if (e->flags & EDGE_ABNORMAL)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: abnormal loop exit edge.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " abnormal loop exit edge.\n");
*loop_cond = vect_get_loop_niters (loop, assumptions, number_of_iterations,
number_of_iterationsm1);
if (!*loop_cond)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: complicated exit condition.\n");
- return false;
- }
+ return opt_result::failure_at
+ (vect_location,
+ "not vectorized: complicated exit condition.\n");
if (integer_zerop (*assumptions)
|| !*number_of_iterations
|| chrec_contains_undetermined (*number_of_iterations))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: number of iterations cannot be "
- "computed.\n");
- return false;
- }
+ return opt_result::failure_at
+ (*loop_cond,
+ "not vectorized: number of iterations cannot be computed.\n");
if (integer_zerop (*number_of_iterations))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: number of iterations = 0.\n");
- return false;
- }
+ return opt_result::failure_at
+ (*loop_cond,
+ "not vectorized: number of iterations = 0.\n");
- return true;
+ return opt_result::success ();
}
/* Analyze LOOP form and return a loop_vec_info if it is of suitable form. */
-loop_vec_info
+opt_loop_vec_info
vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
{
tree assumptions, number_of_iterations, number_of_iterationsm1;
gcond *loop_cond, *inner_loop_cond = NULL;
- if (! vect_analyze_loop_form_1 (loop, &loop_cond,
- &assumptions, &number_of_iterationsm1,
- &number_of_iterations, &inner_loop_cond))
- return NULL;
+ opt_result res
+ = vect_analyze_loop_form_1 (loop, &loop_cond,
+ &assumptions, &number_of_iterationsm1,
+ &number_of_iterations, &inner_loop_cond);
+ if (!res)
+ return opt_loop_vec_info::propagate_failure (res);
loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared);
LOOP_VINFO_NITERSM1 (loop_vinfo) = number_of_iterationsm1;
@@ -1387,7 +1351,7 @@ vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
gcc_assert (!loop->aux);
loop->aux = loop_vinfo;
- return loop_vinfo;
+ return opt_loop_vec_info::success (loop_vinfo);
}
@@ -1489,7 +1453,7 @@ vect_active_double_reduction_p (stmt_vec_info stmt_info)
Scan the loop stmts and make sure they are all vectorizable. */
-static bool
+static opt_result
vect_analyze_loop_operations (loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -1531,13 +1495,9 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
requires to actually do something here. */
if (STMT_VINFO_LIVE_P (stmt_info)
&& !vect_active_double_reduction_p (stmt_info))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "Unsupported loop-closed phi in "
- "outer-loop.\n");
- return false;
- }
+ return opt_result::failure_at (phi,
+ "Unsupported loop-closed phi"
+ " in outer-loop.\n");
/* If PHI is used in the outer loop, we check that its operand
is defined in the inner loop. */
@@ -1546,17 +1506,17 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
tree phi_op;
if (gimple_phi_num_args (phi) != 1)
- return false;
+ return opt_result::failure_at (phi, "unsupported phi");
phi_op = PHI_ARG_DEF (phi, 0);
stmt_vec_info op_def_info = loop_vinfo->lookup_def (phi_op);
if (!op_def_info)
- return false;
+ return opt_result::failure_at (phi, "unsupported phi");
if (STMT_VINFO_RELEVANT (op_def_info) != vect_used_in_outer
&& (STMT_VINFO_RELEVANT (op_def_info)
!= vect_used_in_outer_by_reduction))
- return false;
+ return opt_result::failure_at (phi, "unsupported phi");
}
continue;
@@ -1567,13 +1527,10 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
if ((STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_scope
|| STMT_VINFO_LIVE_P (stmt_info))
&& STMT_VINFO_DEF_TYPE (stmt_info) != vect_induction_def)
- {
- /* A scalar-dependence cycle that we don't support. */
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: scalar dependence cycle.\n");
- return false;
- }
+ /* A scalar-dependence cycle that we don't support. */
+ return opt_result::failure_at (phi,
+ "not vectorized:"
+ " scalar dependence cycle.\n");
if (STMT_VINFO_RELEVANT_P (stmt_info))
{
@@ -1597,24 +1554,25 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
&cost_vec);
if (!ok)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: relevant phi not "
- "supported: %G", phi);
- return false;
- }
+ return opt_result::failure_at (phi,
+ "not vectorized: relevant phi not "
+ "supported: %G",
+ static_cast <gimple *> (phi));
}
for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
gsi_next (&si))
{
gimple *stmt = gsi_stmt (si);
- if (!gimple_clobber_p (stmt)
- && !vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
+ if (!gimple_clobber_p (stmt))
+ {
+ opt_result res
+ = vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
&need_to_vectorize,
- NULL, NULL, &cost_vec))
- return false;
+ NULL, NULL, &cost_vec);
+ if (!res)
+ return res;
+ }
}
} /* bbs */
@@ -1631,14 +1589,12 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"All the computation can be taken out of the loop.\n");
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: redundant loop. no profit to "
- "vectorize.\n");
- return false;
+ return opt_result::failure_at
+ (vect_location,
+ "not vectorized: redundant loop. no profit to vectorize.\n");
}
- return true;
+ return opt_result::success ();
}
/* Analyze the cost of the loop described by LOOP_VINFO. Decide if it
@@ -1736,7 +1692,7 @@ vect_analyze_loop_costing (loop_vec_info loop_vinfo)
return 1;
}
-static bool
+static opt_result
vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
vec<data_reference_p> *datarefs,
unsigned int *n_stmts)
@@ -1750,7 +1706,8 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
if (is_gimple_debug (stmt))
continue;
++(*n_stmts);
- if (!vect_find_stmt_data_reference (loop, stmt, datarefs))
+ opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs);
+ if (!res)
{
if (is_gimple_call (stmt) && loop->safelen)
{
@@ -1782,15 +1739,16 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
}
}
}
- return false;
+ return res;
}
/* If dependence analysis will give up due to the limit on the
number of datarefs stop here and fail fatally. */
if (datarefs->length ()
> (unsigned)PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS))
- return false;
+ return opt_result::failure_at (stmt, "exceeded param "
+ "loop-max-datarefs-for-datadeps\n");
}
- return true;
+ return opt_result::success ();
}
/* Function vect_analyze_loop_2.
@@ -1798,10 +1756,10 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
Apply a set of analyses on LOOP, and create a loop_vec_info struct
for it. The different analyses will record information in the
loop_vec_info struct. */
-static bool
+static opt_result
vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
{
- bool ok;
+ opt_result ok = opt_result::success ();
int res;
unsigned int max_vf = MAX_VECTORIZATION_FACTOR;
poly_uint64 min_vf = 2;
@@ -1817,16 +1775,18 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
/* Gather the data references and count stmts in the loop. */
if (!LOOP_VINFO_DATAREFS (loop_vinfo).exists ())
{
- if (!vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
- &LOOP_VINFO_DATAREFS (loop_vinfo),
- n_stmts))
+ opt_result res
+ = vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
+ &LOOP_VINFO_DATAREFS (loop_vinfo),
+ n_stmts);
+ if (!res)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"not vectorized: loop contains function "
"calls or data references that cannot "
"be analyzed\n");
- return false;
+ return res;
}
loop_vinfo->shared->save_datarefs ();
}
@@ -1842,7 +1802,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"bad data references.\n");
- return false;
+ return ok;
}
/* Classify all cross-iteration scalar data-flow cycles.
@@ -1862,7 +1822,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"bad data access.\n");
- return false;
+ return ok;
}
/* Data-flow analysis to detect stmts that do not need to be vectorized. */
@@ -1873,7 +1833,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"unexpected pattern.\n");
- return false;
+ return ok;
}
/* While the rest of the analysis below depends on it in some way. */
@@ -1885,15 +1845,16 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
FORNOW: fail at the first data dependence that we encounter. */
ok = vect_analyze_data_ref_dependences (loop_vinfo, &max_vf);
- if (!ok
- || (max_vf != MAX_VECTORIZATION_FACTOR
- && maybe_lt (max_vf, min_vf)))
+ if (!ok)
{
if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "bad data dependence.\n");
- return false;
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "bad data dependence.\n");
+ return ok;
}
+ if (max_vf != MAX_VECTORIZATION_FACTOR
+ && maybe_lt (max_vf, min_vf))
+ return opt_result::failure_at (vect_location, "bad data dependence.\n");
LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) = max_vf;
ok = vect_determine_vectorization_factor (loop_vinfo);
@@ -1902,16 +1863,11 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"can't determine vectorization factor.\n");
- return false;
+ return ok;
}
if (max_vf != MAX_VECTORIZATION_FACTOR
&& maybe_lt (max_vf, LOOP_VINFO_VECT_FACTOR (loop_vinfo)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "bad data dependence.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location, "bad data dependence.\n");
/* Compute the scalar iteration cost. */
vect_compute_single_scalar_iteration_cost (loop_vinfo);
@@ -1922,7 +1878,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
/* Check the SLP opportunities in the loop, analyze and build SLP trees. */
ok = vect_analyze_slp (loop_vinfo, *n_stmts);
if (!ok)
- return false;
+ return ok;
/* If there are any SLP instances mark them as pure_slp. */
bool slp = vect_make_slp_decision (loop_vinfo);
@@ -1969,7 +1925,7 @@ start_over:
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"bad data alignment.\n");
- return false;
+ return ok;
}
/* Prune the list of ddrs to be tested at run-time by versioning for alias.
@@ -1977,7 +1933,7 @@ start_over:
since we use grouping information gathered by interleaving analysis. */
ok = vect_prune_runtime_alias_test_list (loop_vinfo);
if (!ok)
- return false;
+ return ok;
/* Do not invoke vect_enhance_data_refs_alignment for epilogue
vectorization, since we do not want to add extra peeling or
@@ -1989,12 +1945,7 @@ start_over:
else
ok = vect_verify_datarefs_alignment (loop_vinfo);
if (!ok)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "bad data alignment.\n");
- return false;
- }
+ return ok;
if (slp)
{
@@ -2004,7 +1955,11 @@ start_over:
unsigned old_size = LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length ();
vect_slp_analyze_operations (loop_vinfo);
if (LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length () != old_size)
- goto again;
+ {
+ ok = opt_result::failure_at (vect_location,
+ "unsupported SLP instances\n");
+ goto again;
+ }
}
/* Scan all the remaining operations in the loop that are not subject
@@ -2015,7 +1970,7 @@ start_over:
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"bad operation or unsupported loop bound.\n");
- return false;
+ return ok;
}
/* Decide whether to use a fully-masked loop for this vectorization
@@ -2044,26 +1999,22 @@ start_over:
tree scalar_niters = LOOP_VINFO_NITERSM1 (loop_vinfo);
if (known_lt (wi::to_widest (scalar_niters), vf))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "loop has no enough iterations to support"
- " peeling for gaps.\n");
- return false;
- }
+ return opt_result::failure_at (vect_location,
+ "loop has no enough iterations to"
+ " support peeling for gaps.\n");
}
/* Check the costings of the loop make vectorizing worthwhile. */
res = vect_analyze_loop_costing (loop_vinfo);
if (res < 0)
- goto again;
- if (!res)
{
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "Loop costings not worthwhile.\n");
- return false;
+ ok = opt_result::failure_at (vect_location,
+ "Loop costings may not be worthwhile.\n");
+ goto again;
}
+ if (!res)
+ return opt_result::failure_at (vect_location,
+ "Loop costings not worthwhile.\n");
/* Decide whether we need to create an epilogue loop to handle
remaining scalar iterations. */
@@ -2112,10 +2063,9 @@ start_over:
single_exit (LOOP_VINFO_LOOP
(loop_vinfo))))
{
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: can't create required "
- "epilog loop\n");
+ ok = opt_result::failure_at (vect_location,
+ "not vectorized: can't create required "
+ "epilog loop\n");
goto again;
}
}
@@ -2154,17 +2104,20 @@ start_over:
LOOP_VINFO_VECT_FACTOR (loop_vinfo)));
/* Ok to vectorize! */
- return true;
+ return opt_result::success ();
again:
+ /* Ensure that "ok" is false (with an opt_problem if dumping is enabled). */
+ gcc_assert (!ok);
+
/* Try again with SLP forced off but if we didn't do any SLP there is
no point in re-trying. */
if (!slp)
- return false;
+ return ok;
/* If there are reduction chains re-trying will fail anyway. */
if (! LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo).is_empty ())
- return false;
+ return ok;
/* Likewise if the grouped loads or stores in the SLP cannot be handled
via interleaving or lane instructions. */
@@ -2183,7 +2136,8 @@ again:
if (! vect_store_lanes_supported (vectype, size, false)
&& ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)
&& ! vect_grouped_store_supported (vectype, size))
- return false;
+ return opt_result::failure_at (vinfo->stmt,
+ "unsupported grouped store\n");
FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), j, node)
{
vinfo = SLP_TREE_SCALAR_STMTS (node)[0];
@@ -2194,7 +2148,8 @@ again:
if (! vect_load_lanes_supported (vectype, size, false)
&& ! vect_grouped_load_supported (vectype, single_element_p,
size))
- return false;
+ return opt_result::failure_at (vinfo->stmt,
+ "unsupported grouped load\n");
}
}
@@ -2263,11 +2218,10 @@ again:
for it. The different analyses will record information in the
loop_vec_info struct. If ORIG_LOOP_VINFO is not NULL epilogue must
be vectorized. */
-loop_vec_info
+opt_loop_vec_info
vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
vec_info_shared *shared)
{
- loop_vec_info loop_vinfo;
auto_vector_sizes vector_sizes;
/* Autodetect first vector size we try. */
@@ -2280,35 +2234,28 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
if (loop_outer (loop)
&& loop_vec_info_for_loop (loop_outer (loop))
&& LOOP_VINFO_VECTORIZABLE_P (loop_vec_info_for_loop (loop_outer (loop))))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "outer-loop already vectorized.\n");
- return NULL;
- }
+ return opt_loop_vec_info::failure_at (vect_location,
+ "outer-loop already vectorized.\n");
if (!find_loop_nest (loop, &shared->loop_nest))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: loop nest containing two "
- "or more consecutive inner loops cannot be "
- "vectorized\n");
- return NULL;
- }
+ return opt_loop_vec_info::failure_at
+ (vect_location,
+ "not vectorized: loop nest containing two or more consecutive inner"
+ " loops cannot be vectorized\n");
unsigned n_stmts = 0;
poly_uint64 autodetected_vector_size = 0;
while (1)
{
/* Check the CFG characteristics of the loop (nesting, entry/exit). */
- loop_vinfo = vect_analyze_loop_form (loop, shared);
+ opt_loop_vec_info loop_vinfo
+ = vect_analyze_loop_form (loop, shared);
if (!loop_vinfo)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"bad loop form.\n");
- return NULL;
+ return loop_vinfo;
}
bool fatal = false;
@@ -2316,7 +2263,8 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
if (orig_loop_vinfo)
LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = orig_loop_vinfo;
- if (vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts))
+ opt_result res = vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts);
+ if (res)
{
LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
@@ -2335,7 +2283,7 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
if (fatal
|| next_size == vector_sizes.length ()
|| known_eq (current_vector_size, 0U))
- return NULL;
+ return opt_loop_vec_info::propagate_failure (res);
/* Try the next biggest vector size. */
current_vector_size = vector_sizes[next_size++];