Commit f4ebbd24 by David Malcolm Committed by David Malcolm

Report vectorization problems via a new opt_problem class

This is v3 of the patch; previous versions were:
  v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html
  v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html

This patch introduces a class opt_problem, along with wrapper
classes for bool (opt_result) and for pointers (e.g. opt_loop_vec_info
for loop_vec_info).

opt_problem instances are created when an optimization problem
is encountered, but only if dump_enabled_p.  They are manually
propagated up the callstack, and are manually reported at the
"top level" of an optimization if dumping is enabled, to give the user
a concise summary of the problem *after* the failure is reported.
In particular, the location of the problematic statement is
captured and emitted, rather than just the loop's location.

For example:

no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop
no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__ __volatile__("" :  :  : "memory");

Changed in v3:
* This version bootstraps and passes regression testing (on
  x86_64-pc-linux-gnu).
* added selftests, to exercise the opt_problem machinery
* removed the "bool to opt_result" ctor, so that attempts to
  use e.g. return a bool from an opt_result-returning function
  will fail at compile time
* use formatted printing within opt_problem ctor to replace the
  various dump_printf_loc calls
* dropped i18n
* changed the sense of vect_analyze_data_ref_dependence's return
  value (see the ChangeLog)
* add MSG_PRIORITY_REEMITTED, so that -fopt-info can show the
  messages, without them messing up the counts in scan-tree-dump-times
  in DejaGnu tests

gcc/ChangeLog:
	* Makefile.in (OBJS): Add opt-problem.o.
	* dump-context.h: Include "selftest.h.
	(selftest::temp_dump_context): New forward decl.
	(class dump_context): Make friend of class
	selftest::temp_dump_context.
	(dump_context::dump_loc_immediate): New decl.
	(class dump_pretty_printer): Move here from dumpfile.c.
	(class temp_dump_context): Move to namespace selftest.
	(temp_dump_context::temp_dump_context): Add param
	"forcibly_enable_dumping".
	(selftest::verify_dumped_text):
	(ASSERT_DUMPED_TEXT_EQ): Move here from dumpfile.c.
	(selftest::verify_item):
	(ASSERT_IS_TEXT): Move here from dumpfile.c.
	(ASSERT_IS_TREE): Likewise.
	(ASSERT_IS_GIMPLE): Likewise.
	* dumpfile.c (dump_context::dump_loc): Move immediate dumping
	to...
	(dump_context::dump_loc_immediate): ...this new function.
	(class dump_pretty_printer): Move to dump-context.h.
	(dump_switch_p_1): Don't enable MSG_PRIORITY_REEMITTED.
	(opt_info_switch_p_1): Enable MSG_PRIORITY_REEMITTED.
	(temp_dump_context::temp_dump_context): Move to "selftest"
	namespace.  Add param "forcibly_enable_dumping", and use it to
	conditionalize the use of m_pp;
	(selftest::verify_dumped_text): Make non-static.
	(ASSERT_DUMPED_TEXT_EQ): Move to dump-context.h.
	(selftest::verify_item): Make non-static.
	(ASSERT_IS_TEXT): Move to dump-context.h.
	(ASSERT_IS_TREE): Likewise.
	(ASSERT_IS_GIMPLE): Likewise.
	(selftest::test_capture_of_dump_calls): Pass "true" for new
	param of temp_dump_context.
	* dumpfile.h (enum dump_flag): Add MSG_PRIORITY_REEMITTED, adding
	it to MSG_ALL_PRIORITIES.  Update values of TDF_COMPARE_DEBUG and
	TDF_COMPARE_DEBUG.
	* opt-problem.cc: New file.
	* opt-problem.h: New file.
	* optinfo-emit-json.cc
	(selftest::test_building_json_from_dump_calls): Pass "true" for
	new param of temp_dump_context.
	* optinfo.cc (optinfo_kind_to_dump_flag): New function.
	(optinfo::emit_for_opt_problem): New function.
	(optinfo::emit): Clarity which emit_item is used.
	* optinfo.h (optinfo::get_dump_location): New accessor.
	(optinfo::emit_for_opt_problem): New decl.
	(optinfo::emit): Make const.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::opt_problem_cc_tests.
	* selftest.h (selftest::opt_problem_cc_tests): New decl.
	* tree-data-ref.c (dr_analyze_innermost): Convert return type from
	bool to opt_result, converting fprintf messages to
	opt_result::failure_at calls.  Add "stmt" param for use by the
	failure_at calls.
	(create_data_ref): Pass "stmt" to the dr_analyze_innermost call.
	(runtime_alias_check_p): Convert return type from bool to
	opt_result, converting dump_printf calls to
	opt_result::failure_at, using the statement DDR_A for their
	location.
	(find_data_references_in_stmt): Convert return type from bool to
	opt_result, converting "return false" to opt_result::failure_at
	with a new message.
	* tree-data-ref.h: Include "opt-problem.h".
	(dr_analyze_innermost): Convert return type from bool to opt_result,
	and add a const gimple * param.
	(find_data_references_in_stmt): Convert return type from bool to
	opt_result.
	(runtime_alias_check_p): Likewise.
	* tree-predcom.c (find_looparound_phi): Pass "init_stmt" to
	dr_analyze_innermost.
	* tree-vect-data-refs.c (vect_mark_for_runtime_alias_test):
	Convert return type from bool to opt_result, adding a message for
	the PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS zero case.
	(vect_analyze_data_ref_dependence): Convert return type from bool
	to opt_result.  Change sense of return type from "false"
	effectively meaning "no problems" to "false" meaning a problem,
	so that "return false" becomes "return opt_result::success".
	Convert "return true" calls to opt_result::failure_at, using
	the location of statement A rather than vect_location.
	(vect_analyze_data_ref_dependences): Convert return type from bool
	to opt_result.
	(verify_data_ref_alignment): Likewise, converting dump_printf_loc
	calls to opt_result::failure_at, using the stmt location rather
	than vect_location.
	(vect_verify_datarefs_alignment): Convert return type from bool
	to opt_result.
	(vect_enhance_data_refs_alignment): Likewise.  Split local "stat"
	into multiple more-tightly-scoped copies.
	(vect_analyze_data_refs_alignment): Convert return type from bool
	to opt_result.
	(vect_analyze_data_ref_accesses): Likewise, converting a
	"return false" to a "return opt_result::failure_at", adding a
	new message.
	(vect_prune_runtime_alias_test_list): Convert return type from
	bool to opt_result, converting dump_printf_loc to
	opt_result::failure_at.  Add a %G to show the pertinent statement,
	and use the stmt's location rather than vect_location.
	(vect_find_stmt_data_reference): Convert return type from
	bool to opt_result, converting dump_printf_loc to
	opt_result::failure_at, using stmt's location.
	(vect_analyze_data_refs):  Convert return type from bool to
	opt_result.  Convert "return false" to "return
	opt_result::failure_at", adding messages as needed.
	* tree-vect-loop.c (vect_determine_vf_for_stmt_1): Convert return
	type from bool to opt_result.
	(vect_determine_vf_for_stmt): Likewise.
	(vect_determine_vectorization_factor): Likewise, converting
	dump_printf_loc to opt_result::failure_at, using location of phi
	rather than vect_location.
	(vect_analyze_loop_form_1): Convert return type from bool to
	opt_result, converting dump_printf_loc calls, retaining the use of
	vect_location.
	(vect_analyze_loop_form): Convert return type from loop_vec_info
	to opt_loop_vec_info.
	(vect_analyze_loop_operations): Convert return type from bool to
	opt_result, converting dump_printf_loc calls, using the location
	of phi/stmt rather than vect_location where available.  Convert
	various "return false" to "return opt_result::failure_at" with
	"unsupported phi" messages.
	(vect_get_datarefs_in_loop): Convert return type from bool to
	opt_result.  Add a message for the
	PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS failure.
	(vect_analyze_loop_2): Convert return type from bool to
	opt_result.  Ensure "ok" is set to a opt_result::failure_at before
	each "goto again;", adding new messages where needed.
	Add "unsupported grouped {store|load}" messages.
	(vect_analyze_loop): Convert return type from loop_vec_info to
	opt_loop_vec_info.
	* tree-vect-slp.c (vect_analyze_slp): Convert return type from
	bool to opt_result.
	* tree-vect-stmts.c (process_use): Likewise, converting
	dump_printf_loc call and using stmt location, rather than
	vect_location.
	(vect_mark_stmts_to_be_vectorized): Likeise.
	(vect_analyze_stmt): Likewise, adding a %G.
	(vect_get_vector_types_for_stmt): Convert return type from bool to
	opt_result, converting dump_printf_loc calls and using stmt
	location, rather than vect_location.
	(vect_get_mask_type_for_stmt): Convert return type from tree to
	opt_tree, converting dump_printf_loc calls and using stmt location.
	* tree-vectorizer.c: Include "opt-problem.h.
	(try_vectorize_loop_1): Flag "Analyzing loop at" dump message as
	MSG_PRIORITY_INTERNALS.  Convert local "loop_vinfo" from
	loop_vec_info to opt_loop_vec_info.  If if fails, and dumping is
	enabled, use it to report at the top level "couldn't vectorize
	loop" followed by the problem.
	* tree-vectorizer.h (opt_loop_vec_info): New typedef.
	(vect_mark_stmts_to_be_vectorized): Convert return type from bool
	to opt_result.
	(vect_analyze_stmt): Likewise.
	(vect_get_vector_types_for_stmt): Likewise.
	(tree vect_get_mask_type_for_stmt): Likewise.
	(vect_analyze_data_ref_dependences): Likewise.
	(vect_enhance_data_refs_alignment): Likewise.
	(vect_analyze_data_refs_alignment): Likewise.
	(vect_verify_datarefs_alignment): Likewise.
	(vect_analyze_data_ref_accesses): Likewise.
	(vect_prune_runtime_alias_test_list): Likewise.
	(vect_find_stmt_data_reference): Likewise.
	(vect_analyze_data_refs): Likewise.
	(vect_analyze_loop): Convert return type from loop_vec_info to
	opt_loop_vec_info.
	(vect_analyze_loop_form): Likewise.
	(vect_analyze_slp): Convert return type from bool to opt_result.

gcc/testsuite/ChangeLog:
	* gcc.dg/vect/nodump-vect-opt-info-2.c: New test.
	* gcc.dg/vect/vect-alias-check-4.c: Add "-fopt-info-vec-all" to
	dg-additional-options.  Add dg-message and dg-missed directives
	to verify that -fopt-info messages are written at the correct
	locations.

From-SVN: r264852
parent 7db960c5
2018-10-04 David Malcolm <dmalcolm@redhat.com> 2018-10-04 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (OBJS): Add opt-problem.o.
* dump-context.h: Include "selftest.h.
(selftest::temp_dump_context): New forward decl.
(class dump_context): Make friend of class
selftest::temp_dump_context.
(dump_context::dump_loc_immediate): New decl.
(class dump_pretty_printer): Move here from dumpfile.c.
(class temp_dump_context): Move to namespace selftest.
(temp_dump_context::temp_dump_context): Add param
"forcibly_enable_dumping".
(selftest::verify_dumped_text):
(ASSERT_DUMPED_TEXT_EQ): Move here from dumpfile.c.
(selftest::verify_item):
(ASSERT_IS_TEXT): Move here from dumpfile.c.
(ASSERT_IS_TREE): Likewise.
(ASSERT_IS_GIMPLE): Likewise.
* dumpfile.c (dump_context::dump_loc): Move immediate dumping
to...
(dump_context::dump_loc_immediate): ...this new function.
(class dump_pretty_printer): Move to dump-context.h.
(dump_switch_p_1): Don't enable MSG_PRIORITY_REEMITTED.
(opt_info_switch_p_1): Enable MSG_PRIORITY_REEMITTED.
(temp_dump_context::temp_dump_context): Move to "selftest"
namespace. Add param "forcibly_enable_dumping", and use it to
conditionalize the use of m_pp;
(selftest::verify_dumped_text): Make non-static.
(ASSERT_DUMPED_TEXT_EQ): Move to dump-context.h.
(selftest::verify_item): Make non-static.
(ASSERT_IS_TEXT): Move to dump-context.h.
(ASSERT_IS_TREE): Likewise.
(ASSERT_IS_GIMPLE): Likewise.
(selftest::test_capture_of_dump_calls): Pass "true" for new
param of temp_dump_context.
* dumpfile.h (enum dump_flag): Add MSG_PRIORITY_REEMITTED, adding
it to MSG_ALL_PRIORITIES. Update values of TDF_COMPARE_DEBUG and
TDF_COMPARE_DEBUG.
* opt-problem.cc: New file.
* opt-problem.h: New file.
* optinfo-emit-json.cc
(selftest::test_building_json_from_dump_calls): Pass "true" for
new param of temp_dump_context.
* optinfo.cc (optinfo_kind_to_dump_flag): New function.
(optinfo::emit_for_opt_problem): New function.
(optinfo::emit): Clarity which emit_item is used.
* optinfo.h (optinfo::get_dump_location): New accessor.
(optinfo::emit_for_opt_problem): New decl.
(optinfo::emit): Make const.
* selftest-run-tests.c (selftest::run_tests): Call
selftest::opt_problem_cc_tests.
* selftest.h (selftest::opt_problem_cc_tests): New decl.
* tree-data-ref.c (dr_analyze_innermost): Convert return type from
bool to opt_result, converting fprintf messages to
opt_result::failure_at calls. Add "stmt" param for use by the
failure_at calls.
(create_data_ref): Pass "stmt" to the dr_analyze_innermost call.
(runtime_alias_check_p): Convert return type from bool to
opt_result, converting dump_printf calls to
opt_result::failure_at, using the statement DDR_A for their
location.
(find_data_references_in_stmt): Convert return type from bool to
opt_result, converting "return false" to opt_result::failure_at
with a new message.
* tree-data-ref.h: Include "opt-problem.h".
(dr_analyze_innermost): Convert return type from bool to opt_result,
and add a const gimple * param.
(find_data_references_in_stmt): Convert return type from bool to
opt_result.
(runtime_alias_check_p): Likewise.
* tree-predcom.c (find_looparound_phi): Pass "init_stmt" to
dr_analyze_innermost.
* tree-vect-data-refs.c (vect_mark_for_runtime_alias_test):
Convert return type from bool to opt_result, adding a message for
the PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS zero case.
(vect_analyze_data_ref_dependence): Convert return type from bool
to opt_result. Change sense of return type from "false"
effectively meaning "no problems" to "false" meaning a problem,
so that "return false" becomes "return opt_result::success".
Convert "return true" calls to opt_result::failure_at, using
the location of statement A rather than vect_location.
(vect_analyze_data_ref_dependences): Convert return type from bool
to opt_result.
(verify_data_ref_alignment): Likewise, converting dump_printf_loc
calls to opt_result::failure_at, using the stmt location rather
than vect_location.
(vect_verify_datarefs_alignment): Convert return type from bool
to opt_result.
(vect_enhance_data_refs_alignment): Likewise. Split local "stat"
into multiple more-tightly-scoped copies.
(vect_analyze_data_refs_alignment): Convert return type from bool
to opt_result.
(vect_analyze_data_ref_accesses): Likewise, converting a
"return false" to a "return opt_result::failure_at", adding a
new message.
(vect_prune_runtime_alias_test_list): Convert return type from
bool to opt_result, converting dump_printf_loc to
opt_result::failure_at. Add a %G to show the pertinent statement,
and use the stmt's location rather than vect_location.
(vect_find_stmt_data_reference): Convert return type from
bool to opt_result, converting dump_printf_loc to
opt_result::failure_at, using stmt's location.
(vect_analyze_data_refs): Convert return type from bool to
opt_result. Convert "return false" to "return
opt_result::failure_at", adding messages as needed.
* tree-vect-loop.c (vect_determine_vf_for_stmt_1): Convert return
type from bool to opt_result.
(vect_determine_vf_for_stmt): Likewise.
(vect_determine_vectorization_factor): Likewise, converting
dump_printf_loc to opt_result::failure_at, using location of phi
rather than vect_location.
(vect_analyze_loop_form_1): Convert return type from bool to
opt_result, converting dump_printf_loc calls, retaining the use of
vect_location.
(vect_analyze_loop_form): Convert return type from loop_vec_info
to opt_loop_vec_info.
(vect_analyze_loop_operations): Convert return type from bool to
opt_result, converting dump_printf_loc calls, using the location
of phi/stmt rather than vect_location where available. Convert
various "return false" to "return opt_result::failure_at" with
"unsupported phi" messages.
(vect_get_datarefs_in_loop): Convert return type from bool to
opt_result. Add a message for the
PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS failure.
(vect_analyze_loop_2): Convert return type from bool to
opt_result. Ensure "ok" is set to a opt_result::failure_at before
each "goto again;", adding new messages where needed.
Add "unsupported grouped {store|load}" messages.
(vect_analyze_loop): Convert return type from loop_vec_info to
opt_loop_vec_info.
* tree-vect-slp.c (vect_analyze_slp): Convert return type from
bool to opt_result.
* tree-vect-stmts.c (process_use): Likewise, converting
dump_printf_loc call and using stmt location, rather than
vect_location.
(vect_mark_stmts_to_be_vectorized): Likeise.
(vect_analyze_stmt): Likewise, adding a %G.
(vect_get_vector_types_for_stmt): Convert return type from bool to
opt_result, converting dump_printf_loc calls and using stmt
location, rather than vect_location.
(vect_get_mask_type_for_stmt): Convert return type from tree to
opt_tree, converting dump_printf_loc calls and using stmt location.
* tree-vectorizer.c: Include "opt-problem.h.
(try_vectorize_loop_1): Flag "Analyzing loop at" dump message as
MSG_PRIORITY_INTERNALS. Convert local "loop_vinfo" from
loop_vec_info to opt_loop_vec_info. If if fails, and dumping is
enabled, use it to report at the top level "couldn't vectorize
loop" followed by the problem.
* tree-vectorizer.h (opt_loop_vec_info): New typedef.
(vect_mark_stmts_to_be_vectorized): Convert return type from bool
to opt_result.
(vect_analyze_stmt): Likewise.
(vect_get_vector_types_for_stmt): Likewise.
(tree vect_get_mask_type_for_stmt): Likewise.
(vect_analyze_data_ref_dependences): Likewise.
(vect_enhance_data_refs_alignment): Likewise.
(vect_analyze_data_refs_alignment): Likewise.
(vect_verify_datarefs_alignment): Likewise.
(vect_analyze_data_ref_accesses): Likewise.
(vect_prune_runtime_alias_test_list): Likewise.
(vect_find_stmt_data_reference): Likewise.
(vect_analyze_data_refs): Likewise.
(vect_analyze_loop): Convert return type from loop_vec_info to
opt_loop_vec_info.
(vect_analyze_loop_form): Likewise.
(vect_analyze_slp): Convert return type from bool to opt_result.
2018-10-04 David Malcolm <dmalcolm@redhat.com>
* doc/invoke.texi (-fopt-info): Document new "internals" * doc/invoke.texi (-fopt-info): Document new "internals"
sub-option. sub-option.
* dump-context.h (dump_context::apply_dump_filter_p): New decl. * dump-context.h (dump_context::apply_dump_filter_p): New decl.
...@@ -1423,6 +1423,7 @@ OBJS = \ ...@@ -1423,6 +1423,7 @@ OBJS = \
omp-grid.o \ omp-grid.o \
omp-low.o \ omp-low.o \
omp-simd-clone.o \ omp-simd-clone.o \
opt-problem.o \
optabs.o \ optabs.o \
optabs-libfuncs.o \ optabs-libfuncs.o \
optabs-query.o \ optabs-query.o \
......
...@@ -24,6 +24,9 @@ along with GCC; see the file COPYING3. If not see ...@@ -24,6 +24,9 @@ along with GCC; see the file COPYING3. If not see
#include "dumpfile.h" #include "dumpfile.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "selftest.h"
namespace selftest { class temp_dump_context; }
/* A class for handling the various dump_* calls. /* A class for handling the various dump_* calls.
...@@ -36,7 +39,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -36,7 +39,8 @@ along with GCC; see the file COPYING3. If not see
class dump_context class dump_context
{ {
friend class temp_dump_context; friend class selftest::temp_dump_context;
public: public:
static dump_context &get () { return *s_current; } static dump_context &get () { return *s_current; }
...@@ -45,6 +49,7 @@ class dump_context ...@@ -45,6 +49,7 @@ class dump_context
void refresh_dumps_are_enabled (); void refresh_dumps_are_enabled ();
void dump_loc (dump_flags_t dump_kind, const dump_location_t &loc); 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, void dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
gimple *gs, int spc); gimple *gs, int spc);
...@@ -129,8 +134,53 @@ class dump_context ...@@ -129,8 +134,53 @@ class dump_context
static dump_context s_default; 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 #if CHECKING_P
namespace selftest {
/* An RAII-style class for use in selftests for temporarily using a different /* An RAII-style class for use in selftests for temporarily using a different
dump_context. */ dump_context. */
...@@ -138,6 +188,7 @@ class temp_dump_context ...@@ -138,6 +188,7 @@ class temp_dump_context
{ {
public: public:
temp_dump_context (bool forcibly_enable_optinfo, temp_dump_context (bool forcibly_enable_optinfo,
bool forcibly_enable_dumping,
dump_flags_t test_pp_flags); dump_flags_t test_pp_flags);
~temp_dump_context (); ~temp_dump_context ();
...@@ -151,6 +202,57 @@ class temp_dump_context ...@@ -151,6 +202,57 @@ class temp_dump_context
dump_context *m_saved; 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 /* CHECKING_P */
#endif /* GCC_DUMP_CONTEXT_H */ #endif /* GCC_DUMP_CONTEXT_H */
...@@ -179,15 +179,22 @@ enum dump_flag ...@@ -179,15 +179,22 @@ enum dump_flag
/* Implicitly supplied for messages within nested dump scopes. */ /* Implicitly supplied for messages within nested dump scopes. */
MSG_PRIORITY_INTERNALS = (1 << 26), 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. */ /* Mask for selecting MSG_PRIORITY_* flags. */
MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
| MSG_PRIORITY_INTERNALS), | MSG_PRIORITY_INTERNALS
| MSG_PRIORITY_REEMITTED),
/* Dumping for -fcompare-debug. */ /* Dumping for -fcompare-debug. */
TDF_COMPARE_DEBUG = (1 << 27), TDF_COMPARE_DEBUG = (1 << 28),
/* All values. */ /* All values. */
TDF_ALL_VALUES = (1 << 28) - 1 TDF_ALL_VALUES = (1 << 29) - 1
}; };
/* Dump flags type. */ /* Dump flags type. */
......
/* 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 */
...@@ -531,7 +531,7 @@ namespace selftest { ...@@ -531,7 +531,7 @@ namespace selftest {
static void static void
test_building_json_from_dump_calls () 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_location_t loc;
dump_printf_loc (MSG_NOTE, loc, "test of tree: "); dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node); dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
......
...@@ -89,11 +89,51 @@ optinfo::add_item (optinfo_item *item) ...@@ -89,11 +89,51 @@ optinfo::add_item (optinfo_item *item)
m_items.safe_push (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 /* 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 void
optinfo::emit () optinfo::emit () const
{ {
/* -fsave-optimization-record. */ /* -fsave-optimization-record. */
optimization_records_maybe_record_optinfo (this); optimization_records_maybe_record_optinfo (this);
......
...@@ -108,6 +108,9 @@ class optinfo ...@@ -108,6 +108,9 @@ class optinfo
{} {}
~optinfo (); ~optinfo ();
const dump_location_t &
get_dump_location () const { return m_loc; }
const dump_user_location_t & const dump_user_location_t &
get_user_location () const { return m_loc.get_user_location (); } get_user_location () const { return m_loc.get_user_location (); }
...@@ -124,8 +127,10 @@ class optinfo ...@@ -124,8 +127,10 @@ class optinfo
void add_item (optinfo_item *item); void add_item (optinfo_item *item);
void emit_for_opt_problem () const;
private: private:
void emit (); void emit () const;
/* Pre-canned ways of manipulating the optinfo, for use by friend class /* Pre-canned ways of manipulating the optinfo, for use by friend class
dump_context. */ dump_context. */
......
...@@ -74,6 +74,7 @@ selftest::run_tests () ...@@ -74,6 +74,7 @@ selftest::run_tests ()
opt_proposer_c_tests (); opt_proposer_c_tests ();
json_cc_tests (); json_cc_tests ();
optinfo_emit_json_cc_tests (); optinfo_emit_json_cc_tests ();
opt_problem_cc_tests ();
/* Mid-level data structures. */ /* Mid-level data structures. */
input_c_tests (); input_c_tests ();
......
...@@ -229,6 +229,7 @@ extern void hash_map_tests_c_tests (); ...@@ -229,6 +229,7 @@ extern void hash_map_tests_c_tests ();
extern void hash_set_tests_c_tests (); extern void hash_set_tests_c_tests ();
extern void input_c_tests (); extern void input_c_tests ();
extern void json_cc_tests (); extern void json_cc_tests ();
extern void opt_problem_cc_tests ();
extern void optinfo_emit_json_cc_tests (); extern void optinfo_emit_json_cc_tests ();
extern void predict_c_tests (); extern void predict_c_tests ();
extern void pretty_print_c_tests (); extern void pretty_print_c_tests ();
......
2018-10-04 David Malcolm <dmalcolm@redhat.com> 2018-10-04 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/vect/nodump-vect-opt-info-2.c: New test.
* gcc.dg/vect/vect-alias-check-4.c: Add "-fopt-info-vec-all" to
dg-additional-options. Add dg-message and dg-missed directives
to verify that -fopt-info messages are written at the correct
locations.
2018-10-04 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/plugin/dump-1.c: Update expected output for test_scopes * gcc.dg/plugin/dump-1.c: Update expected output for test_scopes
due to "-internals" not being selected. due to "-internals" not being selected.
* gcc.dg/plugin/dump-2.c: New test, based on dump-1.c, with * gcc.dg/plugin/dump-2.c: New test, based on dump-1.c, with
......
/* { dg-do compile { target vect_int } } */
/* { dg-additional-options "-fopt-info-vec-all -O3" } */
extern void accumulate (int x, int *a);
int test_missing_function_defn (int *arr, int n) /* { dg-message "vectorized 0 loops in function" } */
{
int sum = 0;
for (int i = 0; i < n; ++i) /* { dg-missed "couldn't vectorize loop" } */
accumulate (arr[i], &sum); /* { dg-missed "statement clobbers memory: accumulate \\(.*\\);" } */
return sum;
}
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-require-effective-target vect_int } */ /* { 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 #define N 16
...@@ -12,24 +12,26 @@ union u { struct s2 f; struct s3 g; }; ...@@ -12,24 +12,26 @@ union u { struct s2 f; struct s3 g; };
/* We allow a and b to overlap arbitrarily. */ /* We allow a and b to overlap arbitrarily. */
void 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]; 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 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]; 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 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) for (int i = 0; i < N - 1; ++i) /* { dg-missed "couldn't vectorize loop" } */
a->a[i + 1] += b->a[i]; a->a[i + 1] += b->a[i]; /* { dg-missed "possible dependence between data-refs" } */
} }
/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ /* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
...@@ -807,7 +807,8 @@ canonicalize_base_object_address (tree addr) ...@@ -807,7 +807,8 @@ canonicalize_base_object_address (tree addr)
return build_fold_addr_expr (TREE_OPERAND (addr, 0)); 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, - BB analysis. In this case we simply split the address into base,
init and offset components, without reference to any containing loop. init and offset components, without reference to any containing loop.
...@@ -827,9 +828,9 @@ canonicalize_base_object_address (tree addr) ...@@ -827,9 +828,9 @@ canonicalize_base_object_address (tree addr)
Return true if the analysis succeeded and store the results in DRB if so. 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. */ BB analysis can only fail for bitfield or reversed-storage accesses. */
bool opt_result
dr_analyze_innermost (innermost_loop_behavior *drb, tree ref, dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
struct loop *loop) struct loop *loop, const gimple *stmt)
{ {
poly_int64 pbitsize, pbitpos; poly_int64 pbitsize, pbitpos;
tree base, poffset; tree base, poffset;
...@@ -848,18 +849,12 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref, ...@@ -848,18 +849,12 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
poly_int64 pbytepos; poly_int64 pbytepos;
if (!multiple_p (pbitpos, BITS_PER_UNIT, &pbytepos)) if (!multiple_p (pbitpos, BITS_PER_UNIT, &pbytepos))
{ return opt_result::failure_at (stmt,
if (dump_file && (dump_flags & TDF_DETAILS)) "failed: bit offset alignment.\n");
fprintf (dump_file, "failed: bit offset alignment.\n");
return false;
}
if (preversep) if (preversep)
{ return opt_result::failure_at (stmt,
if (dump_file && (dump_flags & TDF_DETAILS)) "failed: reverse storage order.\n");
fprintf (dump_file, "failed: reverse storage order.\n");
return false;
}
/* Calculate the alignment and misalignment for the inner reference. */ /* Calculate the alignment and misalignment for the inner reference. */
unsigned int HOST_WIDE_INT bit_base_misalignment; unsigned int HOST_WIDE_INT bit_base_misalignment;
...@@ -895,11 +890,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref, ...@@ -895,11 +890,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
if (in_loop) if (in_loop)
{ {
if (!simple_iv (loop, loop, base, &base_iv, true)) if (!simple_iv (loop, loop, base, &base_iv, true))
{ return opt_result::failure_at
if (dump_file && (dump_flags & TDF_DETAILS)) (stmt, "failed: evolution of base is not affine.\n");
fprintf (dump_file, "failed: evolution of base is not affine.\n");
return false;
}
} }
else else
{ {
...@@ -921,11 +913,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref, ...@@ -921,11 +913,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
offset_iv.step = ssize_int (0); offset_iv.step = ssize_int (0);
} }
else if (!simple_iv (loop, loop, poffset, &offset_iv, true)) else if (!simple_iv (loop, loop, poffset, &offset_iv, true))
{ return opt_result::failure_at
if (dump_file && (dump_flags & TDF_DETAILS)) (stmt, "failed: evolution of offset is not affine.\n");
fprintf (dump_file, "failed: evolution of offset is not affine.\n");
return false;
}
} }
init = ssize_int (pbytepos); init = ssize_int (pbytepos);
...@@ -981,7 +970,7 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref, ...@@ -981,7 +970,7 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "success.\n"); fprintf (dump_file, "success.\n");
return true; return opt_result::success ();
} }
/* Return true if OP is a valid component reference for a DR access /* 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, ...@@ -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_IS_CONDITIONAL_IN_STMT (dr) = is_conditional_in_stmt;
dr_analyze_innermost (&DR_INNERMOST (dr), memref, dr_analyze_innermost (&DR_INNERMOST (dr), memref,
nest != NULL ? loop : NULL); nest != NULL ? loop : NULL, stmt);
dr_analyze_indices (dr, nest, loop); dr_analyze_indices (dr, nest, loop);
dr_analyze_alias (dr); dr_analyze_alias (dr);
...@@ -1318,7 +1307,7 @@ data_ref_compare_tree (tree t1, tree t2) ...@@ -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 /* Return TRUE it's possible to resolve data dependence DDR by runtime alias
check. */ check. */
bool opt_result
runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p) runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
{ {
if (dump_enabled_p ()) if (dump_enabled_p ())
...@@ -1327,25 +1316,18 @@ runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_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))); DR_REF (DDR_A (ddr)), DR_REF (DDR_B (ddr)));
if (!speed_p) if (!speed_p)
{ return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
if (dump_enabled_p ()) "runtime alias check not supported when"
dump_printf (MSG_MISSED_OPTIMIZATION, " optimizing for size.\n");
"runtime alias check not supported when optimizing "
"for size.\n");
return false;
}
/* FORNOW: We don't support versioning with outer-loop in either /* FORNOW: We don't support versioning with outer-loop in either
vectorization or loop distribution. */ vectorization or loop distribution. */
if (loop != NULL && loop->inner != NULL) if (loop != NULL && loop->inner != NULL)
{ return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
if (dump_enabled_p ()) "runtime alias check not supported for"
dump_printf (MSG_MISSED_OPTIMIZATION, " outer loop.\n");
"runtime alias check not supported for outer loop.\n");
return false;
}
return true; return opt_result::success ();
} }
/* Operator == between two dr_with_seg_len objects. /* Operator == between two dr_with_seg_len objects.
...@@ -5043,18 +5025,18 @@ loop_nest_has_data_refs (loop_p loop) ...@@ -5043,18 +5025,18 @@ loop_nest_has_data_refs (loop_p loop)
reference, returns false, otherwise returns true. NEST is the outermost reference, returns false, otherwise returns true. NEST is the outermost
loop of the loop nest in which the references should be analyzed. */ 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, find_data_references_in_stmt (struct loop *nest, gimple *stmt,
vec<data_reference_p> *datarefs) vec<data_reference_p> *datarefs)
{ {
unsigned i; unsigned i;
auto_vec<data_ref_loc, 2> references; auto_vec<data_ref_loc, 2> references;
data_ref_loc *ref; data_ref_loc *ref;
bool ret = true;
data_reference_p dr; data_reference_p dr;
if (get_references_in_stmt (stmt, &references)) 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) FOR_EACH_VEC_ELT (references, i, ref)
{ {
...@@ -5065,7 +5047,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt, ...@@ -5065,7 +5047,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
datarefs->safe_push (dr); datarefs->safe_push (dr);
} }
return ret; return opt_result::success ();
} }
/* Stores the data references in STMT to DATAREFS. If there is an /* Stores the data references in STMT to DATAREFS. If there is an
......
...@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "graphds.h" #include "graphds.h"
#include "tree-chrec.h" #include "tree-chrec.h"
#include "opt-problem.h"
/* /*
innermost_loop_behavior describes the evolution of the address of the memory innermost_loop_behavior describes the evolution of the address of the memory
...@@ -421,7 +422,8 @@ typedef struct data_dependence_relation *ddr_p; ...@@ -421,7 +422,8 @@ typedef struct data_dependence_relation *ddr_p;
#define DDR_COULD_BE_INDEPENDENT_P(DDR) (DDR)->could_be_independent_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, extern bool compute_data_dependences_for_loop (struct loop *, bool,
vec<loop_p> *, vec<loop_p> *,
vec<data_reference_p> *, vec<data_reference_p> *,
...@@ -443,7 +445,7 @@ extern void free_dependence_relation (struct data_dependence_relation *); ...@@ -443,7 +445,7 @@ extern void free_dependence_relation (struct data_dependence_relation *);
extern void free_dependence_relations (vec<ddr_p> ); extern void free_dependence_relations (vec<ddr_p> );
extern void free_data_ref (data_reference_p); extern void free_data_ref (data_reference_p);
extern void free_data_refs (vec<data_reference_p> ); extern void free_data_refs (vec<data_reference_p> );
extern bool find_data_references_in_stmt (struct loop *, gimple *, extern opt_result find_data_references_in_stmt (struct loop *, gimple *,
vec<data_reference_p> *); vec<data_reference_p> *);
extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *, extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
vec<data_reference_p> *); vec<data_reference_p> *);
...@@ -479,7 +481,7 @@ extern bool dr_may_alias_p (const struct data_reference *, ...@@ -479,7 +481,7 @@ extern bool dr_may_alias_p (const struct data_reference *,
extern bool dr_equal_offsets_p (struct data_reference *, extern bool dr_equal_offsets_p (struct data_reference *,
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 int data_ref_compare_tree (tree, tree);
extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *, extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
poly_uint64); poly_uint64);
......
...@@ -1280,7 +1280,8 @@ find_looparound_phi (struct loop *loop, dref ref, dref root) ...@@ -1280,7 +1280,8 @@ find_looparound_phi (struct loop *loop, dref ref, dref root)
memset (&init_dr, 0, sizeof (struct data_reference)); memset (&init_dr, 0, sizeof (struct data_reference));
DR_REF (&init_dr) = init_ref; DR_REF (&init_dr) = init_ref;
DR_STMT (&init_dr) = phi; 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; return NULL;
if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref)) if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
......
...@@ -2071,7 +2071,7 @@ vect_analyze_slp_instance (vec_info *vinfo, ...@@ -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 /* Check if there are stmts in the loop can be vectorized using SLP. Build SLP
trees of packed scalar stmts if SLP is possible. */ trees of packed scalar stmts if SLP is possible. */
bool opt_result
vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
{ {
unsigned int i; unsigned int i;
...@@ -2111,7 +2111,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) ...@@ -2111,7 +2111,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
max_tree_size); max_tree_size);
} }
return true; return opt_result::success ();
} }
......
...@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h" #include "stringpool.h"
#include "attribs.h" #include "attribs.h"
#include "gimple-pretty-print.h" #include "gimple-pretty-print.h"
#include "opt-problem.h"
/* Loop or bb location, with hotness information. */ /* Loop or bb location, with hotness information. */
...@@ -860,13 +861,25 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab, ...@@ -860,13 +861,25 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
vect_location = find_loop_location (loop); vect_location = find_loop_location (loop);
if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION
&& dump_enabled_p ()) && 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_FILE (vect_location.get_location_t ()),
LOCATION_LINE (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; 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)) if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
{ {
/* Free existing information if loop is analyzed with some /* Free existing information if loop is analyzed with some
......
...@@ -612,6 +612,12 @@ typedef struct _loop_vec_info : public vec_info { ...@@ -612,6 +612,12 @@ typedef struct _loop_vec_info : public vec_info {
#define LOOP_VINFO_ORIG_MAX_VECT_FACTOR(L) \ #define LOOP_VINFO_ORIG_MAX_VECT_FACTOR(L) \
(LOOP_VINFO_MAX_VECT_FACTOR (LOOP_VINFO_ORIG_LOOP_INFO (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 static inline loop_vec_info
loop_vec_info_for_loop (struct loop *loop) loop_vec_info_for_loop (struct loop *loop)
{ {
...@@ -1473,7 +1479,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int, ...@@ -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_replace_stmt (stmt_vec_info, gimple *);
extern stmt_vec_info vect_finish_stmt_generation (stmt_vec_info, gimple *, extern stmt_vec_info vect_finish_stmt_generation (stmt_vec_info, gimple *,
gimple_stmt_iterator *); 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_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_1 (stmt_vec_info, enum vect_def_type);
extern tree vect_get_vec_def_for_operand (tree, stmt_vec_info, tree = NULL); 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); ...@@ -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 *, extern bool vect_transform_stmt (stmt_vec_info, gimple_stmt_iterator *,
slp_tree, slp_instance); slp_tree, slp_instance);
extern void vect_remove_stores (stmt_vec_info); extern void vect_remove_stores (stmt_vec_info);
extern bool vect_analyze_stmt (stmt_vec_info, bool *, slp_tree, slp_instance, extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree,
stmt_vector_for_cost *); slp_instance, stmt_vector_for_cost *);
extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *, extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *,
stmt_vec_info *, tree, int, slp_tree, stmt_vec_info *, tree, int, slp_tree,
stmt_vector_for_cost *); stmt_vector_for_cost *);
...@@ -1504,8 +1510,9 @@ extern tree vect_gen_perm_mask_checked (tree, const vec_perm_indices &); ...@@ -1504,8 +1510,9 @@ extern tree vect_gen_perm_mask_checked (tree, const vec_perm_indices &);
extern void optimize_mask_stores (struct loop*); extern void optimize_mask_stores (struct loop*);
extern gcall *vect_gen_while (tree, tree, tree); extern gcall *vect_gen_while (tree, tree, tree);
extern tree vect_gen_while_not (gimple_seq *, 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 opt_result vect_get_vector_types_for_stmt (stmt_vec_info, tree *,
extern tree vect_get_mask_type_for_stmt (stmt_vec_info); tree *);
extern opt_tree vect_get_mask_type_for_stmt (stmt_vec_info);
/* In tree-vect-data-refs.c. */ /* In tree-vect-data-refs.c. */
extern bool vect_can_force_dr_alignment_p (const_tree, unsigned int); 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 ...@@ -1513,21 +1520,21 @@ extern enum dr_alignment_support vect_supportable_dr_alignment
(dr_vec_info *, bool); (dr_vec_info *, bool);
extern tree vect_get_smallest_scalar_type (stmt_vec_info, HOST_WIDE_INT *, extern tree vect_get_smallest_scalar_type (stmt_vec_info, HOST_WIDE_INT *,
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_slp_analyze_instance_dependence (slp_instance);
extern bool vect_enhance_data_refs_alignment (loop_vec_info); extern opt_result vect_enhance_data_refs_alignment (loop_vec_info);
extern bool vect_analyze_data_refs_alignment (loop_vec_info); extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
extern bool vect_verify_datarefs_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_slp_analyze_and_verify_instance_alignment (slp_instance);
extern bool vect_analyze_data_ref_accesses (vec_info *); extern opt_result vect_analyze_data_ref_accesses (vec_info *);
extern bool vect_prune_runtime_alias_test_list (loop_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, extern bool vect_gather_scatter_fn_p (bool, bool, tree, tree, unsigned int,
signop, int, internal_fn *, tree *); signop, int, internal_fn *, tree *);
extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info, extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info,
gather_scatter_info *); gather_scatter_info *);
extern bool vect_find_stmt_data_reference (loop_p, gimple *, extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
vec<data_reference_p> *); vec<data_reference_p> *);
extern bool vect_analyze_data_refs (vec_info *, poly_uint64 *); extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *);
extern void vect_record_base_alignments (vec_info *); extern void vect_record_base_alignments (vec_info *);
extern tree vect_create_data_ref_ptr (stmt_vec_info, tree, struct loop *, tree, extern tree vect_create_data_ref_ptr (stmt_vec_info, tree, struct loop *, tree,
tree *, gimple_stmt_iterator *, tree *, gimple_stmt_iterator *,
...@@ -1563,7 +1570,8 @@ extern stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info, ...@@ -1563,7 +1570,8 @@ 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, extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree,
enum tree_code); enum tree_code);
/* Drive for loop analysis stage. */ /* Drive for loop analysis stage. */
extern loop_vec_info vect_analyze_loop (struct loop *, loop_vec_info, extern opt_loop_vec_info vect_analyze_loop (struct loop *,
loop_vec_info,
vec_info_shared *); vec_info_shared *);
extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL); extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL);
extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *, extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *,
...@@ -1577,7 +1585,8 @@ extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *, ...@@ -1577,7 +1585,8 @@ extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *,
/* Drive for loop transformation stage. */ /* Drive for loop transformation stage. */
extern struct loop *vect_transform_loop (loop_vec_info); 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 *, extern bool vectorizable_live_operation (stmt_vec_info, gimple_stmt_iterator *,
slp_tree, int, stmt_vec_info *, slp_tree, int, stmt_vec_info *,
stmt_vector_for_cost *); stmt_vector_for_cost *);
...@@ -1602,7 +1611,7 @@ extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> , ...@@ -1602,7 +1611,7 @@ extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> ,
slp_instance, bool, unsigned *); slp_instance, bool, unsigned *);
extern bool vect_slp_analyze_operations (vec_info *); extern bool vect_slp_analyze_operations (vec_info *);
extern void vect_schedule_slp (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 bool vect_make_slp_decision (loop_vec_info);
extern void vect_detect_hybrid_slp (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> > *); extern void vect_get_slp_defs (vec<tree> , slp_tree, vec<vec<tree> > *);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment