Add predict_doloop_p target hook
authorKewen Lin <linkw@gcc.gnu.org>
Tue, 18 Jun 2019 05:08:02 +0000 (05:08 +0000)
committerKewen Lin <linkw@gcc.gnu.org>
Tue, 18 Jun 2019 05:08:02 +0000 (05:08 +0000)
    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

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/target.def
gcc/targhooks.c
gcc/targhooks.h
gcc/tree-ssa-loop-ivopts.c

index c75b08e487b0151b45350d459c3774399262b067..9a46f93d89d2a4b898f10efb19f8ace5e0ba265d 100644 (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.
index 657720c186f4e8ea2c43c6fedd310a82669facc8..07e00a9b593f2b99724ba4b3df59a98f75bcea8d 100644 (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;
 }
 
-\f
+/* 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"
index 622e8cf240fbf4834a7a39317aff844989b8b65f..c2aa4d04777f3c30bd115512002639cea8dfc4e0 100644 (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
index 17560fce6b7a2cb0148e4dbac565eca588d5302e..b4d57b86e2fb834973673bcde84cc80f599e9c50 100644 (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
index 7d52102c8153b4c86f6541da5e04c39251c2d42f..71b69723b7587fe7e23d88ec994185db2ab82851 100644 (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,
index b27111639f4960426ff2fc39a10ddc9237deaf61..0da885ec1526937532b75289f729fb804c355f78 100644 (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.
 
index 229aacd7b6597d75774e82594cfa332f37afcf3c..50b03ce3aa0dc0c8663972596fc08949e061548b 100644 (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);
index 047d4a005dbba9029cf9ee82ec9e6defd8e3917c..bbae83cbc6eaa432212a4c71463a449ee9a30b33 100644 (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