[PATCH 3/3] v3: Report vectorization problems via a new opt_problem class
Richard Biener
rguenther@suse.de
Thu Oct 4 11:28:00 GMT 2018
On Fri, 28 Sep 2018, David Malcolm wrote:
> This is v3 of the patch; previous versions were:
> v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html
> v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html
>
> This patch introduces a class opt_problem, along with wrapper
> classes for bool (opt_result) and for pointers (e.g. opt_loop_vec_info
> for loop_vec_info).
>
> opt_problem instances are created when an optimization problem
> is encountered, but only if dump_enabled_p. They are manually
> propagated up the callstack, and are manually reported at the
> "top level" of an optimization if dumping is enabled, to give the user
> a concise summary of the problem *after* the failure is reported.
> In particular, the location of the problematic statement is
> captured and emitted, rather than just the loop's location.
>
> For example:
>
> no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop
> no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__ __volatile__("" : : : "memory");
>
> Changed in v3:
> * This version bootstraps and passes regression testing (on
> x86_64-pc-linux-gnu).
> * added selftests, to exercise the opt_problem machinery
> * removed the "bool to opt_result" ctor, so that attempts to
> use e.g. return a bool from an opt_result-returning function
> will fail at compile time
> * use formatted printing within opt_problem ctor to replace the
> various dump_printf_loc calls
> * dropped i18n
> * changed the sense of vect_analyze_data_ref_dependence's return
> value (see the ChangeLog)
> * add MSG_PRIORITY_REEMITTED, so that -fopt-info can show the
> messages, without them messing up the counts in scan-tree-dump-times
> in DejaGnu tests
>
> Re Richard Sandiford's feedback on the v2 patch:
> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00560.html
> > Since the creation of the opt_problem depends on dump_enabled_p, would
> > it make sense for the dump_printf_loc to happen automatically on
> > opt_result::failure, rather than have both?
>
> Yes; this v3 patch does that: opt_result::failure_at is passed a format
> string with variadic args. If dumping is enabled, it performs the
> equivalent of dump_printf_loc in a form that will reach dumpfiles
> (and -fopt-info-internals), stashing the dumped items in the opt_problem.
> When the opt_problem is emitted at the top-level, the message is re-emitted
> (but only for -fopt-info, not for dumpfiles, to avoid duplicates that mess
> up scan-tree-dump-times in DejaGnu tests)
>
> > I guess this is bike-shedding, but personally I'd prefer an explicit
> > test for success rather than operator bool, so that:
> >
> > opt_result foo = ...;
> > bool bar = foo;
> >
> > is ill-formed. The danger otherwise might be that we drop a useful
> > opt_problem and replace it with something more generic. E.g. the
> > opt_result form of:
> > if (!ok)
> > {
> > if (dump_enabled_p ())
> > {
> > dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> > "not vectorized: relevant stmt not ");
> > dump_printf (MSG_MISSED_OPTIMIZATION, "supported: ");
> > dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
> > }
> >
> > return false;
> > }
> >
> > in vect_analyze_stmt could silently drop the information provided by
> > the subroutine if we forgot to change "ok" from "bool" to "opt_result".
>
> I didn't make that change in v3: if the function returns an opt_result, then
> the "return false;" will be a compile-time failure, alerting us to the
> problem.
>
> I guess this is a matter of style, whether explicit is better than
> implicit. Dropping the operator bool would require an explicit approach,
> with something like:
>
> // Explicit style:
> opt_result res = ...;
> if (res.failed_p ())
> return res;
>
> and:
>
> // Explicit style:
> // It's often currently called "ok":
> opt_result ok = ...;
> if (ok.failed_p ())
> return ok;
>
> as opposed to:
>
> // Implicit style:
> opt_result res = ...;
> if (!res)
> return res;
>
> and:
>
> // Implicit style:
> opt_result ok = ...;
> if (!ok)
> return ok;
>
> I think I went with the implicit style to minimize the lines touched by
> the patch, but I'm happy with either approach. [If we're bikeshedding,
> would renaming those "ok" to "res" be acceptable also? "ok" reads to
> me like a "success" value for a status variable, rather than the status
> variable itself; it's presumably meant to be pronounced with a rising
> interrogative as it were a question - "ok?" - but that's not visible in
> the code when reading the usage sites].
>
> Similarly, the pointer wrappers use an implicit style:
>
> // Implicit style:
>
> 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 ())
> {
>
> but maybe an explicit style is more readable:
>
> // Explicit style:
>
> opt_loop_vec_info opt_loop_vinfo
> = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
> loop_vec_info loop_vinfo = loop_vinfo.get_pointer ();
> loop->aux = loop_vinfo
>
> if (opt_loop_vinfo.failed_p ())
> if (dump_enabled_p ())
> if (opt_problem *problem = loop_vinfo.get_problem ())
> {
>
>
> How would you want the code to look?
>
> Richi: do you have an opinion here?
I wouldn't mind about the explicit variant for the bool but
the explicit for the pointer looks odd.
In general I agree that
opt_result foo = x;
bool bar = x;
is confusing but I also like the brevity that is possible
with the automatic conversions so I am biased towards that.
> (or is that style in the patch OK as-is?)
For me it is OK as-is.
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>
> OK for trunk?
OK. My question on 2/3 leaves Richard time to comment.
Maybe you can tackle the issue that -fopt-info-inline does
nothing at the moment and see if opt-problems are a good fit
there as well (reporting the CIF strings).
Thanks for working on all this!
Richard.
>
> gcc/ChangeLog:
> * Makefile.in (OBJS): Add opt-problem.o.
> * dump-context.h: Include "selftest.h.
> (selftest::temp_dump_context): New forward decl.
> (class dump_context): Make friend of class
> selftest::temp_dump_context.
> (dump_context::dump_loc_immediate): New decl.
> (class dump_pretty_printer): Move here from dumpfile.c.
> (class temp_dump_context): Move to namespace selftest.
> (temp_dump_context::temp_dump_context): Add param
> "forcibly_enable_dumping".
> (selftest::verify_dumped_text):
> (ASSERT_DUMPED_TEXT_EQ): Move here from dumpfile.c.
> (selftest::verify_item):
> (ASSERT_IS_TEXT): Move here from dumpfile.c.
> (ASSERT_IS_TREE): Likewise.
> (ASSERT_IS_GIMPLE): Likewise.
> * dumpfile.c (dump_context::dump_loc): Move immediate dumping
> to...
> (dump_context::dump_loc_immediate): ...this new function.
> (class dump_pretty_printer): Move to dump-context.h.
> (dump_switch_p_1): Don't enable MSG_PRIORITY_REEMITTED.
> (opt_info_switch_p_1): Enable MSG_PRIORITY_REEMITTED.
> (temp_dump_context::temp_dump_context): Move to "selftest"
> namespace. Add param "forcibly_enable_dumping", and use it to
> conditionalize the use of m_pp;
> (selftest::verify_dumped_text): Make non-static.
> (ASSERT_DUMPED_TEXT_EQ): Move to dump-context.h.
> (selftest::verify_item): Make non-static.
> (ASSERT_IS_TEXT): Move to dump-context.h.
> (ASSERT_IS_TREE): Likewise.
> (ASSERT_IS_GIMPLE): Likewise.
> (selftest::test_capture_of_dump_calls): Pass "true" for new
> param of temp_dump_context.
> * dumpfile.h (enum dump_flag): Add MSG_PRIORITY_REEMITTED, adding
> it to MSG_ALL_PRIORITIES. Update values of TDF_COMPARE_DEBUG and
> TDF_COMPARE_DEBUG.
> * opt-problem.cc: New file.
> * opt-problem.h: New file.
> * optinfo-emit-json.cc
> (selftest::test_building_json_from_dump_calls): Pass "true" for
> new param of temp_dump_context.
> * optinfo.cc (optinfo_kind_to_dump_flag): New function.
> (optinfo::emit_for_opt_problem): New function.
> (optinfo::emit): Clarity which emit_item is used.
> * optinfo.h (optinfo::get_dump_location): New accessor.
> (optinfo::emit_for_opt_problem): New decl.
> (optinfo::emit): Make const.
> * selftest-run-tests.c (selftest::run_tests): Call
> selftest::opt_problem_cc_tests.
> * selftest.h (selftest::opt_problem_cc_tests): New decl.
> * tree-data-ref.c (dr_analyze_innermost): Convert return type from
> bool to opt_result, converting fprintf messages to
> opt_result::failure_at calls. Add "stmt" param for use by the
> failure_at calls.
> (create_data_ref): Pass "stmt" to the dr_analyze_innermost call.
> (runtime_alias_check_p): Convert return type from bool to
> opt_result, converting dump_printf calls to
> opt_result::failure_at, using the statement DDR_A for their
> location.
> (find_data_references_in_stmt): Convert return type from bool to
> opt_result, converting "return false" to opt_result::failure_at
> with a new message.
> * tree-data-ref.h: Include "opt-problem.h".
> (dr_analyze_innermost): Convert return type from bool to opt_result,
> and add a const gimple * param.
> (find_data_references_in_stmt): Convert return type from bool to
> opt_result.
> (runtime_alias_check_p): Likewise.
> * tree-predcom.c (find_looparound_phi): Pass "init_stmt" to
> dr_analyze_innermost.
> * tree-vect-data-refs.c (vect_mark_for_runtime_alias_test):
> Convert return type from bool to opt_result, adding a message for
> the PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS zero case.
> (vect_analyze_data_ref_dependence): Convert return type from bool
> to opt_result. Change sense of return type from "false"
> effectively meaning "no problems" to "false" meaning a problem,
> so that "return false" becomes "return opt_result::success".
> Convert "return true" calls to opt_result::failure_at, using
> the location of statement A rather than vect_location.
> (vect_analyze_data_ref_dependences): Convert return type from bool
> to opt_result.
> (verify_data_ref_alignment): Likewise, converting dump_printf_loc
> calls to opt_result::failure_at, using the stmt location rather
> than vect_location.
> (vect_verify_datarefs_alignment): Convert return type from bool
> to opt_result.
> (vect_enhance_data_refs_alignment): Likewise. Split local "stat"
> into multiple more-tightly-scoped copies.
> (vect_analyze_data_refs_alignment): Convert return type from bool
> to opt_result.
> (vect_analyze_data_ref_accesses): Likewise, converting a
> "return false" to a "return opt_result::failure_at", adding a
> new message.
> (vect_prune_runtime_alias_test_list): Convert return type from
> bool to opt_result, converting dump_printf_loc to
> opt_result::failure_at. Add a %G to show the pertinent statement,
> and use the stmt's location rather than vect_location.
> (vect_find_stmt_data_reference): Convert return type from
> bool to opt_result, converting dump_printf_loc to
> opt_result::failure_at, using stmt's location.
> (vect_analyze_data_refs): Convert return type from bool to
> opt_result. Convert "return false" to "return
> opt_result::failure_at", adding messages as needed.
> * tree-vect-loop.c (vect_determine_vf_for_stmt_1): Convert return
> type from bool to opt_result.
> (vect_determine_vf_for_stmt): Likewise.
> (vect_determine_vectorization_factor): Likewise, converting
> dump_printf_loc to opt_result::failure_at, using location of phi
> rather than vect_location.
> (vect_analyze_loop_form_1): Convert return type from bool to
> opt_result, converting dump_printf_loc calls, retaining the use of
> vect_location.
> (vect_analyze_loop_form): Convert return type from loop_vec_info
> to opt_loop_vec_info.
> (vect_analyze_loop_operations): Convert return type from bool to
> opt_result, converting dump_printf_loc calls, using the location
> of phi/stmt rather than vect_location where available. Convert
> various "return false" to "return opt_result::failure_at" with
> "unsupported phi" messages.
> (vect_get_datarefs_in_loop): Convert return type from bool to
> opt_result. Add a message for the
> PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS failure.
> (vect_analyze_loop_2): Convert return type from bool to
> opt_result. Ensure "ok" is set to a opt_result::failure_at before
> each "goto again;", adding new messages where needed.
> Add "unsupported grouped {store|load}" messages.
> (vect_analyze_loop): Convert return type from loop_vec_info to
> opt_loop_vec_info.
> * tree-vect-slp.c (vect_analyze_slp): Convert return type from
> bool to opt_result.
> * tree-vect-stmts.c (process_use): Likewise, converting
> dump_printf_loc call and using stmt location, rather than
> vect_location.
> (vect_mark_stmts_to_be_vectorized): Likeise.
> (vect_analyze_stmt): Likewise, adding a %G.
> (vect_get_vector_types_for_stmt): Convert return type from bool to
> opt_result, converting dump_printf_loc calls and using stmt
> location, rather than vect_location.
> (vect_get_mask_type_for_stmt): Convert return type from tree to
> opt_tree, converting dump_printf_loc calls and using stmt location.
> * tree-vectorizer.c: Include "opt-problem.h.
> (try_vectorize_loop_1): Flag "Analyzing loop at" dump message as
> MSG_PRIORITY_INTERNALS. Convert local "loop_vinfo" from
> loop_vec_info to opt_loop_vec_info. If if fails, and dumping is
> enabled, use it to report at the top level "couldn't vectorize
> loop" followed by the problem.
> * tree-vectorizer.h (opt_loop_vec_info): New typedef.
> (vect_mark_stmts_to_be_vectorized): Convert return type from bool
> to opt_result.
> (vect_analyze_stmt): Likewise.
> (vect_get_vector_types_for_stmt): Likewise.
> (tree vect_get_mask_type_for_stmt): Likewise.
> (vect_analyze_data_ref_dependences): Likewise.
> (vect_enhance_data_refs_alignment): Likewise.
> (vect_analyze_data_refs_alignment): Likewise.
> (vect_verify_datarefs_alignment): Likewise.
> (vect_analyze_data_ref_accesses): Likewise.
> (vect_prune_runtime_alias_test_list): Likewise.
> (vect_find_stmt_data_reference): Likewise.
> (vect_analyze_data_refs): Likewise.
> (vect_analyze_loop): Convert return type from loop_vec_info to
> opt_loop_vec_info.
> (vect_analyze_loop_form): Likewise.
> (vect_analyze_slp): Convert return type from bool to opt_result.
>
> gcc/testsuite/ChangeLog:
> * gcc.dg/vect/nodump-vect-opt-info-2.c: New test.
> * gcc.dg/vect/vect-alias-check-4.c: Add "-fopt-info-vec-all" to
> dg-additional-options. Add dg-message and dg-missed directives
> to verify that -fopt-info messages are written at the correct
> locations.
> ---
> gcc/Makefile.in | 1 +
> gcc/dump-context.h | 104 ++++-
> gcc/dumpfile.c | 160 +++-----
> gcc/dumpfile.h | 13 +-
> gcc/opt-problem.cc | 335 ++++++++++++++++
> gcc/opt-problem.h | 289 ++++++++++++++
> gcc/optinfo-emit-json.cc | 2 +-
> gcc/optinfo.cc | 44 +-
> gcc/optinfo.h | 7 +-
> gcc/selftest-run-tests.c | 1 +
> gcc/selftest.h | 1 +
> gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c | 12 +
> gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c | 18 +-
> gcc/tree-data-ref.c | 70 ++--
> gcc/tree-data-ref.h | 10 +-
> gcc/tree-predcom.c | 3 +-
> gcc/tree-vect-data-refs.c | 347 ++++++++--------
> gcc/tree-vect-loop.c | 442 +++++++++------------
> gcc/tree-vect-slp.c | 4 +-
> gcc/tree-vect-stmts.c | 275 ++++++-------
> gcc/tree-vectorizer.c | 17 +-
> gcc/tree-vectorizer.h | 45 ++-
> 22 files changed, 1408 insertions(+), 792 deletions(-)
> create mode 100644 gcc/opt-problem.cc
> create mode 100644 gcc/opt-problem.h
> create mode 100644 gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 4b7cec8..116ed6e 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1423,6 +1423,7 @@ OBJS = \
> omp-grid.o \
> omp-low.o \
> omp-simd-clone.o \
> + opt-problem.o \
> optabs.o \
> optabs-libfuncs.o \
> optabs-query.o \
> diff --git a/gcc/dump-context.h b/gcc/dump-context.h
> index 20b94a7..3a45f23 100644
> --- a/gcc/dump-context.h
> +++ b/gcc/dump-context.h
> @@ -24,6 +24,9 @@ along with GCC; see the file COPYING3. If not see
>
> #include "dumpfile.h"
> #include "pretty-print.h"
> +#include "selftest.h"
> +
> +namespace selftest { class temp_dump_context; }
>
> /* A class for handling the various dump_* calls.
>
> @@ -36,7 +39,8 @@ along with GCC; see the file COPYING3. If not see
>
> class dump_context
> {
> - friend class temp_dump_context;
> + friend class selftest::temp_dump_context;
> +
> public:
> static dump_context &get () { return *s_current; }
>
> @@ -45,6 +49,7 @@ class dump_context
> 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);
> @@ -129,8 +134,53 @@ class dump_context
> 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. */
>
> @@ -138,6 +188,7 @@ class temp_dump_context
> {
> public:
> temp_dump_context (bool forcibly_enable_optinfo,
> + bool forcibly_enable_dumping,
> dump_flags_t test_pp_flags);
> ~temp_dump_context ();
>
> @@ -151,6 +202,57 @@ class 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 */
> diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
> index e15edc7..0b140ff 100644
> --- a/gcc/dumpfile.c
> +++ b/gcc/dumpfile.c
> @@ -562,6 +562,21 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
> {
> 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))
> @@ -573,12 +588,6 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
> /* 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. */
> @@ -739,49 +748,6 @@ dump_context::dump_generic_expr_loc (dump_flags_t dump_kind,
> 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,
> @@ -1732,7 +1698,12 @@ dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
> 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)
> {
> @@ -1830,8 +1801,9 @@ opt_info_switch_p_1 (const char *arg, dump_flags_t *flags,
> *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;
>
> @@ -1981,19 +1953,26 @@ enable_rtl_dump_file (void)
>
> #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 ();
> }
> @@ -2015,8 +1994,6 @@ temp_dump_context::get_dumped_text ()
> 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). */
> @@ -2055,7 +2032,7 @@ test_impl_location ()
> 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)
> @@ -2065,18 +2042,9 @@ verify_dumped_text (const location &loc,
> 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,
> @@ -2088,30 +2056,6 @@ verify_item (const location &loc,
> 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. */
>
> @@ -2144,7 +2088,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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");
>
> @@ -2161,7 +2105,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2179,7 +2123,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2197,7 +2141,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2220,7 +2164,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
> - 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",
> @@ -2248,7 +2192,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
> @@ -2268,7 +2212,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2288,7 +2232,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
> {
> /* 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);
>
> @@ -2304,7 +2248,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2320,7 +2264,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2336,7 +2280,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
>
> @@ -2353,7 +2297,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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));
>
> @@ -2378,7 +2322,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
> 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,
> @@ -2460,7 +2404,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
> {
> /* 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);
> @@ -2468,7 +2412,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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);
> @@ -2477,7 +2421,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>
> /* 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");
> {
> diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> index 5933905..c82157d 100644
> --- a/gcc/dumpfile.h
> +++ b/gcc/dumpfile.h
> @@ -179,15 +179,22 @@ enum dump_flag
> /* 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. */
> diff --git a/gcc/opt-problem.cc b/gcc/opt-problem.cc
> new file mode 100644
> index 0000000..dad3a8c
> --- /dev/null
> +++ b/gcc/opt-problem.cc
> @@ -0,0 +1,335 @@
> +/* 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 */
> diff --git a/gcc/opt-problem.h b/gcc/opt-problem.h
> new file mode 100644
> index 0000000..68d7e4a
> --- /dev/null
> +++ b/gcc/opt-problem.h
> @@ -0,0 +1,289 @@
> +/* 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 */
> diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc
> index efdbdb3..31029ad 100644
> --- a/gcc/optinfo-emit-json.cc
> +++ b/gcc/optinfo-emit-json.cc
> @@ -531,7 +531,7 @@ namespace selftest {
> 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);
> diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc
> index b858c3c..de781a5 100644
> --- a/gcc/optinfo.cc
> +++ b/gcc/optinfo.cc
> @@ -89,11 +89,51 @@ optinfo::add_item (optinfo_item *item)
> 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);
> diff --git a/gcc/optinfo.h b/gcc/optinfo.h
> index 8ac961c..99bd22c 100644
> --- a/gcc/optinfo.h
> +++ b/gcc/optinfo.h
> @@ -108,6 +108,9 @@ class optinfo
> {}
> ~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 (); }
>
> @@ -124,8 +127,10 @@ class optinfo
>
> 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. */
> diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
> index 5adb033..562ada7 100644
> --- a/gcc/selftest-run-tests.c
> +++ b/gcc/selftest-run-tests.c
> @@ -74,6 +74,7 @@ selftest::run_tests ()
> opt_proposer_c_tests ();
> json_cc_tests ();
> optinfo_emit_json_cc_tests ();
> + opt_problem_cc_tests ();
>
> /* Mid-level data structures. */
> input_c_tests ();
> diff --git a/gcc/selftest.h b/gcc/selftest.h
> index ede7732..8da7c4a 100644
> --- a/gcc/selftest.h
> +++ b/gcc/selftest.h
> @@ -229,6 +229,7 @@ extern void hash_map_tests_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 ();
> diff --git a/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c b/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
> new file mode 100644
> index 0000000..94c55a9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
> @@ -0,0 +1,12 @@
> +/* { 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;
> +}
> diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
> index 1e5fc27..750193e 100644
> --- a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
> +++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
> @@ -1,6 +1,6 @@
> /* { 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
>
> @@ -12,24 +12,26 @@ union u { struct s2 f; struct s3 g; };
> /* 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" } } */
> diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
> index bf30a61..69c5f7b 100644
> --- a/gcc/tree-data-ref.c
> +++ b/gcc/tree-data-ref.c
> @@ -807,7 +807,8 @@ canonicalize_base_object_address (tree addr)
> 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.
> @@ -827,9 +828,9 @@ canonicalize_base_object_address (tree addr)
> 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;
> @@ -848,18 +849,12 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
>
> 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;
> @@ -895,11 +890,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
> 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
> {
> @@ -921,11 +913,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
> 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);
> @@ -981,7 +970,7 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
> 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
> @@ -1205,7 +1194,7 @@ create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
> 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);
>
> @@ -1318,7 +1307,7 @@ data_ref_compare_tree (tree t1, tree t2)
> /* 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 ())
> @@ -1327,25 +1316,18 @@ runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_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.
> @@ -5043,18 +5025,18 @@ loop_nest_has_data_refs (loop_p loop)
> 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)
> {
> @@ -5065,7 +5047,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
> datarefs->safe_push (dr);
> }
>
> - return ret;
> + return opt_result::success ();
> }
>
> /* Stores the data references in STMT to DATAREFS. If there is an
> diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
> index 8739853..525d27f 100644
> --- a/gcc/tree-data-ref.h
> +++ b/gcc/tree-data-ref.h
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
>
> #include "graphds.h"
> #include "tree-chrec.h"
> +#include "opt-problem.h"
>
> /*
> innermost_loop_behavior describes the evolution of the address of the memory
> @@ -421,7 +422,8 @@ typedef struct data_dependence_relation *ddr_p;
> #define DDR_COULD_BE_INDEPENDENT_P(DDR) (DDR)->could_be_independent_p
>
>
> -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> *,
> @@ -443,8 +445,8 @@ extern void free_dependence_relation (struct data_dependence_relation *);
> 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> *);
> @@ -479,7 +481,7 @@ extern bool dr_may_alias_p (const struct data_reference *,
> 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);
> diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
> index 2bde732..1711027 100644
> --- a/gcc/tree-predcom.c
> +++ b/gcc/tree-predcom.c
> @@ -1280,7 +1280,8 @@ find_looparound_phi (struct loop *loop, dref ref, dref root)
> 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))
> diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
> index 56b7968..c4805e7 100644
> --- a/gcc/tree-vect-data-refs.c
> +++ b/gcc/tree-vect-data-refs.c
> @@ -156,20 +156,25 @@ vect_get_smallest_scalar_type (stmt_vec_info stmt_info,
> 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. */
> @@ -277,12 +282,14 @@ vect_analyze_possibly_independent_ddr (data_dependence_relation *ddr,
>
> /* 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)
> @@ -305,11 +312,11 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>
> /* 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
> @@ -318,7 +325,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> && (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.
> @@ -330,7 +337,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> || (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)
> @@ -342,28 +349,25 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> 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. */
> @@ -376,27 +380,24 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> 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));
> @@ -404,7 +405,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *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)
> {
> @@ -440,23 +441,16 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> 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);
> }
> @@ -503,16 +497,13 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> 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.
> @@ -521,7 +512,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
> 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)
> {
> @@ -553,10 +544,14 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
> *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 ();
> }
>
>
> @@ -1055,33 +1050,24 @@ vect_update_misalignment_for_peel (dr_vec_info *dr_info,
>
> 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
> @@ -1089,7 +1075,7 @@ verify_data_ref_alignment (dr_vec_info *dr_info)
> 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;
> @@ -1115,11 +1101,12 @@ vect_verify_datarefs_alignment (loop_vec_info vinfo)
> && !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
> @@ -1593,7 +1580,7 @@ vect_peeling_supportable (loop_vec_info loop_vinfo, dr_vec_info *dr0_info,
> (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);
> @@ -1605,7 +1592,6 @@ vect_enhance_data_refs_alignment (loop_vec_info 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;
> @@ -1992,7 +1978,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
> /* 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
> @@ -2078,7 +2064,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
> /* 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;
> }
> @@ -2201,7 +2187,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
> /* 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;
> }
> @@ -2209,7 +2195,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
> /* 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;
> }
>
> @@ -2275,7 +2261,7 @@ vect_find_same_alignment_drs (vec_info *vinfo, data_dependence_relation *ddr)
> 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");
> @@ -2300,7 +2286,7 @@ vect_analyze_data_refs_alignment (loop_vec_info vinfo)
> vect_compute_data_ref_alignment (dr_info);
> }
>
> - return true;
> + return opt_result::success ();
> }
>
>
> @@ -2825,7 +2811,7 @@ can_group_stmts_p (stmt_vec_info stmt1_info, stmt_vec_info stmt2_info)
>
> FORNOW: handle only arrays and pointer accesses. */
>
> -bool
> +opt_result
> vect_analyze_data_ref_accesses (vec_info *vinfo)
> {
> unsigned int i;
> @@ -2835,7 +2821,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
> 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
> @@ -2994,13 +2980,15 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
> 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.
> @@ -3258,7 +3246,7 @@ vectorizable_with_step_bound_p (dr_vec_info *dr_info_a, dr_vec_info *dr_info_b,
> 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;
> @@ -3292,7 +3280,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
> }
>
> if (may_alias_ddrs.is_empty ())
> - return true;
> + return opt_result::success ();
>
> comp_alias_ddrs.create (may_alias_ddrs.length ());
>
> @@ -3452,12 +3440,11 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
> 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
> @@ -3482,17 +3469,14 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
> "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
> @@ -3846,7 +3830,7 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
> 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)
> {
> @@ -3854,72 +3838,50 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
> 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. */
> @@ -3976,7 +3938,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
> newdr->aux = (void *)-1;
> free_data_ref (dr);
> datarefs->safe_push (newdr);
> - return true;
> + return opt_result::success ();
> }
> }
> }
> @@ -3986,7 +3948,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
> }
>
> datarefs->safe_push (dr);
> - return true;
> + return opt_result::success ();
> }
>
> /* Function vect_analyze_data_refs.
> @@ -4004,7 +3966,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
>
> */
>
> -bool
> +opt_result
> vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> {
> struct loop *loop = NULL;
> @@ -4074,7 +4036,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> 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);
> }
> }
>
> @@ -4082,13 +4047,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> 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;
> }
>
> @@ -4106,7 +4068,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> 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)
> @@ -4114,13 +4079,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> && 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;
> }
>
> @@ -4150,10 +4112,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> 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,
> @@ -4199,7 +4163,11 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> 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
> {
> @@ -4221,17 +4189,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> 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;
> }
> }
> @@ -4240,7 +4203,7 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
> longer need to. */
> gcc_assert (i == datarefs.length ());
>
> - return true;
> + return opt_result::success ();
> }
>
>
> diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
> index fdac10b..6ea1e77 100644
> --- a/gcc/tree-vect-loop.c
> +++ b/gcc/tree-vect-loop.c
> @@ -159,7 +159,7 @@ static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
> statement. VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE
> may already be set for general statements (not just data refs). */
>
> -static bool
> +static opt_result
> vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
> bool vectype_maybe_set_p,
> poly_uint64 *vf,
> @@ -173,13 +173,14 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
> {
> if (dump_enabled_p ())
> dump_printf_loc (MSG_NOTE, vect_location, "skip.\n");
> - return true;
> + return opt_result::success ();
> }
>
> tree stmt_vectype, nunits_vectype;
> - if (!vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
> - &nunits_vectype))
> - return false;
> + opt_result res = vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
> + &nunits_vectype);
> + if (!res)
> + return res;
>
> if (stmt_vectype)
> {
> @@ -199,7 +200,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
> if (nunits_vectype)
> vect_update_max_nunits (vf, nunits_vectype);
>
> - return true;
> + return opt_result::success ();
> }
>
> /* Subroutine of vect_determine_vectorization_factor. Set the vector
> @@ -209,7 +210,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
> add them to MASK_PRODUCERS. Return true on success or false if
> something prevented vectorization. */
>
> -static bool
> +static opt_result
> vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
> vec<stmt_vec_info > *mask_producers)
> {
> @@ -217,8 +218,10 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
> if (dump_enabled_p ())
> dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
> stmt_info->stmt);
> - if (!vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers))
> - return false;
> + opt_result res
> + = vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers);
> + if (!res)
> + return res;
>
> if (STMT_VINFO_IN_PATTERN_P (stmt_info)
> && STMT_VINFO_RELATED_STMT (stmt_info))
> @@ -237,18 +240,22 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
> def_stmt_info->stmt);
> if (!vect_determine_vf_for_stmt_1 (def_stmt_info, true,
> vf, mask_producers))
> - return false;
> + res = vect_determine_vf_for_stmt_1 (def_stmt_info, true,
> + vf, mask_producers);
> + if (!res)
> + return res;
> }
>
> if (dump_enabled_p ())
> dump_printf_loc (MSG_NOTE, vect_location,
> "==> examining pattern statement: %G",
> stmt_info->stmt);
> - if (!vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers))
> - return false;
> + res = vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers);
> + if (!res)
> + return res;
> }
>
> - return true;
> + return opt_result::success ();
> }
>
> /* Function vect_determine_vectorization_factor
> @@ -276,7 +283,7 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
> }
> */
>
> -static bool
> +static opt_result
> vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
> {
> struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> @@ -320,14 +327,10 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
>
> vectype = get_vectype_for_scalar_type (scalar_type);
> if (!vectype)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: unsupported "
> - "data-type %T\n",
> - scalar_type);
> - return false;
> - }
> + return opt_result::failure_at (phi,
> + "not vectorized: unsupported "
> + "data-type %T\n",
> + scalar_type);
> STMT_VINFO_VECTYPE (stmt_info) = vectype;
>
> if (dump_enabled_p ())
> @@ -349,9 +352,11 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
> gsi_next (&si))
> {
> stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
> - if (!vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
> - &mask_producers))
> - return false;
> + opt_result res
> + = vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
> + &mask_producers);
> + if (!res)
> + return res;
> }
> }
>
> @@ -364,24 +369,20 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
> }
>
> if (known_le (vectorization_factor, 1U))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: unsupported data-type\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized: unsupported data-type\n");
> LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
>
> for (i = 0; i < mask_producers.length (); i++)
> {
> stmt_info = mask_producers[i];
> - tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
> + opt_tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
> if (!mask_type)
> - return false;
> + return opt_result::propagate_failure (mask_type);
> STMT_VINFO_VECTYPE (stmt_info) = mask_type;
> }
>
> - return true;
> + return opt_result::success ();
> }
>
>
> @@ -1145,7 +1146,7 @@ vect_compute_single_scalar_iteration_cost (loop_vec_info loop_vinfo)
> - the number of iterations can be analyzed, i.e, a countable loop. The
> niter could be analyzed under some assumptions. */
>
> -bool
> +opt_result
> vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
> tree *assumptions, tree *number_of_iterationsm1,
> tree *number_of_iterations, gcond **inner_loop_cond)
> @@ -1171,20 +1172,13 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
> (exit-bb) */
>
> if (loop->num_nodes != 2)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: control flow in loop.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized:"
> + " control flow in loop.\n");
>
> if (empty_block_p (loop->header))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: empty loop.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized: empty loop.\n");
> }
> else
> {
> @@ -1209,75 +1203,60 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
> as described above. */
>
> if ((loop->inner)->inner || (loop->inner)->next)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: multiple nested loops.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized:"
> + " multiple nested loops.\n");
>
> if (loop->num_nodes != 5)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: control flow in loop.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized:"
> + " control flow in loop.\n");
>
> entryedge = loop_preheader_edge (innerloop);
> if (entryedge->src != loop->header
> || !single_exit (innerloop)
> || single_exit (innerloop)->dest != EDGE_PRED (loop->latch, 0)->src)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: unsupported outerloop form.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized:"
> + " unsupported outerloop form.\n");
>
> /* Analyze the inner-loop. */
> tree inner_niterm1, inner_niter, inner_assumptions;
> - if (! vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
> - &inner_assumptions, &inner_niterm1,
> - &inner_niter, NULL)
> - /* Don't support analyzing niter under assumptions for inner
> - loop. */
> - || !integer_onep (inner_assumptions))
> + opt_result res
> + = vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
> + &inner_assumptions, &inner_niterm1,
> + &inner_niter, NULL);
> + if (!res)
> {
> if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "not vectorized: Bad inner loop.\n");
> - return false;
> + return res;
> }
>
> + /* Don't support analyzing niter under assumptions for inner
> + loop. */
> + if (!integer_onep (inner_assumptions))
> + return opt_result::failure_at (vect_location,
> + "not vectorized: Bad inner loop.\n");
> +
> if (!expr_invariant_in_loop_p (loop, inner_niter))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: inner-loop count not"
> - " invariant.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized: inner-loop count not"
> + " invariant.\n");
>
> if (dump_enabled_p ())
> dump_printf_loc (MSG_NOTE, vect_location,
> "Considering outer-loop vectorization.\n");
> }
>
> - if (!single_exit (loop)
> - || EDGE_COUNT (loop->header->preds) != 2)
> - {
> - if (dump_enabled_p ())
> - {
> - if (!single_exit (loop))
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: multiple exits.\n");
> - else if (EDGE_COUNT (loop->header->preds) != 2)
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: too many incoming edges.\n");
> - }
> - return false;
> - }
> + if (!single_exit (loop))
> + return opt_result::failure_at (vect_location,
> + "not vectorized: multiple exits.\n");
> + if (EDGE_COUNT (loop->header->preds) != 2)
> + return opt_result::failure_at (vect_location,
> + "not vectorized:"
> + " too many incoming edges.\n");
>
> /* We assume that the loop exit condition is at the end of the loop. i.e,
> that the loop is represented as a do-while (with a proper if-guard
> @@ -1285,67 +1264,52 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
> executable statements, and the latch is empty. */
> if (!empty_block_p (loop->latch)
> || !gimple_seq_empty_p (phi_nodes (loop->latch)))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: latch block not empty.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized: latch block not empty.\n");
>
> /* Make sure the exit is not abnormal. */
> edge e = single_exit (loop);
> if (e->flags & EDGE_ABNORMAL)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: abnormal loop exit edge.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "not vectorized:"
> + " abnormal loop exit edge.\n");
>
> *loop_cond = vect_get_loop_niters (loop, assumptions, number_of_iterations,
> number_of_iterationsm1);
> if (!*loop_cond)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: complicated exit condition.\n");
> - return false;
> - }
> + return opt_result::failure_at
> + (vect_location,
> + "not vectorized: complicated exit condition.\n");
>
> if (integer_zerop (*assumptions)
> || !*number_of_iterations
> || chrec_contains_undetermined (*number_of_iterations))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: number of iterations cannot be "
> - "computed.\n");
> - return false;
> - }
> + return opt_result::failure_at
> + (*loop_cond,
> + "not vectorized: number of iterations cannot be computed.\n");
>
> if (integer_zerop (*number_of_iterations))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: number of iterations = 0.\n");
> - return false;
> - }
> + return opt_result::failure_at
> + (*loop_cond,
> + "not vectorized: number of iterations = 0.\n");
>
> - return true;
> + return opt_result::success ();
> }
>
> /* Analyze LOOP form and return a loop_vec_info if it is of suitable form. */
>
> -loop_vec_info
> +opt_loop_vec_info
> vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
> {
> tree assumptions, number_of_iterations, number_of_iterationsm1;
> gcond *loop_cond, *inner_loop_cond = NULL;
>
> - if (! vect_analyze_loop_form_1 (loop, &loop_cond,
> - &assumptions, &number_of_iterationsm1,
> - &number_of_iterations, &inner_loop_cond))
> - return NULL;
> + opt_result res
> + = vect_analyze_loop_form_1 (loop, &loop_cond,
> + &assumptions, &number_of_iterationsm1,
> + &number_of_iterations, &inner_loop_cond);
> + if (!res)
> + return opt_loop_vec_info::propagate_failure (res);
>
> loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared);
> LOOP_VINFO_NITERSM1 (loop_vinfo) = number_of_iterationsm1;
> @@ -1387,7 +1351,7 @@ vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
>
> gcc_assert (!loop->aux);
> loop->aux = loop_vinfo;
> - return loop_vinfo;
> + return opt_loop_vec_info::success (loop_vinfo);
> }
>
>
> @@ -1489,7 +1453,7 @@ vect_active_double_reduction_p (stmt_vec_info stmt_info)
>
> Scan the loop stmts and make sure they are all vectorizable. */
>
> -static bool
> +static opt_result
> vect_analyze_loop_operations (loop_vec_info loop_vinfo)
> {
> struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> @@ -1531,13 +1495,9 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
> requires to actually do something here. */
> if (STMT_VINFO_LIVE_P (stmt_info)
> && !vect_active_double_reduction_p (stmt_info))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "Unsupported loop-closed phi in "
> - "outer-loop.\n");
> - return false;
> - }
> + return opt_result::failure_at (phi,
> + "Unsupported loop-closed phi"
> + " in outer-loop.\n");
>
> /* If PHI is used in the outer loop, we check that its operand
> is defined in the inner loop. */
> @@ -1546,17 +1506,17 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
> tree phi_op;
>
> if (gimple_phi_num_args (phi) != 1)
> - return false;
> + return opt_result::failure_at (phi, "unsupported phi");
>
> phi_op = PHI_ARG_DEF (phi, 0);
> stmt_vec_info op_def_info = loop_vinfo->lookup_def (phi_op);
> if (!op_def_info)
> - return false;
> + return opt_result::failure_at (phi, "unsupported phi");
>
> if (STMT_VINFO_RELEVANT (op_def_info) != vect_used_in_outer
> && (STMT_VINFO_RELEVANT (op_def_info)
> != vect_used_in_outer_by_reduction))
> - return false;
> + return opt_result::failure_at (phi, "unsupported phi");
> }
>
> continue;
> @@ -1567,13 +1527,10 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
> if ((STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_scope
> || STMT_VINFO_LIVE_P (stmt_info))
> && STMT_VINFO_DEF_TYPE (stmt_info) != vect_induction_def)
> - {
> - /* A scalar-dependence cycle that we don't support. */
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: scalar dependence cycle.\n");
> - return false;
> - }
> + /* A scalar-dependence cycle that we don't support. */
> + return opt_result::failure_at (phi,
> + "not vectorized:"
> + " scalar dependence cycle.\n");
>
> if (STMT_VINFO_RELEVANT_P (stmt_info))
> {
> @@ -1597,24 +1554,25 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
> &cost_vec);
>
> if (!ok)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: relevant phi not "
> - "supported: %G", phi);
> - return false;
> - }
> + return opt_result::failure_at (phi,
> + "not vectorized: relevant phi not "
> + "supported: %G",
> + static_cast <gimple *> (phi));
> }
>
> for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
> gsi_next (&si))
> {
> gimple *stmt = gsi_stmt (si);
> - if (!gimple_clobber_p (stmt)
> - && !vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
> + if (!gimple_clobber_p (stmt))
> + {
> + opt_result res
> + = vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
> &need_to_vectorize,
> - NULL, NULL, &cost_vec))
> - return false;
> + NULL, NULL, &cost_vec);
> + if (!res)
> + return res;
> + }
> }
> } /* bbs */
>
> @@ -1631,14 +1589,12 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
> if (dump_enabled_p ())
> dump_printf_loc (MSG_NOTE, vect_location,
> "All the computation can be taken out of the loop.\n");
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: redundant loop. no profit to "
> - "vectorize.\n");
> - return false;
> + return opt_result::failure_at
> + (vect_location,
> + "not vectorized: redundant loop. no profit to vectorize.\n");
> }
>
> - return true;
> + return opt_result::success ();
> }
>
> /* Analyze the cost of the loop described by LOOP_VINFO. Decide if it
> @@ -1736,7 +1692,7 @@ vect_analyze_loop_costing (loop_vec_info loop_vinfo)
> return 1;
> }
>
> -static bool
> +static opt_result
> vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
> vec<data_reference_p> *datarefs,
> unsigned int *n_stmts)
> @@ -1750,7 +1706,8 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
> if (is_gimple_debug (stmt))
> continue;
> ++(*n_stmts);
> - if (!vect_find_stmt_data_reference (loop, stmt, datarefs))
> + opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs);
> + if (!res)
> {
> if (is_gimple_call (stmt) && loop->safelen)
> {
> @@ -1782,15 +1739,16 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
> }
> }
> }
> - return false;
> + return res;
> }
> /* If dependence analysis will give up due to the limit on the
> number of datarefs stop here and fail fatally. */
> if (datarefs->length ()
> > (unsigned)PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS))
> - return false;
> + return opt_result::failure_at (stmt, "exceeded param "
> + "loop-max-datarefs-for-datadeps\n");
> }
> - return true;
> + return opt_result::success ();
> }
>
> /* Function vect_analyze_loop_2.
> @@ -1798,10 +1756,10 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
> Apply a set of analyses on LOOP, and create a loop_vec_info struct
> for it. The different analyses will record information in the
> loop_vec_info struct. */
> -static bool
> +static opt_result
> vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> {
> - bool ok;
> + opt_result ok = opt_result::success ();
> int res;
> unsigned int max_vf = MAX_VECTORIZATION_FACTOR;
> poly_uint64 min_vf = 2;
> @@ -1817,16 +1775,18 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> /* Gather the data references and count stmts in the loop. */
> if (!LOOP_VINFO_DATAREFS (loop_vinfo).exists ())
> {
> - if (!vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
> - &LOOP_VINFO_DATAREFS (loop_vinfo),
> - n_stmts))
> + opt_result res
> + = vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
> + &LOOP_VINFO_DATAREFS (loop_vinfo),
> + n_stmts);
> + if (!res)
> {
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "not vectorized: loop contains function "
> "calls or data references that cannot "
> "be analyzed\n");
> - return false;
> + return res;
> }
> loop_vinfo->shared->save_datarefs ();
> }
> @@ -1842,7 +1802,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "bad data references.\n");
> - return false;
> + return ok;
> }
>
> /* Classify all cross-iteration scalar data-flow cycles.
> @@ -1862,7 +1822,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "bad data access.\n");
> - return false;
> + return ok;
> }
>
> /* Data-flow analysis to detect stmts that do not need to be vectorized. */
> @@ -1873,7 +1833,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "unexpected pattern.\n");
> - return false;
> + return ok;
> }
>
> /* While the rest of the analysis below depends on it in some way. */
> @@ -1885,15 +1845,16 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> FORNOW: fail at the first data dependence that we encounter. */
>
> ok = vect_analyze_data_ref_dependences (loop_vinfo, &max_vf);
> - if (!ok
> - || (max_vf != MAX_VECTORIZATION_FACTOR
> - && maybe_lt (max_vf, min_vf)))
> + if (!ok)
> {
> if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "bad data dependence.\n");
> - return false;
> + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> + "bad data dependence.\n");
> + return ok;
> }
> + if (max_vf != MAX_VECTORIZATION_FACTOR
> + && maybe_lt (max_vf, min_vf))
> + return opt_result::failure_at (vect_location, "bad data dependence.\n");
> LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) = max_vf;
>
> ok = vect_determine_vectorization_factor (loop_vinfo);
> @@ -1902,16 +1863,11 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "can't determine vectorization factor.\n");
> - return false;
> + return ok;
> }
> if (max_vf != MAX_VECTORIZATION_FACTOR
> && maybe_lt (max_vf, LOOP_VINFO_VECT_FACTOR (loop_vinfo)))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "bad data dependence.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location, "bad data dependence.\n");
>
> /* Compute the scalar iteration cost. */
> vect_compute_single_scalar_iteration_cost (loop_vinfo);
> @@ -1922,7 +1878,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
> /* Check the SLP opportunities in the loop, analyze and build SLP trees. */
> ok = vect_analyze_slp (loop_vinfo, *n_stmts);
> if (!ok)
> - return false;
> + return ok;
>
> /* If there are any SLP instances mark them as pure_slp. */
> bool slp = vect_make_slp_decision (loop_vinfo);
> @@ -1969,7 +1925,7 @@ start_over:
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "bad data alignment.\n");
> - return false;
> + return ok;
> }
>
> /* Prune the list of ddrs to be tested at run-time by versioning for alias.
> @@ -1977,7 +1933,7 @@ start_over:
> since we use grouping information gathered by interleaving analysis. */
> ok = vect_prune_runtime_alias_test_list (loop_vinfo);
> if (!ok)
> - return false;
> + return ok;
>
> /* Do not invoke vect_enhance_data_refs_alignment for epilogue
> vectorization, since we do not want to add extra peeling or
> @@ -1989,12 +1945,7 @@ start_over:
> else
> ok = vect_verify_datarefs_alignment (loop_vinfo);
> if (!ok)
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "bad data alignment.\n");
> - return false;
> - }
> + return ok;
>
> if (slp)
> {
> @@ -2004,7 +1955,11 @@ start_over:
> unsigned old_size = LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length ();
> vect_slp_analyze_operations (loop_vinfo);
> if (LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length () != old_size)
> - goto again;
> + {
> + ok = opt_result::failure_at (vect_location,
> + "unsupported SLP instances\n");
> + goto again;
> + }
> }
>
> /* Scan all the remaining operations in the loop that are not subject
> @@ -2015,7 +1970,7 @@ start_over:
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "bad operation or unsupported loop bound.\n");
> - return false;
> + return ok;
> }
>
> /* Decide whether to use a fully-masked loop for this vectorization
> @@ -2044,26 +1999,22 @@ start_over:
> tree scalar_niters = LOOP_VINFO_NITERSM1 (loop_vinfo);
>
> if (known_lt (wi::to_widest (scalar_niters), vf))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_NOTE, vect_location,
> - "loop has no enough iterations to support"
> - " peeling for gaps.\n");
> - return false;
> - }
> + return opt_result::failure_at (vect_location,
> + "loop has no enough iterations to"
> + " support peeling for gaps.\n");
> }
>
> /* Check the costings of the loop make vectorizing worthwhile. */
> res = vect_analyze_loop_costing (loop_vinfo);
> if (res < 0)
> - goto again;
> - if (!res)
> {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "Loop costings not worthwhile.\n");
> - return false;
> + ok = opt_result::failure_at (vect_location,
> + "Loop costings may not be worthwhile.\n");
> + goto again;
> }
> + if (!res)
> + return opt_result::failure_at (vect_location,
> + "Loop costings not worthwhile.\n");
>
> /* Decide whether we need to create an epilogue loop to handle
> remaining scalar iterations. */
> @@ -2112,10 +2063,9 @@ start_over:
> single_exit (LOOP_VINFO_LOOP
> (loop_vinfo))))
> {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: can't create required "
> - "epilog loop\n");
> + ok = opt_result::failure_at (vect_location,
> + "not vectorized: can't create required "
> + "epilog loop\n");
> goto again;
> }
> }
> @@ -2154,17 +2104,20 @@ start_over:
> LOOP_VINFO_VECT_FACTOR (loop_vinfo)));
>
> /* Ok to vectorize! */
> - return true;
> + return opt_result::success ();
>
> again:
> + /* Ensure that "ok" is false (with an opt_problem if dumping is enabled). */
> + gcc_assert (!ok);
> +
> /* Try again with SLP forced off but if we didn't do any SLP there is
> no point in re-trying. */
> if (!slp)
> - return false;
> + return ok;
>
> /* If there are reduction chains re-trying will fail anyway. */
> if (! LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo).is_empty ())
> - return false;
> + return ok;
>
> /* Likewise if the grouped loads or stores in the SLP cannot be handled
> via interleaving or lane instructions. */
> @@ -2183,7 +2136,8 @@ again:
> if (! vect_store_lanes_supported (vectype, size, false)
> && ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)
> && ! vect_grouped_store_supported (vectype, size))
> - return false;
> + return opt_result::failure_at (vinfo->stmt,
> + "unsupported grouped store\n");
> FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), j, node)
> {
> vinfo = SLP_TREE_SCALAR_STMTS (node)[0];
> @@ -2194,7 +2148,8 @@ again:
> if (! vect_load_lanes_supported (vectype, size, false)
> && ! vect_grouped_load_supported (vectype, single_element_p,
> size))
> - return false;
> + return opt_result::failure_at (vinfo->stmt,
> + "unsupported grouped load\n");
> }
> }
>
> @@ -2263,11 +2218,10 @@ again:
> for it. The different analyses will record information in the
> loop_vec_info struct. If ORIG_LOOP_VINFO is not NULL epilogue must
> be vectorized. */
> -loop_vec_info
> +opt_loop_vec_info
> vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
> vec_info_shared *shared)
> {
> - loop_vec_info loop_vinfo;
> auto_vector_sizes vector_sizes;
>
> /* Autodetect first vector size we try. */
> @@ -2280,35 +2234,28 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
> if (loop_outer (loop)
> && loop_vec_info_for_loop (loop_outer (loop))
> && LOOP_VINFO_VECTORIZABLE_P (loop_vec_info_for_loop (loop_outer (loop))))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_NOTE, vect_location,
> - "outer-loop already vectorized.\n");
> - return NULL;
> - }
> + return opt_loop_vec_info::failure_at (vect_location,
> + "outer-loop already vectorized.\n");
>
> if (!find_loop_nest (loop, &shared->loop_nest))
> - {
> - if (dump_enabled_p ())
> - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> - "not vectorized: loop nest containing two "
> - "or more consecutive inner loops cannot be "
> - "vectorized\n");
> - return NULL;
> - }
> + return opt_loop_vec_info::failure_at
> + (vect_location,
> + "not vectorized: loop nest containing two or more consecutive inner"
> + " loops cannot be vectorized\n");
>
> unsigned n_stmts = 0;
> poly_uint64 autodetected_vector_size = 0;
> while (1)
> {
> /* Check the CFG characteristics of the loop (nesting, entry/exit). */
> - loop_vinfo = vect_analyze_loop_form (loop, shared);
> + opt_loop_vec_info loop_vinfo
> + = vect_analyze_loop_form (loop, shared);
> if (!loop_vinfo)
> {
> if (dump_enabled_p ())
> dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> "bad loop form.\n");
> - return NULL;
> + return loop_vinfo;
> }
>
> bool fatal = false;
> @@ -2316,7 +2263,8 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
> if (orig_loop_vinfo)
> LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = orig_loop_vinfo;
>
> - if (vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts))
> + opt_result res = vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts);
> + if (res)
> {
> LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
>
> @@ -2335,7 +2283,7 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
> if (fatal
> || next_size == vector_sizes.length ()
> || known_eq (current_vector_size, 0U))
> - return NULL;
> + return opt_loop_vec_info::propagate_failure (res);
>
> /* Try the next biggest vector size. */
> current_vector_size = vector_sizes[next_size++];
> diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
> index ae1c453..f60fea0 100644
> --- a/gcc/tree-vect-slp.c
> +++ b/gcc/tree-vect-slp.c
> @@ -2071,7 +2071,7 @@ vect_analyze_slp_instance (vec_info *vinfo,
> /* 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;
> @@ -2111,7 +2111,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
> max_tree_size);
> }
>
> - return true;
> + return opt_result::success ();
> }
>
>
> diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
> index 7a6efdb..8108d52 100644
> --- a/gcc/tree-vect-stmts.c
> +++ b/gcc/tree-vect-stmts.c
> @@ -448,7 +448,7 @@ exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
>
> 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)
> @@ -460,18 +460,15 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
> /* 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);
>
> @@ -493,7 +490,7 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
> 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:
> @@ -582,12 +579,12 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
> 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 ();
> }
>
>
> @@ -607,7 +604,7 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
>
> 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);
> @@ -684,38 +681,24 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info 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:
> @@ -735,20 +718,28 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
> 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))
> @@ -756,9 +747,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
> 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;
> }
> }
> }
> @@ -766,9 +759,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
> 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))
> @@ -776,13 +771,15 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_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. */
> @@ -9382,7 +9379,7 @@ can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
>
> /* 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)
> @@ -9398,13 +9395,10 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
> 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
> @@ -9425,10 +9419,12 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
> "==> 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;
> }
> }
> }
> @@ -9468,7 +9464,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
> 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)
> @@ -9483,9 +9479,11 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
> "==> 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))
> @@ -9528,7 +9526,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
> {
> dump_printf_loc (MSG_NOTE, vect_location,
> "handled only by SLP analysis\n");
> - return true;
> + return opt_result::success ();
> }
>
> ok = true;
> @@ -9573,30 +9571,22 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
> }
>
> 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 ();
> }
>
>
> @@ -10537,7 +10527,7 @@ vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
> 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)
> @@ -10560,22 +10550,17 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
> 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;
> @@ -10606,7 +10591,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
> if (dump_enabled_p ())
> dump_printf_loc (MSG_NOTE, vect_location,
> "pure bool operation.\n");
> - return true;
> + return opt_result::success ();
> }
> }
>
> @@ -10615,13 +10600,10 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
> "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;
> @@ -10652,24 +10634,16 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
> 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 ())
> {
> @@ -10682,14 +10656,14 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
> }
>
> *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;
> @@ -10704,12 +10678,8 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
> 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
> {
> @@ -10720,13 +10690,9 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
> 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
> @@ -10738,25 +10704,17 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
> 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.
> @@ -10770,9 +10728,10 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
>
> /* 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);
> }
> diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
> index 23bddf3..747fb67 100644
> --- a/gcc/tree-vectorizer.c
> +++ b/gcc/tree-vectorizer.c
> @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
> #include "stringpool.h"
> #include "attribs.h"
> #include "gimple-pretty-print.h"
> +#include "opt-problem.h"
>
>
> /* Loop or bb location, with hotness information. */
> @@ -860,13 +861,25 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
> 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
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index af5d5bf..63cff79 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -612,6 +612,12 @@ typedef struct _loop_vec_info : public vec_info {
> #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)
> {
> @@ -1473,7 +1479,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int,
> 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);
> @@ -1487,8 +1493,8 @@ extern tree vect_get_vec_def_for_stmt_copy (vec_info *, tree);
> 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 *);
> @@ -1504,8 +1510,9 @@ extern tree vect_gen_perm_mask_checked (tree, const vec_perm_indices &);
> 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);
> @@ -1513,21 +1520,21 @@ extern enum dr_alignment_support vect_supportable_dr_alignment
> (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 *,
> @@ -1563,8 +1570,9 @@ extern stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info,
> 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);
> @@ -1577,7 +1585,8 @@ extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *,
>
> /* 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 *);
> @@ -1602,7 +1611,7 @@ extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> ,
> 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> > *);
>
--
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
More information about the Gcc-patches
mailing list