This refactors the main loop analysis part in vect_analyze_loop, re-purposing the existing vect_reanalyze_as_main_loop for this to reduce code duplication. Failure flow is a bit tricky since we want to extract info from the analyzed loop but I wanted to share the destruction part. Thus I add some std::function and lambda to funnel post-analysis for the case we want that (when analyzing from the main iteration but not when re-analyzing an epilogue as main).
I realize this probably doesn't help the unroll case yet, but it looked like an improvement. Bootstrapped and tested on x86_64-unknown-linux-gnu. OK? Thanks, Richard. 2021-10-27 Richard Biener <rguent...@suse.de> * tree-vect-loop.c: Include <functional>. (vect_reanalyze_as_main_loop): Rename to... (vect_analyze_loop_1): ... this and generalize to be able to use it twice ... (vect_analyze_loop): ... here. --- gcc/tree-vect-loop.c | 202 ++++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 961c1623f81..9a62475a69f 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #define INCLUDE_ALGORITHM +#define INCLUDE_FUNCTIONAL #include "config.h" #include "system.h" #include "coretypes.h" @@ -2898,43 +2899,63 @@ vect_joust_loop_vinfos (loop_vec_info new_loop_vinfo, return true; } -/* If LOOP_VINFO is already a main loop, return it unmodified. Otherwise - try to reanalyze it as a main loop. Return the loop_vinfo on success - and null on failure. */ +/* Analyze LOOP with VECTOR_MODE and as epilogue if MAIN_LOOP_VINFO is + not NULL. Process the analyzed loop with PROCESS even if analysis + failed. Sets *N_STMTS and FATAL according to the analysis. + Return the loop_vinfo on success and wrapped null on failure. */ -static loop_vec_info -vect_reanalyze_as_main_loop (loop_vec_info loop_vinfo, unsigned int *n_stmts) +static opt_loop_vec_info +vect_analyze_loop_1 (class loop *loop, vec_info_shared *shared, + machine_mode vector_mode, loop_vec_info main_loop_vinfo, + unsigned int *n_stmts, bool &fatal, + std::function<void(loop_vec_info)> process = nullptr) { - if (!LOOP_VINFO_EPILOGUE_P (loop_vinfo)) - return loop_vinfo; + /* Check the CFG characteristics of the loop (nesting, entry/exit). */ + 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"); + gcc_checking_assert (main_loop_vinfo == NULL); + return loop_vinfo; + } + loop_vinfo->vector_mode = vector_mode; - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "***** Reanalyzing as a main loop with vector mode %s\n", - GET_MODE_NAME (loop_vinfo->vector_mode)); + if (main_loop_vinfo) + LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = main_loop_vinfo; - struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); - vec_info_shared *shared = loop_vinfo->shared; - opt_loop_vec_info main_loop_vinfo = vect_analyze_loop_form (loop, shared); - gcc_assert (main_loop_vinfo); + /* Run the main analysis. */ + fatal = false; + opt_result res = vect_analyze_loop_2 (loop_vinfo, fatal, n_stmts); + loop->aux = NULL; - main_loop_vinfo->vector_mode = loop_vinfo->vector_mode; + /* Process info before we destroy loop_vinfo upon analysis failure. */ + if (process) + process (loop_vinfo); - bool fatal = false; - bool res = vect_analyze_loop_2 (main_loop_vinfo, fatal, n_stmts); - loop->aux = NULL; - if (!res) + if (dump_enabled_p ()) { - if (dump_enabled_p ()) + if (res) dump_printf_loc (MSG_NOTE, vect_location, - "***** Failed to analyze main loop with vector" - " mode %s\n", + "***** Analysis succeeded with vector mode %s\n", GET_MODE_NAME (loop_vinfo->vector_mode)); - delete main_loop_vinfo; - return NULL; + else + dump_printf_loc (MSG_NOTE, vect_location, + "***** Analysis failed with vector mode %s\n", + GET_MODE_NAME (loop_vinfo->vector_mode)); + } + + if (!res) + { + delete loop_vinfo; + if (fatal) + gcc_checking_assert (main_loop_vinfo == NULL); + return opt_loop_vec_info::propagate_failure (res); } - LOOP_VINFO_VECTORIZABLE_P (main_loop_vinfo) = 1; - return main_loop_vinfo; + + LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1; + return loop_vinfo; } /* Function vect_analyze_loop. @@ -2981,20 +3002,6 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) unsigned HOST_WIDE_INT simdlen = loop->simdlen; while (1) { - /* Check the CFG characteristics of the loop (nesting, entry/exit). */ - 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"); - gcc_checking_assert (first_loop_vinfo == NULL); - return loop_vinfo; - } - loop_vinfo->vector_mode = next_vector_mode; - - bool fatal = false; - /* When pick_lowest_cost_p is true, we should in principle iterate over all the loop_vec_infos that LOOP_VINFO could replace and try to vectorize LOOP_VINFO under the same conditions. @@ -3023,41 +3030,35 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) LOOP_VINFO fails when treated as an epilogue loop, succeeds when treated as a standalone loop, and ends up being genuinely cheaper than FIRST_LOOP_VINFO. */ - if (vect_epilogues) - LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = first_loop_vinfo; - res = vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts); - if (mode_i == 0) - autodetected_vector_mode = loop_vinfo->vector_mode; - if (dump_enabled_p ()) + bool fatal; + auto cb = [&] (loop_vec_info loop_vinfo) { - if (res) - dump_printf_loc (MSG_NOTE, vect_location, - "***** Analysis succeeded with vector mode %s\n", - GET_MODE_NAME (loop_vinfo->vector_mode)); - else - dump_printf_loc (MSG_NOTE, vect_location, - "***** Analysis failed with vector mode %s\n", - GET_MODE_NAME (loop_vinfo->vector_mode)); - } - - loop->aux = NULL; - - if (!fatal) - while (mode_i < vector_modes.length () - && vect_chooses_same_modes_p (loop_vinfo, vector_modes[mode_i])) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "***** The result for vector mode %s would" - " be the same\n", - GET_MODE_NAME (vector_modes[mode_i])); - mode_i += 1; - } + if (mode_i ==0) + autodetected_vector_mode = loop_vinfo->vector_mode; + if (!fatal) + while (mode_i < vector_modes.length () + && vect_chooses_same_modes_p (loop_vinfo, + vector_modes[mode_i])) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "***** The result for vector mode %s would" + " be the same\n", + GET_MODE_NAME (vector_modes[mode_i])); + mode_i += 1; + } + }; + opt_loop_vec_info loop_vinfo + = vect_analyze_loop_1 (loop, shared, next_vector_mode, + vect_epilogues + ? (loop_vec_info)first_loop_vinfo : NULL, + &n_stmts, fatal, cb); + if (fatal) + break; - if (res) + if (loop_vinfo) { - LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1; vectorized_loops++; /* Once we hit the desired simdlen for the first time, @@ -3084,33 +3085,44 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) if (vinfos.is_empty () && vect_joust_loop_vinfos (loop_vinfo, first_loop_vinfo)) { - loop_vec_info main_loop_vinfo - = vect_reanalyze_as_main_loop (loop_vinfo, &n_stmts); - if (main_loop_vinfo == loop_vinfo) - { - delete first_loop_vinfo; - first_loop_vinfo = opt_loop_vec_info::success (NULL); - } - else if (main_loop_vinfo - && vect_joust_loop_vinfos (main_loop_vinfo, - first_loop_vinfo)) + if (!vect_epilogues) { delete first_loop_vinfo; first_loop_vinfo = opt_loop_vec_info::success (NULL); - delete loop_vinfo; - loop_vinfo - = opt_loop_vec_info::success (main_loop_vinfo); } else { if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, - "***** No longer preferring vector" - " mode %s after reanalyzing the loop" - " as a main loop\n", + "***** Reanalyzing as a main loop " + "with vector mode %s\n", GET_MODE_NAME - (main_loop_vinfo->vector_mode)); - delete main_loop_vinfo; + (loop_vinfo->vector_mode)); + opt_loop_vec_info main_loop_vinfo + = vect_analyze_loop_1 (loop, shared, + loop_vinfo->vector_mode, + NULL, &n_stmts, fatal); + if (main_loop_vinfo + && vect_joust_loop_vinfos (main_loop_vinfo, + first_loop_vinfo)) + { + delete first_loop_vinfo; + first_loop_vinfo = opt_loop_vec_info::success (NULL); + delete loop_vinfo; + loop_vinfo + = opt_loop_vec_info::success (main_loop_vinfo); + } + else + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "***** No longer preferring vector" + " mode %s after reanalyzing the " + " loop as a main loop\n", + GET_MODE_NAME + (loop_vinfo->vector_mode)); + delete main_loop_vinfo; + } } } } @@ -3159,16 +3171,6 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) if (!simdlen && !vect_epilogues && !pick_lowest_cost_p) break; } - else - { - delete loop_vinfo; - loop_vinfo = opt_loop_vec_info::success (NULL); - if (fatal) - { - gcc_checking_assert (first_loop_vinfo == NULL); - break; - } - } /* Handle the case that the original loop can use partial vectorization, but want to only adopt it for the epilogue. -- 2.31.1