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
This commit is contained in:
parent
7db960c5b6
commit
f4ebbd243f
24 changed files with 1585 additions and 794 deletions
167
gcc/ChangeLog
167
gcc/ChangeLog
|
@ -1,3 +1,170 @@
|
|||
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"
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 */
|
||||
|
|
160
gcc/dumpfile.c
160
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");
|
||||
{
|
||||
|
|
|
@ -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. */
|
||||
|
|
335
gcc/opt-problem.cc
Normal file
335
gcc/opt-problem.cc
Normal file
|
@ -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 */
|
289
gcc/opt-problem.h
Normal file
289
gcc/opt-problem.h
Normal file
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -89,11 +89,51 @@ optinfo::add_item (optinfo_item *item)
|
|||
m_items.safe_push (item);
|
||||
}
|
||||
|
||||
/* Emit the optinfo to all of the "non-immediate" destinations
|
||||
(emission to "immediate" destinations is done by emit_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 ()
|
||||
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
|
||||
dump_context::emit_item). */
|
||||
|
||||
void
|
||||
optinfo::emit () const
|
||||
{
|
||||
/* -fsave-optimization-record. */
|
||||
optimization_records_maybe_record_optinfo (this);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
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
|
||||
|
|
12
gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
Normal file
12
gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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" } } */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 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 true;
|
||||
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 ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
if (dump_enabled_p ())
|
||||
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
|
||||
"not vectorized: Bad inner loop.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!expr_invariant_in_loop_p (loop, inner_niter))
|
||||
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,
|
||||
"not vectorized: inner-loop count not"
|
||||
" invariant.\n");
|
||||
return false;
|
||||
"not vectorized: Bad inner loop.\n");
|
||||
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))
|
||||
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++];
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> > *);
|
||||
|
|
Loading…
Add table
Reference in a new issue