diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 91fafc4e766..54bcc1608ae 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1909,6 +1909,9 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_CAN_USE_DOLOOP_P #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost +#undef TARGET_PREDICT_DOLOOP_P +#define TARGET_PREDICT_DOLOOP_P rs6000_predict_doloop_p + #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV rs6000_atomic_assign_expand_fenv @@ -39413,7 +39416,27 @@ rs6000_mangle_decl_assembler_name (tree decl, tree id) return id; } - +/* Predict whether the given loop in gimple will be transformed in the RTL + doloop_optimize pass. This is for rs6000 target specific. */ + +static bool +rs6000_predict_doloop_p (struct loop *loop) +{ + gcc_assert (loop); + + /* On rs6000, targetm.can_use_doloop_p is actually + can_use_doloop_if_innermost. Just ensure it's innermost. */ + if (loop->inner != NULL) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Predict doloop failure due to" + " no innermost.\n"); + return false; + } + + return true; +} + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-rs6000.h" diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 622e8cf240f..69081ca0700 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -11610,6 +11610,14 @@ function version at run-time for a given set of function versions. body must be generated. @end deftypefn +@deftypefn {Target Hook} bool TARGET_PREDICT_DOLOOP_P (struct loop *@var{loop}) +Return true if we can predict it is possible to use a low-overhead loop +for a particular loop. The parameter @var{loop} is a pointer to the loop. +This target hook is required only when the target supports low-overhead +loops, and will help some earlier middle-end passes to make some decisions. +The default version of this hook returns false. +@end deftypefn + @deftypefn {Target Hook} bool TARGET_CAN_USE_DOLOOP_P (const widest_int @var{&iterations}, const widest_int @var{&iterations_max}, unsigned int @var{loop_depth}, bool @var{entered_at_top}) Return true if it is possible to use low-overhead loops (@code{doloop_end} and @code{doloop_begin}) for a particular loop. @var{iterations} gives the diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 17560fce6b7..b4d57b86e2f 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -7944,6 +7944,8 @@ to by @var{ce_info}. @hook TARGET_GENERATE_VERSION_DISPATCHER_BODY +@hook TARGET_PREDICT_DOLOOP_P + @hook TARGET_CAN_USE_DOLOOP_P @hook TARGET_INVALID_WITHIN_DOLOOP diff --git a/gcc/target.def b/gcc/target.def index 7d52102c815..5063c3c0b94 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4236,6 +4236,15 @@ DEFHOOK rtx, (machine_mode mode, rtx result, rtx val, rtx failval), default_speculation_safe_value) +DEFHOOK +(predict_doloop_p, + "Return true if we can predict it is possible to use a low-overhead loop\n\ +for a particular loop. The parameter @var{loop} is a pointer to the loop.\n\ +This target hook is required only when the target supports low-overhead\n\ +loops, and will help some earlier middle-end passes to make some decisions.\n\ +The default version of this hook returns false.", + bool, (struct loop *loop), + default_predict_doloop_p) DEFHOOK (can_use_doloop_p, diff --git a/gcc/targhooks.c b/gcc/targhooks.c index b27111639f4..a83166d81ba 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -643,6 +643,19 @@ default_has_ifunc_p (void) return HAVE_GNU_INDIRECT_FUNCTION; } +/* True if we can predict this loop is possible to be transformed to a + low-overhead loop, otherwise returns false. + + By default, false is returned, as this hook's applicability should be + verified for each target. Target maintainers should re-define the hook + if the target can take advantage of it. */ + +bool +default_predict_doloop_p (struct loop *loop ATTRIBUTE_UNUSED) +{ + return false; +} + /* NULL if INSN insn is valid within a low-overhead loop, otherwise returns an error message. diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 229aacd7b65..50b03ce3aa0 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -85,6 +85,7 @@ extern bool default_fixed_point_supported_p (void); extern bool default_has_ifunc_p (void); +extern bool default_predict_doloop_p (struct loop *); extern const char * default_invalid_within_doloop (const rtx_insn *); extern tree default_builtin_vectorized_function (unsigned int, tree, tree); diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 890f9b788b4..530ea4ae343 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -3712,6 +3712,63 @@ prepare_decl_rtl (tree *expr_p, int *ws, void *data) return NULL_TREE; } +/* Predict whether the given loop will be transformed in the RTL + doloop_optimize pass. Attempt to duplicate some doloop_optimize checks. + This is only for target independent checks, see targetm.predict_doloop_p + for the target dependent ones. + + Note that according to some initial investigation, some checks like costly + niter check and invalid stmt scanning don't have much gains among general + cases, so keep this as simple as possible first. + + Some RTL specific checks seems unable to be checked in gimple, if any new + checks or easy checks _are_ missing here, please add them. */ + +static bool ATTRIBUTE_UNUSED +generic_predict_doloop_p (struct ivopts_data *data) +{ + struct loop *loop = data->current_loop; + + /* Call target hook for target dependent checks. */ + if (!targetm.predict_doloop_p (loop)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Predict doloop failure due to" + " target specific checks.\n"); + return false; + } + + /* Similar to doloop_optimize, check iteration description to know it's + suitable or not. Keep it as simple as possible, feel free to extend it + if you find any multiple exits cases matter. */ + edge exit = single_dom_exit (loop); + struct tree_niter_desc *niter_desc; + if (!exit || !(niter_desc = niter_for_exit (data, exit))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Predict doloop failure due to" + " unexpected niters.\n"); + return false; + } + + /* Similar to doloop_optimize, check whether iteration count too small + and not profitable. */ + HOST_WIDE_INT est_niter = get_estimated_loop_iterations_int (loop); + if (est_niter == -1) + est_niter = get_likely_max_loop_iterations_int (loop); + if (est_niter >= 0 && est_niter < 3) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "Predict doloop failure due to" + " too few iterations (%u).\n", + (unsigned int) est_niter); + return false; + } + + return true; +} + /* Determines cost of the computation of EXPR. */ static unsigned