[Ada] Fix typo and layout in comments about matching
[gcc.git] / gcc / loop-unroll.c
index 91bf5dddeeda8d8649a4e154ee1d6a1ffa3a25fd..693c77688688f2e2c5daba0af5abd79c5671ce52 100644 (file)
@@ -1,5 +1,5 @@
 /* Loop unrolling.
-   Copyright (C) 2002-2017 Free Software Foundation, Inc.
+   Copyright (C) 2002-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "profile.h"
 #include "cfgrtl.h"
 #include "cfgloop.h"
-#include "params.h"
 #include "dojump.h"
 #include "expr.h"
 #include "dumpfile.h"
@@ -163,19 +162,19 @@ struct opt_info
   basic_block loop_preheader;      /* The loop preheader basic block.  */
 };
 
-static void decide_unroll_stupid (struct loop *, int);
-static void decide_unroll_constant_iterations (struct loop *, int);
-static void decide_unroll_runtime_iterations (struct loop *, int);
-static void unroll_loop_stupid (struct loop *);
+static void decide_unroll_stupid (class loop *, int);
+static void decide_unroll_constant_iterations (class loop *, int);
+static void decide_unroll_runtime_iterations (class loop *, int);
+static void unroll_loop_stupid (class loop *);
 static void decide_unrolling (int);
-static void unroll_loop_constant_iterations (struct loop *);
-static void unroll_loop_runtime_iterations (struct loop *);
-static struct opt_info *analyze_insns_in_loop (struct loop *);
+static void unroll_loop_constant_iterations (class loop *);
+static void unroll_loop_runtime_iterations (class loop *);
+static struct opt_info *analyze_insns_in_loop (class loop *);
 static void opt_info_start_duplication (struct opt_info *);
 static void apply_opt_in_copies (struct opt_info *, unsigned, bool, bool);
 static void free_opt_info (struct opt_info *);
-static struct var_to_expand *analyze_insn_to_expand_var (struct loop*, rtx_insn *);
-static bool referenced_in_one_insn_in_loop_p (struct loop *, rtx, int *);
+static struct var_to_expand *analyze_insn_to_expand_var (class loop*, rtx_insn *);
+static bool referenced_in_one_insn_in_loop_p (class loop *, rtx, int *);
 static struct iv_to_split *analyze_iv_to_split_insn (rtx_insn *);
 static void expand_var_during_unrolling (struct var_to_expand *, rtx_insn *);
 static void insert_var_expansion_initialization (struct var_to_expand *,
@@ -189,7 +188,7 @@ static rtx get_expansion (struct var_to_expand *);
    appropriate given the dump or -fopt-info settings.  */
 
 static void
-report_unroll (struct loop *loop, location_t locus)
+report_unroll (class loop *loop, dump_location_t locus)
 {
   dump_flags_t report_flags = MSG_OPTIMIZED_LOCATIONS | TDF_DETAILS;
 
@@ -199,34 +198,42 @@ report_unroll (struct loop *loop, location_t locus)
   if (!dump_enabled_p ())
     return;
 
-  dump_printf_loc (report_flags, locus,
+  dump_metadata_t metadata (report_flags, locus.get_impl_location ());
+  dump_printf_loc (metadata, locus.get_user_location (),
                    "loop unrolled %d times",
                    loop->lpt_decision.times);
   if (profile_info && loop->header->count.initialized_p ())
-    dump_printf (report_flags,
+    dump_printf (metadata,
                  " (header execution count %d)",
                  (int)loop->header->count.to_gcov_type ());
 
-  dump_printf (report_flags, "\n");
+  dump_printf (metadata, "\n");
 }
 
 /* Decide whether unroll loops and how much.  */
 static void
 decide_unrolling (int flags)
 {
-  struct loop *loop;
+  class loop *loop;
 
   /* Scan the loops, inner ones first.  */
   FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
     {
       loop->lpt_decision.decision = LPT_NONE;
-      location_t locus = get_loop_location (loop);
+      dump_user_location_t locus = get_loop_location (loop);
 
       if (dump_enabled_p ())
        dump_printf_loc (MSG_NOTE, locus,
-                         ";; *** Considering loop %d at BB %d for "
-                         "unrolling ***\n",
-                         loop->num, loop->header->index);
+                        "considering unrolling loop %d at BB %d\n",
+                        loop->num, loop->header->index);
+
+      if (loop->unroll == 1)
+       {
+         if (dump_file)
+           fprintf (dump_file,
+                    ";; Not unrolling loop, user didn't want it unrolled\n");
+         continue;
+       }
 
       /* Do not peel cold areas.  */
       if (optimize_loop_for_size_p (loop))
@@ -256,9 +263,7 @@ decide_unrolling (int flags)
       loop->ninsns = num_loop_insns (loop);
       loop->av_ninsns = average_num_loop_insns (loop);
 
-      /* Try transformations one by one in decreasing order of
-        priority.  */
-
+      /* Try transformations one by one in decreasing order of priority.  */
       decide_unroll_constant_iterations (loop, flags);
       if (loop->lpt_decision.decision == LPT_NONE)
        decide_unroll_runtime_iterations (loop, flags);
@@ -273,7 +278,7 @@ decide_unrolling (int flags)
 void
 unroll_loops (int flags)
 {
-  struct loop *loop;
+  class loop *loop;
   bool changed = false;
 
   /* Now decide rest of unrolling.  */
@@ -316,9 +321,9 @@ unroll_loops (int flags)
 /* Check whether exit of the LOOP is at the end of loop body.  */
 
 static bool
-loop_exit_at_end_p (struct loop *loop)
+loop_exit_at_end_p (class loop *loop)
 {
-  struct niter_desc *desc = get_simple_loop_desc (loop);
+  class niter_desc *desc = get_simple_loop_desc (loop);
   rtx_insn *insn;
 
   /* We should never have conditional in latch block.  */
@@ -341,32 +346,30 @@ loop_exit_at_end_p (struct loop *loop)
    and how much.  */
 
 static void
-decide_unroll_constant_iterations (struct loop *loop, int flags)
+decide_unroll_constant_iterations (class loop *loop, int flags)
 {
   unsigned nunroll, nunroll_by_av, best_copies, best_unroll = 0, n_copies, i;
-  struct niter_desc *desc;
+  class niter_desc *desc;
   widest_int iterations;
 
-  if (!(flags & UAP_UNROLL))
-    {
-      /* We were not asked to, just return back silently.  */
-      return;
-    }
+  /* If we were not asked to unroll this loop, just return back silently.  */
+  if (!(flags & UAP_UNROLL) && !loop->unroll)
+    return;
 
-  if (dump_file)
-    fprintf (dump_file,
-            "\n;; Considering unrolling loop with constant "
-            "number of iterations\n");
+  if (dump_enabled_p ())
+    dump_printf (MSG_NOTE,
+                "considering unrolling loop with constant "
+                "number of iterations\n");
 
   /* nunroll = total number of copies of the original loop body in
-     unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
-  nunroll = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / loop->ninsns;
+     unrolled loop (i.e. if it is 2, we have to duplicate loop body once).  */
+  nunroll = param_max_unrolled_insns / loop->ninsns;
   nunroll_by_av
-    = PARAM_VALUE (PARAM_MAX_AVERAGE_UNROLLED_INSNS) / loop->av_ninsns;
+    = param_max_average_unrolled_insns / loop->av_ninsns;
   if (nunroll > nunroll_by_av)
     nunroll = nunroll_by_av;
-  if (nunroll > (unsigned) PARAM_VALUE (PARAM_MAX_UNROLL_TIMES))
-    nunroll = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
+  if (nunroll > (unsigned) param_max_unroll_times)
+    nunroll = param_max_unroll_times;
 
   if (targetm.loop_unroll_adjust)
     nunroll = targetm.loop_unroll_adjust (nunroll, loop);
@@ -391,6 +394,24 @@ decide_unroll_constant_iterations (struct loop *loop, int flags)
       return;
     }
 
+  /* Check for an explicit unrolling factor.  */
+  if (loop->unroll > 0 && loop->unroll < USHRT_MAX)
+    {
+      /* However we cannot unroll completely at the RTL level a loop with
+        constant number of iterations; it should have been peeled instead.  */
+      if (desc->niter == 0 || (unsigned) loop->unroll > desc->niter - 1)
+       {
+         if (dump_file)
+           fprintf (dump_file, ";; Loop should have been peeled\n");
+       }
+      else
+       {
+         loop->lpt_decision.decision = LPT_UNROLL_CONSTANT;
+         loop->lpt_decision.times = loop->unroll - 1;
+       }
+      return;
+    }
+
   /* Check whether the loop rolls enough to consider.  
      Consult also loop bounds and profile; in the case the loop has more
      than one exit it may well loop less than determined maximal number
@@ -412,7 +433,7 @@ decide_unroll_constant_iterations (struct loop *loop, int flags)
   best_copies = 2 * nunroll + 10;
 
   i = 2 * nunroll + 2;
-  if (i - 1 >= desc->niter)
+  if (i > desc->niter - 2)
     i = desc->niter - 2;
 
   for (; i >= nunroll - 1; i--)
@@ -458,14 +479,14 @@ decide_unroll_constant_iterations (struct loop *loop, int flags)
      }
   */
 static void
-unroll_loop_constant_iterations (struct loop *loop)
+unroll_loop_constant_iterations (class loop *loop)
 {
   unsigned HOST_WIDE_INT niter;
   unsigned exit_mod;
   unsigned i;
   edge e;
   unsigned max_unroll = loop->lpt_decision.times;
-  struct niter_desc *desc = get_simple_loop_desc (loop);
+  class niter_desc *desc = get_simple_loop_desc (loop);
   bool exit_at_end = loop_exit_at_end_p (loop);
   struct opt_info *opt_info = NULL;
   bool ok;
@@ -477,7 +498,7 @@ unroll_loop_constant_iterations (struct loop *loop)
 
   exit_mod = niter % (max_unroll + 1);
 
-  auto_sbitmap wont_exit (max_unroll + 1);
+  auto_sbitmap wont_exit (max_unroll + 2);
   bitmap_ones (wont_exit);
 
   auto_vec<edge> remove_edges;
@@ -630,7 +651,7 @@ unroll_loop_constant_iterations (struct loop *loop)
   if (loop->any_likely_upper_bound)
     loop->nb_iterations_likely_upper_bound
       = wi::udiv_trunc (loop->nb_iterations_likely_upper_bound, max_unroll + 1);
-  desc->niter_expr = GEN_INT (desc->niter);
+  desc->niter_expr = gen_int_mode (desc->niter, desc->mode);
 
   /* Remove the edges.  */
   FOR_EACH_VEC_ELT (remove_edges, i, e)
@@ -645,35 +666,36 @@ unroll_loop_constant_iterations (struct loop *loop)
 /* Decide whether to unroll LOOP iterating runtime computable number of times
    and how much.  */
 static void
-decide_unroll_runtime_iterations (struct loop *loop, int flags)
+decide_unroll_runtime_iterations (class loop *loop, int flags)
 {
   unsigned nunroll, nunroll_by_av, i;
-  struct niter_desc *desc;
+  class niter_desc *desc;
   widest_int iterations;
 
-  if (!(flags & UAP_UNROLL))
-    {
-      /* We were not asked to, just return back silently.  */
-      return;
-    }
+  /* If we were not asked to unroll this loop, just return back silently.  */
+  if (!(flags & UAP_UNROLL) && !loop->unroll)
+    return;
 
-  if (dump_file)
-    fprintf (dump_file,
-            "\n;; Considering unrolling loop with runtime "
-            "computable number of iterations\n");
+  if (dump_enabled_p ())
+    dump_printf (MSG_NOTE,
+                "considering unrolling loop with runtime-"
+                "computable number of iterations\n");
 
   /* nunroll = total number of copies of the original loop body in
      unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
-  nunroll = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / loop->ninsns;
-  nunroll_by_av = PARAM_VALUE (PARAM_MAX_AVERAGE_UNROLLED_INSNS) / loop->av_ninsns;
+  nunroll = param_max_unrolled_insns / loop->ninsns;
+  nunroll_by_av = param_max_average_unrolled_insns / loop->av_ninsns;
   if (nunroll > nunroll_by_av)
     nunroll = nunroll_by_av;
-  if (nunroll > (unsigned) PARAM_VALUE (PARAM_MAX_UNROLL_TIMES))
-    nunroll = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
+  if (nunroll > (unsigned) param_max_unroll_times)
+    nunroll = param_max_unroll_times;
 
   if (targetm.loop_unroll_adjust)
     nunroll = targetm.loop_unroll_adjust (nunroll, loop);
 
+  if (loop->unroll > 0 && loop->unroll < USHRT_MAX)
+    nunroll = loop->unroll;
+
   /* Skip big loops.  */
   if (nunroll <= 1)
     {
@@ -712,8 +734,9 @@ decide_unroll_runtime_iterations (struct loop *loop, int flags)
       return;
     }
 
-  /* Success; now force nunroll to be power of 2, as we are unable to
-     cope with overflows in computation of number of iterations.  */
+  /* Success; now force nunroll to be power of 2, as code-gen
+     requires it, we are unable to cope with overflows in
+     computation of number of iterations.  */
   for (i = 1; 2 * i <= nunroll; i *= 2)
     continue;
 
@@ -824,9 +847,10 @@ compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp,
   return seq;
 }
 
-/* Unroll LOOP for which we are able to count number of iterations in runtime
-   LOOP->LPT_DECISION.TIMES times.  The transformation does this (with some
-   extra care for case n < 0):
+/* Unroll LOOP for which we are able to count number of iterations in
+   runtime LOOP->LPT_DECISION.TIMES times.  The times value must be a
+   power of two.  The transformation does this (with some extra care
+   for case n < 0):
 
    for (i = 0; i < n; i++)
      body;
@@ -856,7 +880,7 @@ compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp,
      }
    */
 static void
-unroll_loop_runtime_iterations (struct loop *loop)
+unroll_loop_runtime_iterations (class loop *loop)
 {
   rtx old_niter, niter, tmp;
   rtx_insn *init_code, *branch_code;
@@ -869,7 +893,7 @@ unroll_loop_runtime_iterations (struct loop *loop)
   edge e;
   bool extra_zero_check, last_may_exit;
   unsigned max_unroll = loop->lpt_decision.times;
-  struct niter_desc *desc = get_simple_loop_desc (loop);
+  class niter_desc *desc = get_simple_loop_desc (loop);
   bool exit_at_end = loop_exit_at_end_p (loop);
   struct opt_info *opt_info = NULL;
   bool ok;
@@ -995,9 +1019,9 @@ unroll_loop_runtime_iterations (struct loop *loop)
       preheader = split_edge (loop_preheader_edge (loop));
       /* Add in count of edge from switch block.  */
       preheader->count += iter_count;
-      branch_code = compare_and_jump_seq (copy_rtx (niter), GEN_INT (j), EQ,
-                                         block_label (preheader), p,
-                                         NULL);
+      branch_code = compare_and_jump_seq (copy_rtx (niter),
+                                         gen_int_mode (j, desc->mode), EQ,
+                                         block_label (preheader), p, NULL);
 
       /* We rely on the fact that the compare and jump cannot be optimized out,
         and hence the cfg we create is correct.  */
@@ -1127,34 +1151,35 @@ unroll_loop_runtime_iterations (struct loop *loop)
 
 /* Decide whether to unroll LOOP stupidly and how much.  */
 static void
-decide_unroll_stupid (struct loop *loop, int flags)
+decide_unroll_stupid (class loop *loop, int flags)
 {
   unsigned nunroll, nunroll_by_av, i;
-  struct niter_desc *desc;
+  class niter_desc *desc;
   widest_int iterations;
 
-  if (!(flags & UAP_UNROLL_ALL))
-    {
-      /* We were not asked to, just return back silently.  */
-      return;
-    }
+  /* If we were not asked to unroll this loop, just return back silently.  */
+  if (!(flags & UAP_UNROLL_ALL) && !loop->unroll)
+    return;
 
-  if (dump_file)
-    fprintf (dump_file, "\n;; Considering unrolling loop stupidly\n");
+  if (dump_enabled_p ())
+    dump_printf (MSG_NOTE, "considering unrolling loop stupidly\n");
 
   /* nunroll = total number of copies of the original loop body in
      unrolled loop (i.e. if it is 2, we have to duplicate loop body once.  */
-  nunroll = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / loop->ninsns;
+  nunroll = param_max_unrolled_insns / loop->ninsns;
   nunroll_by_av
-    = PARAM_VALUE (PARAM_MAX_AVERAGE_UNROLLED_INSNS) / loop->av_ninsns;
+    = param_max_average_unrolled_insns / loop->av_ninsns;
   if (nunroll > nunroll_by_av)
     nunroll = nunroll_by_av;
-  if (nunroll > (unsigned) PARAM_VALUE (PARAM_MAX_UNROLL_TIMES))
-    nunroll = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
+  if (nunroll > (unsigned) param_max_unroll_times)
+    nunroll = param_max_unroll_times;
 
   if (targetm.loop_unroll_adjust)
     nunroll = targetm.loop_unroll_adjust (nunroll, loop);
 
+  if (loop->unroll > 0 && loop->unroll < USHRT_MAX)
+    nunroll = loop->unroll;
+
   /* Skip big loops.  */
   if (nunroll <= 1)
     {
@@ -1170,7 +1195,7 @@ decide_unroll_stupid (struct loop *loop, int flags)
   if (desc->simple_p && !desc->assumptions)
     {
       if (dump_file)
-       fprintf (dump_file, ";; The loop is simple\n");
+       fprintf (dump_file, ";; Loop is simple\n");
       return;
     }
 
@@ -1224,10 +1249,10 @@ decide_unroll_stupid (struct loop *loop, int flags)
      }
    */
 static void
-unroll_loop_stupid (struct loop *loop)
+unroll_loop_stupid (class loop *loop)
 {
   unsigned nunroll = loop->lpt_decision.times;
-  struct niter_desc *desc = get_simple_loop_desc (loop);
+  class niter_desc *desc = get_simple_loop_desc (loop);
   struct opt_info *opt_info = NULL;
   bool ok;
 
@@ -1275,7 +1300,7 @@ unroll_loop_stupid (struct loop *loop)
    variable.  */
 
 static bool
-referenced_in_one_insn_in_loop_p (struct loop *loop, rtx reg,
+referenced_in_one_insn_in_loop_p (class loop *loop, rtx reg,
                                  int *debug_uses)
 {
   basic_block *body, bb;
@@ -1303,7 +1328,7 @@ referenced_in_one_insn_in_loop_p (struct loop *loop, rtx reg,
 /* Reset the DEBUG_USES debug insns in LOOP that reference REG.  */
 
 static void
-reset_debug_uses_in_loop (struct loop *loop, rtx reg, int debug_uses)
+reset_debug_uses_in_loop (class loop *loop, rtx reg, int debug_uses)
 {
   basic_block *body, bb;
   unsigned i;
@@ -1352,7 +1377,7 @@ reset_debug_uses_in_loop (struct loop *loop, rtx reg, int debug_uses)
 */
 
 static struct var_to_expand *
-analyze_insn_to_expand_var (struct loop *loop, rtx_insn *insn)
+analyze_insn_to_expand_var (class loop *loop, rtx_insn *insn)
 {
   rtx set, dest, src;
   struct var_to_expand *ves;
@@ -1381,7 +1406,7 @@ analyze_insn_to_expand_var (struct loop *loop, rtx_insn *insn)
     }
 
   /* Hmm, this is a bit paradoxical.  We know that INSN is a valid insn
-     in MD.  But if there is no optab to generate the insn, we can not
+     in MD.  But if there is no optab to generate the insn, we cannot
      perform the variable expansion.  This can happen if an MD provides
      an insn but not a named pattern to generate it, for example to avoid
      producing code that needs additional mode switches like for x87/mmx.
@@ -1493,7 +1518,7 @@ static struct iv_to_split *
 analyze_iv_to_split_insn (rtx_insn *insn)
 {
   rtx set, dest;
-  struct rtx_iv iv;
+  class rtx_iv iv;
   struct iv_to_split *ivts;
   scalar_int_mode mode;
   bool ok;
@@ -1545,7 +1570,7 @@ analyze_iv_to_split_insn (rtx_insn *insn)
    is undefined for the return value.  */
 
 static struct opt_info *
-analyze_insns_in_loop (struct loop *loop)
+analyze_insns_in_loop (class loop *loop)
 {
   basic_block *body, bb;
   unsigned i;
@@ -1798,7 +1823,7 @@ expand_var_during_unrolling (struct var_to_expand *ve, rtx_insn *insn)
 
   /* Generate a new register only if the expansion limit has not been
      reached.  Else reuse an already existing expansion.  */
-  if (PARAM_VALUE (PARAM_MAX_VARIABLE_EXPANSIONS) > ve->expansion_count)
+  if (param_max_variable_expansions > ve->expansion_count)
     {
       really_new_expansion = true;
       new_reg = gen_reg_rtx (GET_MODE (ve->reg));
@@ -2012,12 +2037,14 @@ apply_opt_in_copies (struct opt_info *opt_info,
       FOR_BB_INSNS_SAFE (bb, insn, next)
         {
          if (!INSN_P (insn)
-             || (DEBUG_INSN_P (insn)
+             || (DEBUG_BIND_INSN_P (insn)
+                 && INSN_VAR_LOCATION_DECL (insn)
                  && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL))
             continue;
 
          while (!INSN_P (orig_insn)
-                || (DEBUG_INSN_P (orig_insn)
+                || (DEBUG_BIND_INSN_P (orig_insn)
+                    && INSN_VAR_LOCATION_DECL (orig_insn)
                     && (TREE_CODE (INSN_VAR_LOCATION_DECL (orig_insn))
                         == LABEL_DECL)))
             orig_insn = NEXT_INSN (orig_insn);