+2018-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * 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.
+
2018-10-04 David Malcolm <dmalcolm@redhat.com>
* doc/invoke.texi (-fopt-info): Document new "internals"
omp-grid.o \
omp-low.o \
omp-simd-clone.o \
+ opt-problem.o \
optabs.o \
optabs-libfuncs.o \
optabs-query.o \
#include "dumpfile.h"
#include "pretty-print.h"
+#include "selftest.h"
+
+namespace selftest { class temp_dump_context; }
/* A class for handling the various dump_* calls.
class dump_context
{
- friend class temp_dump_context;
+ friend class selftest::temp_dump_context;
+
public:
static dump_context &get () { return *s_current; }
void refresh_dumps_are_enabled ();
void dump_loc (dump_flags_t dump_kind, const dump_location_t &loc);
+ void dump_loc_immediate (dump_flags_t dump_kind, const dump_location_t &loc);
void dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
gimple *gs, int spc);
static dump_context s_default;
};
+/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
+ In particular, the formatted chunks are captured as optinfo_item instances,
+ thus retaining metadata about the entities being dumped (e.g. source
+ locations), rather than just as plain text. */
+
+class dump_pretty_printer : public pretty_printer
+{
+public:
+ dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
+
+ void emit_items (optinfo *dest);
+
+private:
+ /* Information on an optinfo_item that was generated during phase 2 of
+ formatting. */
+ struct stashed_item
+ {
+ stashed_item (const char **buffer_ptr_, optinfo_item *item_)
+ : buffer_ptr (buffer_ptr_), item (item_) {}
+ const char **buffer_ptr;
+ optinfo_item *item;
+ };
+
+ static bool format_decoder_cb (pretty_printer *pp, text_info *text,
+ const char *spec, int /*precision*/,
+ bool /*wide*/, bool /*set_locus*/,
+ bool /*verbose*/, bool */*quoted*/,
+ const char **buffer_ptr);
+
+ bool decode_format (text_info *text, const char *spec,
+ const char **buffer_ptr);
+
+ void stash_item (const char **buffer_ptr, optinfo_item *item);
+
+ void emit_any_pending_textual_chunks (optinfo *dest);
+
+ void emit_item (optinfo_item *item, optinfo *dest);
+
+ dump_context *m_context;
+ dump_flags_t m_dump_kind;
+ auto_vec<stashed_item> m_stashed_items;
+};
+
#if CHECKING_P
+namespace selftest {
+
/* An RAII-style class for use in selftests for temporarily using a different
dump_context. */
{
public:
temp_dump_context (bool forcibly_enable_optinfo,
+ bool forcibly_enable_dumping,
dump_flags_t test_pp_flags);
~temp_dump_context ();
dump_context *m_saved;
};
+/* Implementation detail of ASSERT_DUMPED_TEXT_EQ. */
+
+extern void verify_dumped_text (const location &loc,
+ temp_dump_context *context,
+ const char *expected_text);
+
+/* Verify that the text dumped so far in CONTEXT equals
+ EXPECTED_TEXT.
+ As a side-effect, the internal buffer is 0-terminated. */
+
+#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT) \
+ SELFTEST_BEGIN_STMT \
+ verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
+ SELFTEST_END_STMT
+
+
+/* Verify that ITEM has the expected values. */
+
+void
+verify_item (const location &loc,
+ const optinfo_item *item,
+ enum optinfo_item_kind expected_kind,
+ location_t expected_location,
+ const char *expected_text);
+
+/* Verify that ITEM is a text item, with EXPECTED_TEXT. */
+
+#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
+ SELFTEST_BEGIN_STMT \
+ verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
+ UNKNOWN_LOCATION, (EXPECTED_TEXT)); \
+ SELFTEST_END_STMT
+
+/* Verify that ITEM is a tree item, with the expected values. */
+
+#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
+ SELFTEST_BEGIN_STMT \
+ verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
+ (EXPECTED_LOCATION), (EXPECTED_TEXT)); \
+ SELFTEST_END_STMT
+
+/* Verify that ITEM is a gimple item, with the expected values. */
+
+#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
+ SELFTEST_BEGIN_STMT \
+ verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
+ (EXPECTED_LOCATION), (EXPECTED_TEXT)); \
+ SELFTEST_END_STMT
+
+} // namespace selftest
+
#endif /* CHECKING_P */
#endif /* GCC_DUMP_CONTEXT_H */
{
end_any_optinfo ();
+ dump_loc_immediate (dump_kind, loc);
+
+ if (optinfo_enabled_p ())
+ {
+ optinfo &info = begin_next_optinfo (loc);
+ info.handle_dump_file_kind (dump_kind);
+ }
+}
+
+/* As dump_loc above, but without starting a new optinfo. */
+
+void
+dump_context::dump_loc_immediate (dump_flags_t dump_kind,
+ const dump_location_t &loc)
+{
location_t srcloc = loc.get_location_t ();
if (dump_file && apply_dump_filter_p (dump_kind, pflags))
/* Support for temp_dump_context in selftests. */
if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
::dump_loc (dump_kind, m_test_pp, srcloc);
-
- if (optinfo_enabled_p ())
- {
- optinfo &info = begin_next_optinfo (loc);
- info.handle_dump_file_kind (dump_kind);
- }
}
/* Make an item for the given dump call, equivalent to print_gimple_stmt. */
dump_generic_expr (dump_kind, extra_dump_flags, t);
}
-/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
- In particular, the formatted chunks are captured as optinfo_item instances,
- thus retaining metadata about the entities being dumped (e.g. source
- locations), rather than just as plain text. */
-
-class dump_pretty_printer : public pretty_printer
-{
-public:
- dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
-
- void emit_items (optinfo *dest);
-
-private:
- /* Information on an optinfo_item that was generated during phase 2 of
- formatting. */
- struct stashed_item
- {
- stashed_item (const char **buffer_ptr_, optinfo_item *item_)
- : buffer_ptr (buffer_ptr_), item (item_) {}
- const char **buffer_ptr;
- optinfo_item *item;
- };
-
- static bool format_decoder_cb (pretty_printer *pp, text_info *text,
- const char *spec, int /*precision*/,
- bool /*wide*/, bool /*set_locus*/,
- bool /*verbose*/, bool */*quoted*/,
- const char **buffer_ptr);
-
- bool decode_format (text_info *text, const char *spec,
- const char **buffer_ptr);
-
- void stash_item (const char **buffer_ptr, optinfo_item *item);
-
- void emit_any_pending_textual_chunks (optinfo *dest);
-
- void emit_item (optinfo_item *item, optinfo *dest);
-
- dump_context *m_context;
- dump_flags_t m_dump_kind;
- auto_vec<stashed_item> m_stashed_items;
-};
-
/* dump_pretty_printer's ctor. */
dump_pretty_printer::dump_pretty_printer (dump_context *context,
return 0;
ptr = option_value;
- flags = MSG_ALL_PRIORITIES;
+
+ /* Retain "user-facing" and "internals" messages, but filter out
+ those from an opt_problem being re-emitted at the top level
+ (MSG_PRIORITY_REEMITTED), so as to avoid duplicate messages
+ messing up scan-tree-dump-times" in DejaGnu tests. */
+ flags = MSG_PRIORITY_USER_FACING | MSG_PRIORITY_INTERNALS;
while (*ptr)
{
*filename = NULL;
/* Default to filtering out "internals" messages, and retaining
- "user-facing" messages. */
- *flags = MSG_PRIORITY_USER_FACING;
+ "user-facing" messages, and those from an opt_problem being
+ re-emitted at the top level. */
+ *flags = MSG_PRIORITY_USER_FACING | MSG_PRIORITY_REEMITTED;
*optgroup_flags = OPTGROUP_NONE;
#if CHECKING_P
+namespace selftest {
+
/* temp_dump_context's ctor. Temporarily override the dump_context
(to forcibly enable optinfo-generation). */
temp_dump_context::temp_dump_context (bool forcibly_enable_optinfo,
+ bool forcibly_enable_dumping,
dump_flags_t test_pp_flags)
-
: m_context (),
m_saved (&dump_context ().get ())
{
dump_context::s_current = &m_context;
m_context.m_forcibly_enable_optinfo = forcibly_enable_optinfo;
- m_context.m_test_pp = &m_pp;
- m_context.m_test_pp_flags = test_pp_flags;
+ /* Conditionally enable the test dump, so that we can verify both the
+ dump_enabled_p and the !dump_enabled_p cases in selftests. */
+ if (forcibly_enable_dumping)
+ {
+ m_context.m_test_pp = &m_pp;
+ m_context.m_test_pp_flags = test_pp_flags;
+ }
dump_context::get ().refresh_dumps_are_enabled ();
}
return pp_formatted_text (&m_pp);
}
-namespace selftest {
-
/* Verify that the dump_location_t constructors capture the source location
at which they were called (provided that the build compiler is sufficiently
recent). */
EXPECTED_TEXT, using LOC for the location of any failure.
As a side-effect, the internal buffer is 0-terminated. */
-static void
+void
verify_dumped_text (const location &loc,
temp_dump_context *context,
const char *expected_text)
expected_text);
}
-/* Verify that the text dumped so far in CONTEXT equals
- EXPECTED_TEXT.
- As a side-effect, the internal buffer is 0-terminated. */
-
-#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT) \
- SELFTEST_BEGIN_STMT \
- verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
- SELFTEST_END_STMT
-
/* Verify that ITEM has the expected values. */
-static void
+void
verify_item (const location &loc,
const optinfo_item *item,
enum optinfo_item_kind expected_kind,
ASSERT_STREQ_AT (loc, item->get_text (), expected_text);
}
-/* Verify that ITEM is a text item, with EXPECTED_TEXT. */
-
-#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
- SELFTEST_BEGIN_STMT \
- verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
- UNKNOWN_LOCATION, (EXPECTED_TEXT)); \
- SELFTEST_END_STMT
-
-/* Verify that ITEM is a tree item, with the expected values. */
-
-#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
- SELFTEST_BEGIN_STMT \
- verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
- (EXPECTED_LOCATION), (EXPECTED_TEXT)); \
- SELFTEST_END_STMT
-
-/* Verify that ITEM is a gimple item, with the expected values. */
-
-#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
- SELFTEST_BEGIN_STMT \
- verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
- (EXPECTED_LOCATION), (EXPECTED_TEXT)); \
- SELFTEST_END_STMT
-
/* Verify that calls to the dump_* API are captured and consolidated into
optimization records. */
/* Test of dump_printf. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
/* Test of dump_printf with %T. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
/* Test of dump_printf with %E. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_printf (MSG_NOTE, "gimple: %E", stmt);
/* Test of dump_printf with %G. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_printf (MSG_NOTE, "gimple: %G", stmt);
- multiple dump-specific format codes: some consecutive, others
separated by text, trailing text after the final one. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
" %i consecutive %E%E after\n",
/* Tree, via dump_generic_expr. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
/* Tree, via dump_generic_expr_loc. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, integer_one_node);
{
/* dump_gimple_stmt_loc. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
/* dump_gimple_stmt. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
/* dump_gimple_expr_loc. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
/* dump_gimple_expr. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
/* poly_int. */
{
- temp_dump_context tmp (with_optinfo,
+ temp_dump_context tmp (with_optinfo, true,
MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
dump_dec (MSG_NOTE, poly_int64 (42));
if (j / 2)
dump_filter |= MSG_PRIORITY_INTERNALS;
- temp_dump_context tmp (with_optinfo, dump_filter);
+ temp_dump_context tmp (with_optinfo, true, dump_filter);
/* Emit various messages, mostly with implicit priority. */
dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, stmt,
{
/* MSG_OPTIMIZED_LOCATIONS. */
{
- temp_dump_context tmp (true, MSG_ALL_KINDS);
+ temp_dump_context tmp (true, true, MSG_ALL_KINDS);
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
OPTINFO_KIND_SUCCESS);
/* MSG_MISSED_OPTIMIZATION. */
{
- temp_dump_context tmp (true, MSG_ALL_KINDS);
+ temp_dump_context tmp (true, true, MSG_ALL_KINDS);
dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
OPTINFO_KIND_FAILURE);
/* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump calls. */
{
- temp_dump_context tmp (false,
+ temp_dump_context tmp (false, true,
MSG_OPTIMIZED_LOCATIONS | MSG_ALL_PRIORITIES);
dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
{
/* Implicitly supplied for messages within nested dump scopes. */
MSG_PRIORITY_INTERNALS = (1 << 26),
+ /* Supplied when an opt_problem generated in a nested scope is re-emitted
+ at the top-level. We want to default to showing these in -fopt-info
+ output, but to *not* show them in dump files, as the message would be
+ shown twice, messing up "scan-tree-dump-times" in DejaGnu tests. */
+ MSG_PRIORITY_REEMITTED = (1 << 27),
+
/* Mask for selecting MSG_PRIORITY_* flags. */
MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
- | MSG_PRIORITY_INTERNALS),
+ | MSG_PRIORITY_INTERNALS
+ | MSG_PRIORITY_REEMITTED),
/* Dumping for -fcompare-debug. */
- TDF_COMPARE_DEBUG = (1 << 27),
+ TDF_COMPARE_DEBUG = (1 << 28),
/* All values. */
- TDF_ALL_VALUES = (1 << 28) - 1
+ TDF_ALL_VALUES = (1 << 29) - 1
};
/* Dump flags type. */
--- /dev/null
+/* Rich optional information on why an optimization wasn't possible.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "pretty-print.h"
+#include "opt-problem.h"
+#include "dump-context.h"
+#include "tree-pass.h"
+#include "selftest.h"
+
+/* opt_problem's ctor.
+
+ Use FMT and AP to emit a message to the "immediate" dump destinations
+ as if via:
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, ...)
+
+ The optinfo_item instances are not emitted yet. Instead, they
+ are retained internally so that the message can be replayed and
+ emitted when this problem is handled, higher up the call stack. */
+
+opt_problem::opt_problem (const dump_location_t &loc,
+ const char *fmt, va_list *ap)
+: m_optinfo (loc, OPTINFO_KIND_FAILURE, current_pass)
+{
+ /* We shouldn't be bothering to construct these objects if
+ dumping isn't enabled. */
+ gcc_assert (dump_enabled_p ());
+
+ /* Update the singleton. */
+ delete s_the_problem;
+ s_the_problem = this;
+
+ /* Print the location to the "immediate" dump destinations. */
+ dump_context &dc = dump_context::get ();
+ dc.dump_loc (MSG_MISSED_OPTIMIZATION, loc);
+
+ /* Print the formatted string to this opt_problem's optinfo, dumping
+ the items to the "immediate" dump destinations, and storing items
+ for later retrieval. */
+ {
+ dump_pretty_printer pp (&dump_context::get (), MSG_MISSED_OPTIMIZATION);
+
+ text_info text;
+ text.err_no = errno;
+ text.args_ptr = ap;
+ text.format_spec = fmt; /* No i18n is performed. */
+
+ /* Phases 1 and 2, using pp_format. */
+ pp_format (&pp, &text);
+
+ /* Phase 3: dump the items to the "immediate" dump destinations,
+ and storing them into m_optinfo for later retrieval. */
+ pp.emit_items (&m_optinfo);
+ }
+}
+
+/* Emit this problem and delete it, clearing the current opt_problem. */
+
+void
+opt_problem::emit_and_clear ()
+{
+ gcc_assert (this == s_the_problem);
+
+ m_optinfo.emit_for_opt_problem ();
+
+ delete this;
+ s_the_problem = NULL;
+}
+
+/* The singleton opt_problem *. */
+
+opt_problem *opt_problem::s_the_problem;
+
+#if CHECKING_P
+
+namespace selftest {
+
+static opt_result
+function_that_succeeds ()
+{
+ return opt_result::success ();
+}
+
+/* Verify that opt_result::success works. */
+
+static void
+test_opt_result_success ()
+{
+ /* Run all tests twice, with and then without dumping enabled. */
+ for (int i = 0 ; i < 2; i++)
+ {
+ bool with_dumping = (i == 0);
+
+ temp_dump_context tmp (with_dumping, with_dumping,
+ MSG_ALL_KINDS | MSG_ALL_PRIORITIES);
+
+ if (with_dumping)
+ gcc_assert (dump_enabled_p ());
+ else
+ gcc_assert (!dump_enabled_p ());
+
+ opt_result res = function_that_succeeds ();
+
+ /* Verify that "success" can be used as a "true" boolean. */
+ ASSERT_TRUE (res);
+
+ /* Verify the underlying opt_wrapper<bool>. */
+ ASSERT_TRUE (res.get_result ());
+ ASSERT_EQ (res.get_problem (), NULL);
+
+ /* Nothing should have been dumped. */
+ ASSERT_DUMPED_TEXT_EQ (tmp, "");
+ optinfo *info = tmp.get_pending_optinfo ();
+ ASSERT_EQ (info, NULL);
+ }
+}
+
+/* Example of a function that fails, with a non-trivial
+ pre-canned error message. */
+
+static opt_result
+function_that_fails (const greturn *stmt)
+{
+ gcc_assert (stmt);
+ gcc_assert (gimple_return_retval (stmt));
+
+ AUTO_DUMP_SCOPE ("function_that_fails", stmt);
+
+ return opt_result::failure_at (stmt,
+ "can't handle return type: %T for stmt: %G",
+ TREE_TYPE (gimple_return_retval (stmt)),
+ static_cast <const gimple *> (stmt));
+}
+
+/* Example of a function that indirectly fails. */
+
+static opt_result
+function_that_indirectly_fails (const greturn *stmt)
+{
+ AUTO_DUMP_SCOPE ("function_that_indirectly_fails", stmt);
+
+ opt_result res = function_that_fails (stmt);
+ if (!res)
+ return res;
+ return opt_result::success ();
+}
+
+/* Verify that opt_result::failure_at works.
+ Simulate a failure handling a stmt at one location whilst considering
+ an optimization that's notionally at another location (as a microcosm
+ of e.g. a problematic statement within a loop that prevents loop
+ vectorization). */
+
+static void
+test_opt_result_failure_at (const line_table_case &case_)
+{
+ /* Generate a location_t for testing. */
+ line_table_test ltt (case_);
+ const line_map_ordinary *ord_map
+ = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
+ "test.c", 0));
+ linemap_line_start (line_table, 5, 100);
+
+ /* A test location: "test.c:5:10". */
+ const location_t line_5 = linemap_position_for_column (line_table, 10);
+
+ /* Another test location: "test.c:6:12". */
+ const location_t line_6
+ = linemap_position_for_line_and_column (line_table, ord_map, 6, 12);
+
+ if (line_6 > LINE_MAP_MAX_LOCATION_WITH_COLS)
+ return;
+
+ /* Generate statements using "line_5" and "line_6" for testing. */
+ greturn *stmt_at_5 = gimple_build_return (integer_one_node);
+ gimple_set_location (stmt_at_5, line_5);
+
+ greturn *stmt_at_6 = gimple_build_return (integer_zero_node);
+ gimple_set_location (stmt_at_6, line_6);
+
+ /* Run with and then without dumping enabled. */
+ for (int i = 0; i < 2; i++)
+ {
+ bool with_dumping = (i == 0);
+
+ /* Run with all 4 combinations of
+ with and without MSG_PRIORITY_INTERNALS and
+ with and without MSG_PRIORITY_REEMITTED. */
+ for (int j = 0; j < 4; j++)
+ {
+ dump_flags_t filter = MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING;
+ if (j / 2)
+ filter |= MSG_PRIORITY_INTERNALS;
+ if (j % 2)
+ filter |= MSG_PRIORITY_REEMITTED;
+
+ temp_dump_context tmp (with_dumping, with_dumping, filter);
+
+ if (with_dumping)
+ gcc_assert (dump_enabled_p ());
+ else
+ gcc_assert (!dump_enabled_p ());
+
+ /* Simulate attempting to optimize "stmt_at_6". */
+ opt_result res = function_that_indirectly_fails (stmt_at_6);
+
+ /* Verify that "failure" can be used as a "false" boolean. */
+ ASSERT_FALSE (res);
+
+ /* Verify the underlying opt_wrapper<bool>. */
+ ASSERT_FALSE (res.get_result ());
+ opt_problem *problem = res.get_problem ();
+
+ if (with_dumping)
+ {
+ ASSERT_NE (problem, NULL);
+ ASSERT_EQ (problem->get_dump_location ().get_location_t (),
+ line_6);
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+ /* Verify that the problem captures the implementation location
+ it was emitted from. */
+ const dump_impl_location_t &impl_location
+ = problem->get_dump_location ().get_impl_location ();
+ ASSERT_STR_CONTAINS (impl_location.m_function,
+ "function_that_fails");
+#endif
+
+ /* Verify that the underlying dump items are retained in the
+ opt_problem. */
+ const optinfo &info = problem->get_optinfo ();
+ ASSERT_EQ (info.get_dump_location ().get_location_t (), line_6);
+ ASSERT_EQ (info.num_items (), 4);
+ ASSERT_IS_TEXT (info.get_item (0), "can't handle return type: ");
+ ASSERT_IS_TREE (info.get_item (1), UNKNOWN_LOCATION, "int");
+ ASSERT_IS_TEXT (info.get_item (2), " for stmt: ");
+ ASSERT_IS_GIMPLE (info.get_item (3), line_6, "return 0;\n");
+
+ /* ...but not in the dump_context's pending_optinfo. */
+ ASSERT_EQ (tmp.get_pending_optinfo (), NULL);
+
+ /* Simulate emitting a high-level summary message, followed
+ by the problem. */
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt_at_5,
+ "can't optimize loop\n");
+ problem->emit_and_clear ();
+ ASSERT_EQ (res.get_problem (), NULL);
+
+ /* Verify that the error message was dumped (when the failure
+ occurred). We can't use a switch here as not all of the
+ values are const expressions (using C++98). */
+ dump_flags_t effective_filter
+ = filter & (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED);
+ if (effective_filter
+ == (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED))
+ /* The -fopt-info-internals case. */
+ ASSERT_DUMPED_TEXT_EQ
+ (tmp,
+ "test.c:6:12: note: === function_that_indirectly_fails"
+ " ===\n"
+ "test.c:6:12: note: === function_that_fails ===\n"
+ "test.c:6:12: missed: can't handle return type: int"
+ " for stmt: return 0;\n"
+ "test.c:5:10: missed: can't optimize loop\n"
+ "test.c:6:12: missed: can't handle return type: int"
+ " for stmt: return 0;\n");
+ else if (effective_filter == MSG_PRIORITY_INTERNALS)
+ /* The default for dump files. */
+ ASSERT_DUMPED_TEXT_EQ
+ (tmp,
+ "test.c:6:12: note: === function_that_indirectly_fails"
+ " ===\n"
+ "test.c:6:12: note: === function_that_fails ===\n"
+ "test.c:6:12: missed: can't handle return type: int"
+ " for stmt: return 0;\n"
+ "test.c:5:10: missed: can't optimize loop\n");
+ else if (effective_filter == MSG_PRIORITY_REEMITTED)
+ /* The default when -fopt-info is enabled. */
+ ASSERT_DUMPED_TEXT_EQ
+ (tmp,
+ "test.c:5:10: missed: can't optimize loop\n"
+ "test.c:6:12: missed: can't handle return type: int"
+ " for stmt: return 0;\n");
+ else
+ {
+ gcc_assert (effective_filter == 0);
+ ASSERT_DUMPED_TEXT_EQ
+ (tmp,
+ "test.c:5:10: missed: can't optimize loop\n");
+ }
+ }
+ else
+ {
+ /* If dumping was disabled, then no problem should have been
+ created, and nothing should have been dumped. */
+ ASSERT_EQ (problem, NULL);
+ ASSERT_DUMPED_TEXT_EQ (tmp, "");
+ }
+ }
+ }
+}
+
+/* Run all of the selftests within this file. */
+
+void
+opt_problem_cc_tests ()
+{
+ test_opt_result_success ();
+ for_each_line_table_case (test_opt_result_failure_at);
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
--- /dev/null
+/* Rich information on why an optimization wasn't possible.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_OPT_PROBLEM_H
+#define GCC_OPT_PROBLEM_H
+
+#include "diagnostic-core.h" /* for ATTRIBUTE_GCC_DIAG. */
+#include "optinfo.h" /* for optinfo. */
+
+/* This header declares a family of wrapper classes for tracking a
+ success/failure value, while optionally supporting propagating an
+ opt_problem * describing any failure back up the call stack.
+
+ For instance, at the deepest point of the callstack where the failure
+ happens, rather than:
+
+ if (!check_something ())
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "foo is unsupported.\n");
+ return false;
+ }
+ // [...more checks...]
+
+ // All checks passed:
+ return true;
+
+ we can capture the cause of the failure via:
+
+ if (!check_something ())
+ return opt_result::failure_at (stmt, "foo is unsupported");
+ // [...more checks...]
+
+ // All checks passed:
+ return opt_result::success ();
+
+ which effectively returns true or false, whilst recording any problem.
+
+ opt_result::success and opt_result::failure return opt_result values
+ which "looks like" true/false respectively, via operator bool().
+ If dump_enabled_p, then opt_result::failure also creates an opt_problem *,
+ capturing the pertinent data (here, "foo is unsupported " and "stmt").
+ If dumps are disabled, then opt_problem instances aren't
+ created, and it's equivalent to just returning a bool.
+
+ The opt_problem can be propagated via opt_result values back up
+ the call stack to where it makes most sense to the user.
+ For instance, rather than:
+
+ bool ok = try_something_that_might_fail ();
+ if (!ok)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "some message.\n");
+ return false;
+ }
+
+ we can replace the bool with an opt_result, so if dump_enabled_p, we
+ assume that if try_something_that_might_fail, an opt_problem * will be
+ created, and we can propagate it up the call chain:
+
+ opt_result ok = try_something_that_might_fail ();
+ if (!ok)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "some message.\n");
+ return ok; // propagating the opt_result
+ }
+
+ opt_result is an opt_wrapper<bool>, where opt_wrapper<T> is a base
+ class for wrapping a T, optionally propagating an opt_problem in
+ case of failure_at (when dumps are enabled). Similarly,
+ opt_pointer_wrapper<T> can be used to wrap pointer types (where non-NULL
+ signifies success, NULL signifies failure).
+
+ In all cases, opt_wrapper<T> acts as if the opt_problem were one of its
+ fields, but the opt_problem is actually stored in a global, so that when
+ compiled, an opt_wrapper<T> is effectively just a T, so that we're
+ still just passing e.g. a bool around; the opt_wrapper<T> classes
+ simply provide type-checking and an API to ensure that we provide
+ error-messages deep in the callstack at the places where problems
+ occur, and that we propagate them. This also avoids having
+ to manage the ownership of the opt_problem instances.
+
+ Using opt_result and opt_wrapper<T> documents the intent of the code
+ for the places where we represent success values, and allows the C++ type
+ system to track where the deepest points in the callstack are where we
+ need to emit the failure messages from. */
+
+/* A bundle of information about why an optimization failed (e.g.
+ vectorization), and the location in both the user's code and
+ in GCC itself where the problem occurred.
+
+ Instances are created by static member functions in opt_wrapper
+ subclasses, such as opt_result::failure.
+
+ Instances are only created when dump_enabled_p (). */
+
+class opt_problem
+{
+ public:
+ static opt_problem *get_singleton () { return s_the_problem; }
+
+ opt_problem (const dump_location_t &loc,
+ const char *fmt, va_list *ap)
+ ATTRIBUTE_GCC_DUMP_PRINTF (3, 0);
+
+ const dump_location_t &
+ get_dump_location () const { return m_optinfo.get_dump_location (); }
+
+ const optinfo & get_optinfo () const { return m_optinfo; }
+
+ void emit_and_clear ();
+
+ private:
+ optinfo m_optinfo;
+
+ static opt_problem *s_the_problem;
+};
+
+/* A base class for wrapper classes that track a success/failure value, while
+ optionally supporting propagating an opt_problem * describing any
+ failure back up the call stack. */
+
+template <typename T>
+class opt_wrapper
+{
+ public:
+ typedef T wrapped_t;
+
+ /* Be accessible as the wrapped type. */
+ operator wrapped_t () const { return m_result; }
+
+ /* No public ctor. */
+
+ wrapped_t get_result () const { return m_result; }
+ opt_problem *get_problem () const { return opt_problem::get_singleton (); }
+
+ protected:
+ opt_wrapper (wrapped_t result, opt_problem */*problem*/)
+ : m_result (result)
+ {
+ /* "problem" is ignored: although it looks like a field, we
+ actually just use the opt_problem singleton, so that
+ opt_wrapper<T> in memory is just a T. */
+ }
+
+ private:
+ wrapped_t m_result;
+};
+
+/* Subclass of opt_wrapper<T> for bool, where
+ - true signifies "success", and
+ - false signifies "failure"
+ whilst effectively propagating an opt_problem * describing any failure
+ back up the call stack. */
+
+class opt_result : public opt_wrapper <bool>
+{
+ public:
+ /* Generate a "success" value: a wrapper around "true". */
+
+ static opt_result success () { return opt_result (true, NULL); }
+
+ /* Generate a "failure" value: a wrapper around "false", and,
+ if dump_enabled_p, an opt_problem. */
+
+ static opt_result failure_at (const dump_location_t &loc,
+ const char *fmt, ...)
+ ATTRIBUTE_GCC_DUMP_PRINTF (2, 3)
+ {
+ opt_problem *problem = NULL;
+ if (dump_enabled_p ())
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ problem = new opt_problem (loc, fmt, &ap);
+ va_end (ap);
+ }
+ return opt_result (false, problem);
+ }
+
+ /* Given a failure wrapper of some other kind, make an opt_result failure
+ object, for propagating the opt_problem up the call stack. */
+
+ template <typename S>
+ static opt_result
+ propagate_failure (opt_wrapper <S> other)
+ {
+ return opt_result (false, other.get_problem ());
+ }
+
+ private:
+ /* Private ctor. Instances should be created by the success and failure
+ static member functions. */
+ opt_result (wrapped_t result, opt_problem *problem)
+ : opt_wrapper (result, problem)
+ {}
+};
+
+/* Subclass of opt_wrapper<T> where T is a pointer type, for tracking
+ success/failure, where:
+ - a non-NULL value signifies "success", and
+ - a NULL value signifies "failure",
+ whilst effectively propagating an opt_problem * describing any failure
+ back up the call stack. */
+
+template <typename PtrType_t>
+class opt_pointer_wrapper : public opt_wrapper <PtrType_t>
+{
+ public:
+ typedef PtrType_t wrapped_pointer_t;
+
+ /* Given a non-NULL pointer, make a success object wrapping it. */
+
+ static opt_pointer_wrapper <wrapped_pointer_t>
+ success (wrapped_pointer_t ptr)
+ {
+ return opt_pointer_wrapper <wrapped_pointer_t> (ptr, NULL);
+ }
+
+ /* Make a NULL pointer failure object, with the given message
+ (if dump_enabled_p). */
+
+ static opt_pointer_wrapper <wrapped_pointer_t>
+ failure_at (const dump_location_t &loc,
+ const char *fmt, ...)
+ ATTRIBUTE_GCC_DUMP_PRINTF (2, 3)
+ {
+ opt_problem *problem = NULL;
+ if (dump_enabled_p ())
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ problem = new opt_problem (loc, fmt, &ap);
+ va_end (ap);
+ }
+ return opt_pointer_wrapper <wrapped_pointer_t> (NULL, problem);
+ }
+
+ /* Given a failure wrapper of some other kind, make a NULL pointer
+ failure object, propagating the problem. */
+
+ template <typename S>
+ static opt_pointer_wrapper <wrapped_pointer_t>
+ propagate_failure (opt_wrapper <S> other)
+ {
+ return opt_pointer_wrapper <wrapped_pointer_t> (NULL,
+ other.get_problem ());
+ }
+
+ /* Support accessing the underlying pointer via ->. */
+
+ wrapped_pointer_t operator-> () const { return this->get_result (); }
+
+ private:
+ /* Private ctor. Instances should be built using the static member
+ functions "success" and "failure". */
+ opt_pointer_wrapper (wrapped_pointer_t result, opt_problem *problem)
+ : opt_wrapper<PtrType_t> (result, problem)
+ {}
+};
+
+/* A typedef for wrapping "tree" so that NULL_TREE can carry an
+ opt_problem describing the failure (if dump_enabled_p). */
+
+typedef opt_pointer_wrapper<tree> opt_tree;
+
+#endif /* #ifndef GCC_OPT_PROBLEM_H */
static void
test_building_json_from_dump_calls ()
{
- temp_dump_context tmp (true, MSG_NOTE);
+ temp_dump_context tmp (true, true, MSG_NOTE);
dump_location_t loc;
dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
m_items.safe_push (item);
}
+/* Get MSG_* flags corresponding to KIND. */
+
+static dump_flags_t
+optinfo_kind_to_dump_flag (enum optinfo_kind kind)
+{
+ switch (kind)
+ {
+ default:
+ gcc_unreachable ();
+ case OPTINFO_KIND_SUCCESS:
+ return MSG_OPTIMIZED_LOCATIONS;
+ case OPTINFO_KIND_FAILURE:
+ return MSG_MISSED_OPTIMIZATION;
+ case OPTINFO_KIND_NOTE:
+ case OPTINFO_KIND_SCOPE:
+ return MSG_NOTE;
+ }
+}
+
+/* Re-emit this optinfo, both to the "non-immediate" destinations,
+ *and* to the "immediate" destinations. */
+
+void
+optinfo::emit_for_opt_problem () const
+{
+ dump_flags_t dump_kind = optinfo_kind_to_dump_flag (get_kind ());
+ dump_kind |= MSG_PRIORITY_REEMITTED;
+
+ /* Re-emit to "immediate" destinations, without creating a new optinfo. */
+ dump_context::get ().dump_loc_immediate (dump_kind, get_dump_location ());
+ unsigned i;
+ optinfo_item *item;
+ FOR_EACH_VEC_ELT (m_items, i, item)
+ dump_context::get ().emit_item (item, dump_kind);
+
+ /* Re-emit to "non-immediate" destinations. */
+ emit ();
+}
+
/* Emit the optinfo to all of the "non-immediate" destinations
- (emission to "immediate" destinations is done by emit_item). */
+ (emission to "immediate" destinations is done by
+ dump_context::emit_item). */
void
-optinfo::emit ()
+optinfo::emit () const
{
/* -fsave-optimization-record. */
optimization_records_maybe_record_optinfo (this);
{}
~optinfo ();
+ const dump_location_t &
+ get_dump_location () const { return m_loc; }
+
const dump_user_location_t &
get_user_location () const { return m_loc.get_user_location (); }
void add_item (optinfo_item *item);
+ void emit_for_opt_problem () const;
+
private:
- void emit ();
+ void emit () const;
/* Pre-canned ways of manipulating the optinfo, for use by friend class
dump_context. */
opt_proposer_c_tests ();
json_cc_tests ();
optinfo_emit_json_cc_tests ();
+ opt_problem_cc_tests ();
/* Mid-level data structures. */
input_c_tests ();
extern void hash_set_tests_c_tests ();
extern void input_c_tests ();
extern void json_cc_tests ();
+extern void opt_problem_cc_tests ();
extern void optinfo_emit_json_cc_tests ();
extern void predict_c_tests ();
extern void pretty_print_c_tests ();
+2018-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * 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.
+
2018-10-04 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/plugin/dump-1.c: Update expected output for test_scopes
--- /dev/null
+/* { dg-do compile { target vect_int } } */
+/* { dg-additional-options "-fopt-info-vec-all -O3" } */
+
+extern void accumulate (int x, int *a);
+
+int test_missing_function_defn (int *arr, int n) /* { dg-message "vectorized 0 loops in function" } */
+{
+ int sum = 0;
+ for (int i = 0; i < n; ++i) /* { dg-missed "couldn't vectorize loop" } */
+ accumulate (arr[i], &sum); /* { dg-missed "statement clobbers memory: accumulate \\(.*\\);" } */
+ return sum;
+}
/* { dg-do compile } */
/* { dg-require-effective-target vect_int } */
-/* { dg-additional-options "--param vect-max-version-for-alias-checks=0" } */
+/* { dg-additional-options "--param vect-max-version-for-alias-checks=0 -fopt-info-vec-all" } */
#define N 16
/* We allow a and b to overlap arbitrarily. */
void
-f1 (int a[][N], int b[][N])
+f1 (int a[][N], int b[][N]) /* { dg-message "vectorized 0 loops in function" } */
{
- for (int i = 0; i < N; ++i)
+ for (int i = 0; i < N; ++i) /* { dg-missed "couldn't vectorize loop" } */
a[0][i] += b[0][i];
+ /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
}
void
-f2 (union u *a, union u *b)
+f2 (union u *a, union u *b) /* { dg-message "vectorized 0 loops in function" } */
{
- for (int i = 0; i < N; ++i)
+ for (int i = 0; i < N; ++i) /* { dg-missed "couldn't vectorize loop" } */
a->f.b.a[i] += b->g.e.a[i];
+ /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
}
void
-f3 (struct s1 *a, struct s1 *b)
+f3 (struct s1 *a, struct s1 *b) /* { dg-message "vectorized 0 loops in function" } */
{
- for (int i = 0; i < N - 1; ++i)
- a->a[i + 1] += b->a[i];
+ for (int i = 0; i < N - 1; ++i) /* { dg-missed "couldn't vectorize loop" } */
+ a->a[i + 1] += b->a[i]; /* { dg-missed "possible dependence between data-refs" } */
}
/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
return build_fold_addr_expr (TREE_OPERAND (addr, 0));
}
-/* Analyze the behavior of memory reference REF. There are two modes:
+/* Analyze the behavior of memory reference REF within STMT.
+ There are two modes:
- BB analysis. In this case we simply split the address into base,
init and offset components, without reference to any containing loop.
Return true if the analysis succeeded and store the results in DRB if so.
BB analysis can only fail for bitfield or reversed-storage accesses. */
-bool
+opt_result
dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
- struct loop *loop)
+ struct loop *loop, const gimple *stmt)
{
poly_int64 pbitsize, pbitpos;
tree base, poffset;
poly_int64 pbytepos;
if (!multiple_p (pbitpos, BITS_PER_UNIT, &pbytepos))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failed: bit offset alignment.\n");
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "failed: bit offset alignment.\n");
if (preversep)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failed: reverse storage order.\n");
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "failed: reverse storage order.\n");
/* Calculate the alignment and misalignment for the inner reference. */
unsigned int HOST_WIDE_INT bit_base_misalignment;
if (in_loop)
{
if (!simple_iv (loop, loop, base, &base_iv, true))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failed: evolution of base is not affine.\n");
- return false;
- }
+ return opt_result::failure_at
+ (stmt, "failed: evolution of base is not affine.\n");
}
else
{
offset_iv.step = ssize_int (0);
}
else if (!simple_iv (loop, loop, poffset, &offset_iv, true))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failed: evolution of offset is not affine.\n");
- return false;
- }
+ return opt_result::failure_at
+ (stmt, "failed: evolution of offset is not affine.\n");
}
init = ssize_int (pbytepos);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "success.\n");
- return true;
+ return opt_result::success ();
}
/* Return true if OP is a valid component reference for a DR access
DR_IS_CONDITIONAL_IN_STMT (dr) = is_conditional_in_stmt;
dr_analyze_innermost (&DR_INNERMOST (dr), memref,
- nest != NULL ? loop : NULL);
+ nest != NULL ? loop : NULL, stmt);
dr_analyze_indices (dr, nest, loop);
dr_analyze_alias (dr);
/* Return TRUE it's possible to resolve data dependence DDR by runtime alias
check. */
-bool
+opt_result
runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
{
if (dump_enabled_p ())
DR_REF (DDR_A (ddr)), DR_REF (DDR_B (ddr)));
if (!speed_p)
- {
- if (dump_enabled_p ())
- dump_printf (MSG_MISSED_OPTIMIZATION,
- "runtime alias check not supported when optimizing "
- "for size.\n");
- return false;
- }
+ return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
+ "runtime alias check not supported when"
+ " optimizing for size.\n");
/* FORNOW: We don't support versioning with outer-loop in either
vectorization or loop distribution. */
if (loop != NULL && loop->inner != NULL)
- {
- if (dump_enabled_p ())
- dump_printf (MSG_MISSED_OPTIMIZATION,
- "runtime alias check not supported for outer loop.\n");
- return false;
- }
+ return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
+ "runtime alias check not supported for"
+ " outer loop.\n");
- return true;
+ return opt_result::success ();
}
/* Operator == between two dr_with_seg_len objects.
reference, returns false, otherwise returns true. NEST is the outermost
loop of the loop nest in which the references should be analyzed. */
-bool
+opt_result
find_data_references_in_stmt (struct loop *nest, gimple *stmt,
vec<data_reference_p> *datarefs)
{
unsigned i;
auto_vec<data_ref_loc, 2> references;
data_ref_loc *ref;
- bool ret = true;
data_reference_p dr;
if (get_references_in_stmt (stmt, &references))
- return false;
+ return opt_result::failure_at (stmt, "statement clobbers memory: %G",
+ stmt);
FOR_EACH_VEC_ELT (references, i, ref)
{
datarefs->safe_push (dr);
}
- return ret;
+ return opt_result::success ();
}
/* Stores the data references in STMT to DATAREFS. If there is an
#include "graphds.h"
#include "tree-chrec.h"
+#include "opt-problem.h"
/*
innermost_loop_behavior describes the evolution of the address of the memory
#define DDR_COULD_BE_INDEPENDENT_P(DDR) (DDR)->could_be_independent_p
\f
-bool dr_analyze_innermost (innermost_loop_behavior *, tree, struct loop *);
+opt_result dr_analyze_innermost (innermost_loop_behavior *, tree,
+ struct loop *, const gimple *);
extern bool compute_data_dependences_for_loop (struct loop *, bool,
vec<loop_p> *,
vec<data_reference_p> *,
extern void free_dependence_relations (vec<ddr_p> );
extern void free_data_ref (data_reference_p);
extern void free_data_refs (vec<data_reference_p> );
-extern bool find_data_references_in_stmt (struct loop *, gimple *,
- vec<data_reference_p> *);
+extern opt_result find_data_references_in_stmt (struct loop *, gimple *,
+ vec<data_reference_p> *);
extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
vec<data_reference_p> *);
tree find_data_references_in_loop (struct loop *, vec<data_reference_p> *);
extern bool dr_equal_offsets_p (struct data_reference *,
struct data_reference *);
-extern bool runtime_alias_check_p (ddr_p, struct loop *, bool);
+extern opt_result runtime_alias_check_p (ddr_p, struct loop *, bool);
extern int data_ref_compare_tree (tree, tree);
extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
poly_uint64);
memset (&init_dr, 0, sizeof (struct data_reference));
DR_REF (&init_dr) = init_ref;
DR_STMT (&init_dr) = phi;
- if (!dr_analyze_innermost (&DR_INNERMOST (&init_dr), init_ref, loop))
+ if (!dr_analyze_innermost (&DR_INNERMOST (&init_dr), init_ref, loop,
+ init_stmt))
return NULL;
if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
tested at run-time. Return TRUE if DDR was successfully inserted.
Return false if versioning is not supported. */
-static bool
+static opt_result
vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
if ((unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS) == 0)
- return false;
+ return opt_result::failure_at (vect_location,
+ "will not create alias checks, as"
+ " --param vect-max-version-for-alias-checks"
+ " == 0\n");
- if (!runtime_alias_check_p (ddr, loop,
- optimize_loop_nest_for_speed_p (loop)))
- return false;
+ opt_result res
+ = runtime_alias_check_p (ddr, loop,
+ optimize_loop_nest_for_speed_p (loop));
+ if (!res)
+ return res;
LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).safe_push (ddr);
- return true;
+ return opt_result::success ();
}
/* Record that loop LOOP_VINFO needs to check that VALUE is nonzero. */
/* Function vect_analyze_data_ref_dependence.
- Return TRUE if there (might) exist a dependence between a memory-reference
+ FIXME: I needed to change the sense of the returned flag.
+
+ Return FALSE if there (might) exist a dependence between a memory-reference
DRA and a memory-reference DRB. When versioning for alias may check a
- dependence at run-time, return FALSE. Adjust *MAX_VF according to
+ dependence at run-time, return TRUE. Adjust *MAX_VF according to
the data dependence. */
-static bool
+static opt_result
vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
loop_vec_info loop_vinfo,
unsigned int *max_vf)
/* Independent data accesses. */
if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
- return false;
+ return opt_result::success ();
if (dra == drb
|| (DR_IS_READ (dra) && DR_IS_READ (drb)))
- return false;
+ return opt_result::success ();
/* We do not have to consider dependences between accesses that belong
to the same group, unless the stride could be smaller than the
&& (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)
== DR_GROUP_FIRST_ELEMENT (stmtinfo_b))
&& !STMT_VINFO_STRIDED_P (stmtinfo_a))
- return false;
+ return opt_result::success ();
/* Even if we have an anti-dependence then, as the vectorized loop covers at
least two scalar iterations, there is always also a true dependence.
|| (DR_IS_WRITE (dra) && DR_IS_READ (drb)))
&& !alias_sets_conflict_p (get_alias_set (DR_REF (dra)),
get_alias_set (DR_REF (drb))))
- return false;
+ return opt_result::success ();
/* Unknown data dependence. */
if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
if ((unsigned int) loop->safelen < *max_vf)
*max_vf = loop->safelen;
LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
- return false;
+ return opt_result::success ();
}
if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
|| STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "versioning for alias not supported for: "
- "can't determine dependence between %T and %T\n",
- DR_REF (dra), DR_REF (drb));
- return true;
- }
+ return opt_result::failure_at
+ (stmtinfo_a->stmt,
+ "versioning for alias not supported for: "
+ "can't determine dependence between %T and %T\n",
+ DR_REF (dra), DR_REF (drb));
if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
"versioning for alias required: "
"can't determine dependence between %T and %T\n",
DR_REF (dra), DR_REF (drb));
/* Add to list of ddrs that need to be tested at run-time. */
- return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
+ return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
}
/* Known data dependence. */
if ((unsigned int) loop->safelen < *max_vf)
*max_vf = loop->safelen;
LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
- return false;
+ return opt_result::success ();
}
if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
|| STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "versioning for alias not supported for: "
- "bad dist vector for %T and %T\n",
- DR_REF (dra), DR_REF (drb));
- return true;
- }
+ return opt_result::failure_at
+ (stmtinfo_a->stmt,
+ "versioning for alias not supported for: "
+ "bad dist vector for %T and %T\n",
+ DR_REF (dra), DR_REF (drb));
if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
"versioning for alias required: "
"bad dist vector for %T and %T\n",
DR_REF (dra), DR_REF (drb));
/* Add to list of ddrs that need to be tested at run-time. */
- return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
+ return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
}
loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr));
if (DDR_COULD_BE_INDEPENDENT_P (ddr)
&& vect_analyze_possibly_independent_ddr (ddr, loop_vinfo,
loop_depth, max_vf))
- return false;
+ return opt_result::success ();
FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)
{
a[i+1] = ...;
where loads from the group interleave with the store. */
if (!vect_preserves_scalar_order_p (dr_info_a, dr_info_b))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "READ_WRITE dependence in interleaving.\n");
- return true;
- }
+ return opt_result::failure_at (stmtinfo_a->stmt,
+ "READ_WRITE dependence"
+ " in interleaving.\n");
if (loop->safelen < 2)
{
tree indicator = dr_zero_step_indicator (dra);
if (!indicator || integer_zerop (indicator))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "access also has a zero step\n");
- return true;
- }
+ return opt_result::failure_at (stmtinfo_a->stmt,
+ "access also has a zero step\n");
else if (TREE_CODE (indicator) != INTEGER_CST)
vect_check_nonzero_value (loop_vinfo, indicator);
}
continue;
}
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized, possible dependence "
- "between data-refs %T and %T\n",
- DR_REF (dra), DR_REF (drb));
-
- return true;
+ return opt_result::failure_at (stmtinfo_a->stmt,
+ "not vectorized, possible dependence "
+ "between data-refs %T and %T\n",
+ DR_REF (dra), DR_REF (drb));
}
- return false;
+ return opt_result::success ();
}
/* Function vect_analyze_data_ref_dependences.
exist any data dependences between them. Set *MAX_VF according to
the maximum vectorization factor the data dependences allow. */
-bool
+opt_result
vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
unsigned int *max_vf)
{
*max_vf = LOOP_VINFO_ORIG_MAX_VECT_FACTOR (loop_vinfo);
else
FOR_EACH_VEC_ELT (LOOP_VINFO_DDRS (loop_vinfo), i, ddr)
- if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf))
- return false;
+ {
+ opt_result res
+ = vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf);
+ if (!res)
+ return res;
+ }
- return true;
+ return opt_result::success ();
}
Return TRUE if DR_INFO can be handled with respect to alignment. */
-static bool
+static opt_result
verify_data_ref_alignment (dr_vec_info *dr_info)
{
enum dr_alignment_support supportable_dr_alignment
= vect_supportable_dr_alignment (dr_info, false);
if (!supportable_dr_alignment)
- {
- if (dump_enabled_p ())
- {
- if (DR_IS_READ (dr_info->dr))
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported unaligned load.");
- else
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported unaligned "
- "store.");
-
- dump_printf (MSG_MISSED_OPTIMIZATION, "%T\n", DR_REF (dr_info->dr));
- }
- return false;
- }
+ return opt_result::failure_at
+ (dr_info->stmt->stmt,
+ DR_IS_READ (dr_info->dr)
+ ? "not vectorized: unsupported unaligned load: %T\n"
+ : "not vectorized: unsupported unaligned store: %T\n",
+ DR_REF (dr_info->dr));
if (supportable_dr_alignment != dr_aligned && dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"Vectorizing an unaligned access.\n");
- return true;
+ return opt_result::success ();
}
/* Function vect_verify_datarefs_alignment
Return TRUE if all data references in the loop can be
handled with respect to alignment. */
-bool
+opt_result
vect_verify_datarefs_alignment (loop_vec_info vinfo)
{
vec<data_reference_p> datarefs = vinfo->shared->datarefs;
&& !STMT_VINFO_GROUPED_ACCESS (stmt_info))
continue;
- if (! verify_data_ref_alignment (dr_info))
- return false;
+ opt_result res = verify_data_ref_alignment (dr_info);
+ if (!res)
+ return res;
}
- return true;
+ return opt_result::success ();
}
/* Given an memory reference EXP return whether its alignment is less
(whether to generate regular loads/stores, or with special handling for
misalignment). */
-bool
+opt_result
vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
{
vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
unsigned int i, j;
bool do_peeling = false;
bool do_versioning = false;
- bool stat;
unsigned int npeel = 0;
bool one_misalignment_known = false;
bool one_misalignment_unknown = false;
/* Check if all datarefs are supportable and log. */
if (do_peeling && known_alignment_for_access_p (dr0_info) && npeel == 0)
{
- stat = vect_verify_datarefs_alignment (loop_vinfo);
+ opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
if (!stat)
do_peeling = false;
else
/* The inside-loop cost will be accounted for in vectorizable_load
and vectorizable_store correctly with adjusted alignments.
Drop the body_cst_vec on the floor here. */
- stat = vect_verify_datarefs_alignment (loop_vinfo);
+ opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
gcc_assert (stat);
return stat;
}
/* Peeling and versioning can't be done together at this time. */
gcc_assert (! (do_peeling && do_versioning));
- stat = vect_verify_datarefs_alignment (loop_vinfo);
+ opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
gcc_assert (stat);
return stat;
}
/* This point is reached if neither peeling nor versioning is being done. */
gcc_assert (! (do_peeling || do_versioning));
- stat = vect_verify_datarefs_alignment (loop_vinfo);
+ opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
return stat;
}
Analyze the alignment of the data-references in the loop.
Return FALSE if a data reference is found that cannot be vectorized. */
-bool
+opt_result
vect_analyze_data_refs_alignment (loop_vec_info vinfo)
{
DUMP_VECT_SCOPE ("vect_analyze_data_refs_alignment");
vect_compute_data_ref_alignment (dr_info);
}
- return true;
+ return opt_result::success ();
}
FORNOW: handle only arrays and pointer accesses. */
-bool
+opt_result
vect_analyze_data_ref_accesses (vec_info *vinfo)
{
unsigned int i;
DUMP_VECT_SCOPE ("vect_analyze_data_ref_accesses");
if (datarefs.is_empty ())
- return true;
+ return opt_result::success ();
/* Sort the array of datarefs to make building the interleaving chains
linear. Don't modify the original vector's order, it is needed for
else
{
datarefs_copy.release ();
- return false;
+ return opt_result::failure_at (dr_info->stmt->stmt,
+ "not vectorized:"
+ " complicated access pattern.\n");
}
}
}
datarefs_copy.release ();
- return true;
+ return opt_result::success ();
}
/* Function vect_vfa_segment_size.
Return FALSE if resulting list of ddrs is longer then allowed by
PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE. */
-bool
+opt_result
vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
{
typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
}
if (may_alias_ddrs.is_empty ())
- return true;
+ return opt_result::success ();
comp_alias_ddrs.create (may_alias_ddrs.length ());
continue;
if (res == 1)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "not vectorized: compilation time alias.\n");
- return false;
- }
+ return opt_result::failure_at (stmt_info_b->stmt,
+ "not vectorized:"
+ " compilation time alias: %G%G",
+ stmt_info_a->stmt,
+ stmt_info_b->stmt);
}
dr_with_seg_len_pair_t dr_with_seg_len_pair
"improved number of alias checks from %d to %d\n",
may_alias_ddrs.length (), count);
if ((int) count > PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "number of versioning for alias "
- "run-time tests exceeds %d "
- "(--param vect-max-version-for-alias-checks)\n",
- PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
- return false;
- }
-
- return true;
+ return opt_result::failure_at
+ (vect_location,
+ "number of versioning for alias "
+ "run-time tests exceeds %d "
+ "(--param vect-max-version-for-alias-checks)\n",
+ PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
+
+ return opt_result::success ();
}
/* Check whether we can use an internal function for a gather load
append them to DATAREFS. Return false if datarefs in this stmt cannot
be handled. */
-bool
+opt_result
vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
vec<data_reference_p> *datarefs)
{
loop vectorization and BB vectorization checks dependences with a
stmt walk. */
if (gimple_clobber_p (stmt))
- return true;
+ return opt_result::success ();
if (gimple_has_volatile_ops (stmt))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: volatile type %G", stmt);
- return false;
- }
+ return opt_result::failure_at (stmt, "not vectorized: volatile type: %G",
+ stmt);
if (stmt_can_throw_internal (stmt))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: statement can throw an exception %G",
- stmt);
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized:"
+ " statement can throw an exception: %G",
+ stmt);
auto_vec<data_reference_p, 2> refs;
- if (!find_data_references_in_stmt (loop, stmt, &refs))
- return false;
+ opt_result res = find_data_references_in_stmt (loop, stmt, &refs);
+ if (!res)
+ return res;
if (refs.is_empty ())
- return true;
+ return opt_result::success ();
if (refs.length () > 1)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: more than one data ref "
- "in stmt: %G", stmt);
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized:"
+ " more than one data ref in stmt: %G", stmt);
if (gcall *call = dyn_cast <gcall *> (stmt))
if (!gimple_call_internal_p (call)
|| (gimple_call_internal_fn (call) != IFN_MASK_LOAD
&& gimple_call_internal_fn (call) != IFN_MASK_STORE))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: dr in a call %G", stmt);
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized: dr in a call %G", stmt);
data_reference_p dr = refs.pop ();
if (TREE_CODE (DR_REF (dr)) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (DR_REF (dr), 1)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: statement is bitfield "
- "access %G", stmt);
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized:"
+ " statement is bitfield access %G", stmt);
if (DR_BASE_ADDRESS (dr)
&& TREE_CODE (DR_BASE_ADDRESS (dr)) == INTEGER_CST)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: base addr of dr is a "
- "constant\n");
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized:"
+ " base addr of dr is a constant\n");
/* Check whether this may be a SIMD lane access and adjust the
DR to make it easier for us to handle it. */
newdr->aux = (void *)-1;
free_data_ref (dr);
datarefs->safe_push (newdr);
- return true;
+ return opt_result::success ();
}
}
}
}
datarefs->safe_push (dr);
- return true;
+ return opt_result::success ();
}
/* Function vect_analyze_data_refs.
*/
-bool
+opt_result
vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
{
struct loop *loop = NULL;
STMT_VINFO_VECTORIZABLE (stmt_info) = false;
continue;
}
- return false;
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ " data ref analysis failed: %G",
+ stmt_info->stmt);
}
}
if (dr->aux == (void *)-1)
{
if (nested_in_vect_loop_p (loop, stmt_info))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: data ref analysis "
- "failed %G", stmt_info->stmt);
- return false;
- }
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ " data ref analysis failed: %G",
+ stmt_info->stmt);
STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) = true;
}
STMT_VINFO_VECTORIZABLE (stmt_info) = false;
continue;
}
- return false;
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized: base object not"
+ " addressable for stmt: %G",
+ stmt_info->stmt);
}
if (is_a <loop_vec_info> (vinfo)
&& TREE_CODE (DR_STEP (dr)) != INTEGER_CST)
{
if (nested_in_vect_loop_p (loop, stmt_info))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: not suitable for strided "
- "load %G", stmt_info->stmt);
- return false;
- }
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ "not suitable for strided load %G",
+ stmt_info->stmt);
STMT_VINFO_STRIDED_P (stmt_info) = true;
}
dump_printf_loc (MSG_NOTE, vect_location,
"analyze in outer loop: %T\n", init_ref);
- if (!dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
- init_ref, loop))
+ opt_result res
+ = dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
+ init_ref, loop, stmt_info->stmt);
+ if (!res)
/* dr_analyze_innermost already explained the failure. */
- return false;
+ return res;
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
STMT_VINFO_VECTORIZABLE (stmt_info) = false;
continue;
}
- return false;
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ " no vectype for stmt: %G"
+ " scalar_type: %T\n",
+ stmt_info->stmt, scalar_type);
}
else
{
as_a <loop_vec_info> (vinfo),
&gs_info)
|| !get_vectype_for_scalar_type (TREE_TYPE (gs_info.offset)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- (gatherscatter == GATHER) ?
- "not vectorized: not suitable for gather "
- "load %G" :
- "not vectorized: not suitable for scatter "
- "store %G",
- stmt_info->stmt);
- return false;
- }
+ return opt_result::failure_at
+ (stmt_info->stmt,
+ (gatherscatter == GATHER) ?
+ "not vectorized: not suitable for gather load %G" :
+ "not vectorized: not suitable for scatter store %G",
+ stmt_info->stmt);
STMT_VINFO_GATHER_SCATTER_P (stmt_info) = gatherscatter;
}
}
longer need to. */
gcc_assert (i == datarefs.length ());
- return true;
+ return opt_result::success ();
}
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,
{
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)
{
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
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)
{
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))
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
}
*/
-static bool
+static opt_result
vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (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 ())
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;
}
}
}
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 ();
}
- 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)
(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
{
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
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;
gcc_assert (!loop->aux);
loop->aux = loop_vinfo;
- return loop_vinfo;
+ return opt_loop_vec_info::success (loop_vinfo);
}
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);
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. */
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;
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))
{
&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 */
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
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)
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)
{
}
}
}
- 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.
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;
/* 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 ();
}
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.
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. */
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. */
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);
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);
/* 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);
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.
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
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)
{
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
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
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. */
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;
}
}
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. */
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];
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");
}
}
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. */
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;
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;
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++];
/* Check if there are stmts in the loop can be vectorized using SLP. Build SLP
trees of packed scalar stmts if SLP is possible. */
-bool
+opt_result
vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
{
unsigned int i;
max_tree_size);
}
- return true;
+ return opt_result::success ();
}
Return true if everything is as expected. Return false otherwise. */
-static bool
+static opt_result
process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
bool force)
/* case 1: we are only interested in uses that need to be vectorized. Uses
that are used for address computation are not considered relevant. */
if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
- return true;
+ return opt_result::success ();
if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported use in stmt.\n");
- return false;
- }
+ return opt_result::failure_at (stmt_vinfo->stmt,
+ "not vectorized:"
+ " unsupported use in stmt.\n");
if (!dstmt_vinfo)
- return true;
+ return opt_result::success ();
def_bb = gimple_bb (dstmt_vinfo->stmt);
gcc_assert (STMT_VINFO_RELEVANT (dstmt_vinfo) < vect_used_by_reduction);
gcc_assert (STMT_VINFO_LIVE_P (dstmt_vinfo)
|| STMT_VINFO_RELEVANT (dstmt_vinfo) > vect_unused_in_scope);
- return true;
+ return opt_result::success ();
}
/* case 3a: outer-loop stmt defining an inner-loop stmt:
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"induction value on backedge.\n");
- return true;
+ return opt_result::success ();
}
vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
- return true;
+ return opt_result::success ();
}
This pass detects such stmts. */
-bool
+opt_result
vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
&& relevant != vect_used_in_scope
&& relevant != vect_used_by_reduction
&& relevant != vect_used_only_live)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported use of reduction.\n");
- return false;
- }
+ return opt_result::failure_at
+ (stmt_vinfo->stmt, "unsupported use of reduction.\n");
break;
case vect_nested_cycle:
if (relevant != vect_unused_in_scope
&& relevant != vect_used_in_outer_by_reduction
&& relevant != vect_used_in_outer)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported use of nested cycle.\n");
-
- return false;
- }
+ return opt_result::failure_at
+ (stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
break;
case vect_double_reduction_def:
if (relevant != vect_unused_in_scope
&& relevant != vect_used_by_reduction
&& relevant != vect_used_only_live)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported use of double reduction.\n");
-
- return false;
- }
+ return opt_result::failure_at
+ (stmt_vinfo->stmt, "unsupported use of double reduction.\n");
break;
default:
i = 1;
if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
{
- if (!process_use (stmt_vinfo, TREE_OPERAND (op, 0),
- loop_vinfo, relevant, &worklist, false)
- || !process_use (stmt_vinfo, TREE_OPERAND (op, 1),
- loop_vinfo, relevant, &worklist, false))
- return false;
+ opt_result res
+ = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
+ loop_vinfo, relevant, &worklist, false);
+ if (!res)
+ return res;
+ res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
+ loop_vinfo, relevant, &worklist, false);
+ if (!res)
+ return res;
i = 2;
}
for (; i < gimple_num_ops (assign); i++)
{
op = gimple_op (assign, i);
- if (TREE_CODE (op) == SSA_NAME
- && !process_use (stmt_vinfo, op, loop_vinfo, relevant,
- &worklist, false))
- return false;
+ if (TREE_CODE (op) == SSA_NAME)
+ {
+ opt_result res
+ = process_use (stmt_vinfo, op, loop_vinfo, relevant,
+ &worklist, false);
+ if (!res)
+ return res;
+ }
}
}
else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
for (i = 0; i < gimple_call_num_args (call); i++)
{
tree arg = gimple_call_arg (call, i);
- if (!process_use (stmt_vinfo, arg, loop_vinfo, relevant,
- &worklist, false))
- return false;
+ opt_result res
+ = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
+ &worklist, false);
+ if (!res)
+ return res;
}
}
}
FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
{
tree op = USE_FROM_PTR (use_p);
- if (!process_use (stmt_vinfo, op, loop_vinfo, relevant,
- &worklist, false))
- return false;
+ opt_result res
+ = process_use (stmt_vinfo, op, loop_vinfo, relevant,
+ &worklist, false);
+ if (!res)
+ return res;
}
if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
gather_scatter_info gs_info;
if (!vect_check_gather_scatter (stmt_vinfo, loop_vinfo, &gs_info))
gcc_unreachable ();
- if (!process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
- &worklist, true))
- return false;
+ opt_result res
+ = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
+ &worklist, true);
+ if (!res)
+ return res;
}
} /* while worklist */
- return true;
+ return opt_result::success ();
}
/* Compute the prologue cost for invariant or constant operands. */
/* Make sure the statement is vectorizable. */
-bool
+opt_result
vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
slp_tree node, slp_instance node_instance,
stmt_vector_for_cost *cost_vec)
stmt_info->stmt);
if (gimple_has_volatile_ops (stmt_info->stmt))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: stmt has volatile operands\n");
-
- return false;
- }
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ " stmt has volatile operands: %G\n",
+ stmt_info->stmt);
if (STMT_VINFO_IN_PATTERN_P (stmt_info)
&& node == NULL
"==> examining pattern def statement: %G",
pattern_def_stmt_info->stmt);
- if (!vect_analyze_stmt (pattern_def_stmt_info,
- need_to_vectorize, node, node_instance,
- cost_vec))
- return false;
+ opt_result res
+ = vect_analyze_stmt (pattern_def_stmt_info,
+ need_to_vectorize, node, node_instance,
+ cost_vec);
+ if (!res)
+ return res;
}
}
}
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
- return true;
+ return opt_result::success ();
}
}
else if (STMT_VINFO_IN_PATTERN_P (stmt_info)
"==> examining pattern statement: %G",
pattern_stmt_info->stmt);
- if (!vect_analyze_stmt (pattern_stmt_info, need_to_vectorize, node,
- node_instance, cost_vec))
- return false;
+ opt_result res
+ = vect_analyze_stmt (pattern_stmt_info, need_to_vectorize, node,
+ node_instance, cost_vec);
+ if (!res)
+ return res;
}
switch (STMT_VINFO_DEF_TYPE (stmt_info))
{
dump_printf_loc (MSG_NOTE, vect_location,
"handled only by SLP analysis\n");
- return true;
+ return opt_result::success ();
}
ok = true;
}
if (!ok)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: relevant stmt not supported: %G",
- stmt_info->stmt);
-
- return false;
- }
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ " relevant stmt not supported: %G",
+ stmt_info->stmt);
/* Stmts that are (also) "live" (i.e. - that are used out of the loop)
need extra handling, except for vectorizable reductions. */
if (!bb_vinfo
&& STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
&& !can_vectorize_live_stmts (stmt_info, NULL, node, NULL, cost_vec))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: live stmt not supported: %G",
- stmt_info->stmt);
+ return opt_result::failure_at (stmt_info->stmt,
+ "not vectorized:"
+ " live stmt not supported: %G",
+ stmt_info->stmt);
- return false;
- }
-
- return true;
+ return opt_result::success ();
}
number of units needed to vectorize STMT_INFO, or NULL_TREE if the
statement does not help to determine the overall number of units. */
-bool
+opt_result
vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
tree *stmt_vectype_out,
tree *nunits_vectype_out)
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"defer to SIMD clone analysis.\n");
- return true;
+ return opt_result::success ();
}
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: irregular stmt.%G", stmt);
- return false;
+ return opt_result::failure_at (stmt,
+ "not vectorized: irregular stmt.%G", stmt);
}
if (VECTOR_MODE_P (TYPE_MODE (gimple_expr_type (stmt))))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: vector stmt in loop:%G", stmt);
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized: vector stmt in loop:%G",
+ stmt);
tree vectype;
tree scalar_type = NULL_TREE;
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"pure bool operation.\n");
- return true;
+ return opt_result::success ();
}
}
"get vectype for scalar type: %T\n", scalar_type);
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 (stmt,
+ "not vectorized:"
+ " unsupported data-type %T\n",
+ scalar_type);
if (!*stmt_vectype_out)
*stmt_vectype_out = vectype;
nunits_vectype = get_vectype_for_scalar_type (scalar_type);
}
if (!nunits_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 (stmt,
+ "not vectorized: unsupported data-type %T\n",
+ scalar_type);
if (maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
GET_MODE_SIZE (TYPE_MODE (nunits_vectype))))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: different sized vector "
- "types in statement, %T and %T\n",
- vectype, nunits_vectype);
- return false;
- }
+ return opt_result::failure_at (stmt,
+ "not vectorized: different sized vector "
+ "types in statement, %T and %T\n",
+ vectype, nunits_vectype);
if (dump_enabled_p ())
{
}
*nunits_vectype_out = nunits_vectype;
- return true;
+ return opt_result::success ();
}
/* Try to determine the correct vector type for STMT_INFO, which is a
statement that produces a scalar boolean result. Return the vector
type on success, otherwise return NULL_TREE. */
-tree
+opt_tree
vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
{
gimple *stmt = stmt_info->stmt;
mask_type = get_mask_type_for_scalar_type (scalar_type);
if (!mask_type)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: unsupported mask\n");
- return NULL_TREE;
- }
+ return opt_tree::failure_at (stmt,
+ "not vectorized: unsupported mask\n");
}
else
{
FOR_EACH_SSA_TREE_OPERAND (rhs, stmt, iter, SSA_OP_USE)
{
if (!vect_is_simple_use (rhs, stmt_info->vinfo, &dt, &vectype))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: can't compute mask type "
- "for statement, %G", stmt);
- return NULL_TREE;
- }
+ return opt_tree::failure_at (stmt,
+ "not vectorized:can't compute mask"
+ " type for statement, %G", stmt);
/* No vectype probably means external definition.
Allow it in case there is another operand which
mask_type = vectype;
else if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_type),
TYPE_VECTOR_SUBPARTS (vectype)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: different sized masks "
- "types in statement, %T and %T\n",
- mask_type, vectype);
- return NULL_TREE;
- }
+ return opt_tree::failure_at (stmt,
+ "not vectorized: different sized mask"
+ " types in statement, %T and %T\n",
+ mask_type, vectype);
else if (VECTOR_BOOLEAN_TYPE_P (mask_type)
!= VECTOR_BOOLEAN_TYPE_P (vectype))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: mixed mask and "
- "nonmask vector types in statement, "
- "%T and %T\n",
- mask_type, vectype);
- return NULL_TREE;
- }
+ return opt_tree::failure_at (stmt,
+ "not vectorized: mixed mask and "
+ "nonmask vector types in statement, "
+ "%T and %T\n",
+ mask_type, vectype);
}
/* We may compare boolean value loaded as vector of integers.
/* No mask_type should mean loop invariant predicate.
This is probably a subject for optimization in if-conversion. */
- if (!mask_type && dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: can't compute mask type "
- "for statement, %G", stmt);
- return mask_type;
+ if (!mask_type)
+ return opt_tree::failure_at (stmt,
+ "not vectorized: can't compute mask type "
+ "for statement: %G", stmt);
+
+ return opt_tree::success (mask_type);
}
#include "stringpool.h"
#include "attribs.h"
#include "gimple-pretty-print.h"
+#include "opt-problem.h"
/* Loop or bb location, with hotness information. */
vect_location = find_loop_location (loop);
if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION
&& dump_enabled_p ())
- dump_printf (MSG_NOTE, "\nAnalyzing loop at %s:%d\n",
+ dump_printf (MSG_NOTE | MSG_PRIORITY_INTERNALS,
+ "\nAnalyzing loop at %s:%d\n",
LOCATION_FILE (vect_location.get_location_t ()),
LOCATION_LINE (vect_location.get_location_t ()));
- loop_vec_info loop_vinfo = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
+ /* Try to analyze the loop, retaining an opt_problem if dump_enabled_p. */
+ opt_loop_vec_info loop_vinfo
+ = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
loop->aux = loop_vinfo;
+ if (!loop_vinfo)
+ if (dump_enabled_p ())
+ if (opt_problem *problem = loop_vinfo.get_problem ())
+ {
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "couldn't vectorize loop\n");
+ problem->emit_and_clear ();
+ }
+
if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
{
/* Free existing information if loop is analyzed with some
#define LOOP_VINFO_ORIG_MAX_VECT_FACTOR(L) \
(LOOP_VINFO_MAX_VECT_FACTOR (LOOP_VINFO_ORIG_LOOP_INFO (L)))
+/* Wrapper for loop_vec_info, for tracking success/failure, where a non-NULL
+ value signifies success, and a NULL value signifies failure, supporting
+ propagating an opt_problem * describing the failure back up the call
+ stack. */
+typedef opt_pointer_wrapper <loop_vec_info> opt_loop_vec_info;
+
static inline loop_vec_info
loop_vec_info_for_loop (struct loop *loop)
{
extern stmt_vec_info vect_finish_replace_stmt (stmt_vec_info, gimple *);
extern stmt_vec_info vect_finish_stmt_generation (stmt_vec_info, gimple *,
gimple_stmt_iterator *);
-extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
+extern opt_result vect_mark_stmts_to_be_vectorized (loop_vec_info);
extern tree vect_get_store_rhs (stmt_vec_info);
extern tree vect_get_vec_def_for_operand_1 (stmt_vec_info, enum vect_def_type);
extern tree vect_get_vec_def_for_operand (tree, stmt_vec_info, tree = NULL);
extern bool vect_transform_stmt (stmt_vec_info, gimple_stmt_iterator *,
slp_tree, slp_instance);
extern void vect_remove_stores (stmt_vec_info);
-extern bool vect_analyze_stmt (stmt_vec_info, bool *, slp_tree, slp_instance,
- stmt_vector_for_cost *);
+extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree,
+ slp_instance, stmt_vector_for_cost *);
extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *,
stmt_vec_info *, tree, int, slp_tree,
stmt_vector_for_cost *);
extern void optimize_mask_stores (struct loop*);
extern gcall *vect_gen_while (tree, tree, tree);
extern tree vect_gen_while_not (gimple_seq *, tree, tree, tree);
-extern bool vect_get_vector_types_for_stmt (stmt_vec_info, tree *, tree *);
-extern tree vect_get_mask_type_for_stmt (stmt_vec_info);
+extern opt_result vect_get_vector_types_for_stmt (stmt_vec_info, tree *,
+ tree *);
+extern opt_tree vect_get_mask_type_for_stmt (stmt_vec_info);
/* In tree-vect-data-refs.c. */
extern bool vect_can_force_dr_alignment_p (const_tree, unsigned int);
(dr_vec_info *, bool);
extern tree vect_get_smallest_scalar_type (stmt_vec_info, HOST_WIDE_INT *,
HOST_WIDE_INT *);
-extern bool vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
+extern opt_result vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
extern bool vect_slp_analyze_instance_dependence (slp_instance);
-extern bool vect_enhance_data_refs_alignment (loop_vec_info);
-extern bool vect_analyze_data_refs_alignment (loop_vec_info);
-extern bool vect_verify_datarefs_alignment (loop_vec_info);
+extern opt_result vect_enhance_data_refs_alignment (loop_vec_info);
+extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
+extern opt_result vect_verify_datarefs_alignment (loop_vec_info);
extern bool vect_slp_analyze_and_verify_instance_alignment (slp_instance);
-extern bool vect_analyze_data_ref_accesses (vec_info *);
-extern bool vect_prune_runtime_alias_test_list (loop_vec_info);
+extern opt_result vect_analyze_data_ref_accesses (vec_info *);
+extern opt_result vect_prune_runtime_alias_test_list (loop_vec_info);
extern bool vect_gather_scatter_fn_p (bool, bool, tree, tree, unsigned int,
signop, int, internal_fn *, tree *);
extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info,
gather_scatter_info *);
-extern bool vect_find_stmt_data_reference (loop_p, gimple *,
- vec<data_reference_p> *);
-extern bool vect_analyze_data_refs (vec_info *, poly_uint64 *);
+extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
+ vec<data_reference_p> *);
+extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *);
extern void vect_record_base_alignments (vec_info *);
extern tree vect_create_data_ref_ptr (stmt_vec_info, tree, struct loop *, tree,
tree *, gimple_stmt_iterator *,
extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree,
enum tree_code);
/* Drive for loop analysis stage. */
-extern loop_vec_info vect_analyze_loop (struct loop *, loop_vec_info,
- vec_info_shared *);
+extern opt_loop_vec_info vect_analyze_loop (struct loop *,
+ loop_vec_info,
+ vec_info_shared *);
extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL);
extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *,
tree *, bool);
/* Drive for loop transformation stage. */
extern struct loop *vect_transform_loop (loop_vec_info);
-extern loop_vec_info vect_analyze_loop_form (struct loop *, vec_info_shared *);
+extern opt_loop_vec_info vect_analyze_loop_form (struct loop *,
+ vec_info_shared *);
extern bool vectorizable_live_operation (stmt_vec_info, gimple_stmt_iterator *,
slp_tree, int, stmt_vec_info *,
stmt_vector_for_cost *);
slp_instance, bool, unsigned *);
extern bool vect_slp_analyze_operations (vec_info *);
extern void vect_schedule_slp (vec_info *);
-extern bool vect_analyze_slp (vec_info *, unsigned);
+extern opt_result vect_analyze_slp (vec_info *, unsigned);
extern bool vect_make_slp_decision (loop_vec_info);
extern void vect_detect_hybrid_slp (loop_vec_info);
extern void vect_get_slp_defs (vec<tree> , slp_tree, vec<vec<tree> > *);