Add predict_doloop_p target hook

Add one target hook predict_doloop_p, it return true if we can predict it
    is possible to use a low-overhead loop, it can help ivopts to make some
    better decisions.

    PR middle-end/80791
    * target.def (predict_doloop_p): New hook.
    * targhooks.h (default_predict_doloop_p): New declaration.
    * targhooks.c (default_predict_doloop_p): New function.
    * doc/tm.texi.in (TARGET_PREDICT_DOLOOP_P): New hook.
    * doc/tm.texi: Regenerate.
    * config/rs6000/rs6000.c (rs6000_predict_doloop_p): New function.
    (TARGET_PREDICT_DOLOOP_P): New macro.
    * tree-ssa-loop-ivopts.c (generic_predict_doloop_p): New function.

From-SVN: r272405
This commit is contained in:
Kewen Lin 2019-06-18 05:08:02 +00:00
parent 702eb490a8
commit 74b5fcf733
8 changed files with 126 additions and 1 deletions

View File

@ -1,3 +1,15 @@
2019-06-18 Kewen Lin <linkw@gcc.gnu.org>
PR middle-end/80791
* target.def (predict_doloop_p): New hook.
* targhooks.h (default_predict_doloop_p): New declaration.
* targhooks.c (default_predict_doloop_p): New function.
* doc/tm.texi.in (TARGET_PREDICT_DOLOOP_P): New hook.
* doc/tm.texi: Regenerate.
* config/rs6000/rs6000.c (rs6000_predict_doloop_p): New function.
(TARGET_PREDICT_DOLOOP_P): New macro.
* tree-ssa-loop-ivopts.c (generic_predict_doloop_p): New function.
2019-06-17 Jakub Jelinek <jakub@redhat.com>
* omp-low.c (struct omp_context): Add scan_inclusive field.

View File

@ -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
@ -39417,7 +39420,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. */
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 the loop is innermost. */
if (loop->inner != NULL)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Predict doloop failure due to"
" loop nesting.\n");
return false;
}
return true;
}
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-rs6000.h"

View File

@ -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 ivopts 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

View File

@ -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

View File

@ -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 ivopts 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,

View File

@ -643,6 +643,19 @@ default_has_ifunc_p (void)
return HAVE_GNU_INDIRECT_FUNCTION;
}
/* Return true if we predict the loop LOOP will be transformed to a
low-overhead loop, otherwise return 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.

View File

@ -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);

View File

@ -3734,6 +3734,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