diff mbox series

[v3] Use range-based for loops for traversing loops

Message ID 79a93b1f-6417-234c-a785-fdc598dfb92c@linux.ibm.com
State New
Headers show
Series [v3] Use range-based for loops for traversing loops | expand

Commit Message

Kewen.Lin July 23, 2021, 8:35 a.m. UTC
Hi,

Comparing to v2, this v3 removed the new CTOR with struct loops *loops
as Richi clarified.  I'd like to support it in a separated follow up
patch by extending the existing CTOR with an optional argument loop_p
root.

Bootstrapped and regtested again on powerpc64le-linux-gnu P9,
x86_64-redhat-linux and aarch64-linux-gnu, also
bootstrapped again on ppc64le P9 with bootstrap-O3 config.

Is it ok for trunk?

BR,
Kewen
-----
gcc/ChangeLog:

	* cfgloop.h (as_const): New function.
	(class loop_iterator): Rename to ...
	(class loops_list): ... this.
	(loop_iterator::next): Rename to ...
	(loops_list::Iter::fill_curr_loop): ... this and adjust.
	(loop_iterator::loop_iterator): Rename to ...
	(loops_list::loops_list): ... this and adjust.
	(loops_list::Iter): New class.
	(loops_list::iterator): New type.
	(loops_list::const_iterator): New type.
	(loops_list::begin): New function.
	(loops_list::end): Likewise.
	(loops_list::begin const): Likewise.
	(loops_list::end const): Likewise.
	(FOR_EACH_LOOP): Remove.
	(FOR_EACH_LOOP_FN): Remove.
	* cfgloop.c (flow_loops_dump): Adjust FOR_EACH_LOOP* with range-based
	for loop with loops_list instance.
	(sort_sibling_loops): Likewise.
	(disambiguate_loops_with_multiple_latches): Likewise.
	(verify_loop_structure): Likewise.
	* cfgloopmanip.c (create_preheaders): Likewise.
	(force_single_succ_latches): Likewise.
	* config/aarch64/falkor-tag-collision-avoidance.c
	(execute_tag_collision_avoidance): Likewise.
	* config/mn10300/mn10300.c (mn10300_scan_for_setlb_lcc): Likewise.
	* config/s390/s390.c (s390_adjust_loops): Likewise.
	* doc/loop.texi: Likewise.
	* gimple-loop-interchange.cc (pass_linterchange::execute): Likewise.
	* gimple-loop-jam.c (tree_loop_unroll_and_jam): Likewise.
	* gimple-loop-versioning.cc (loop_versioning::analyze_blocks): Likewise.
	(loop_versioning::make_versioning_decisions): Likewise.
	* gimple-ssa-split-paths.c (split_paths): Likewise.
	* graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl): Likewise.
	* graphite.c (canonicalize_loop_form): Likewise.
	(graphite_transform_loops): Likewise.
	* ipa-fnsummary.c (analyze_function_body): Likewise.
	* ipa-pure-const.c (analyze_function): Likewise.
	* loop-doloop.c (doloop_optimize_loops): Likewise.
	* loop-init.c (loop_optimizer_finalize): Likewise.
	(fix_loop_structure): Likewise.
	* loop-invariant.c (calculate_loop_reg_pressure): Likewise.
	(move_loop_invariants): Likewise.
	* loop-unroll.c (decide_unrolling): Likewise.
	(unroll_loops): Likewise.
	* modulo-sched.c (sms_schedule): Likewise.
	* predict.c (predict_loops): Likewise.
	(pass_profile::execute): Likewise.
	* profile.c (branch_prob): Likewise.
	* sel-sched-ir.c (sel_finish_pipelining): Likewise.
	(sel_find_rgns): Likewise.
	* tree-cfg.c (replace_loop_annotate): Likewise.
	(replace_uses_by): Likewise.
	(move_sese_region_to_fn): Likewise.
	* tree-if-conv.c (pass_if_conversion::execute): Likewise.
	* tree-loop-distribution.c (loop_distribution::execute): Likewise.
	* tree-parloops.c (parallelize_loops): Likewise.
	* tree-predcom.c (tree_predictive_commoning): Likewise.
	* tree-scalar-evolution.c (scev_initialize): Likewise.
	(scev_reset): Likewise.
	* tree-ssa-dce.c (find_obviously_necessary_stmts): Likewise.
	* tree-ssa-live.c (remove_unused_locals): Likewise.
	* tree-ssa-loop-ch.c (ch_base::copy_headers): Likewise.
	* tree-ssa-loop-im.c (analyze_memory_references): Likewise.
	(tree_ssa_lim_initialize): Likewise.
	* tree-ssa-loop-ivcanon.c (canonicalize_induction_variables): Likewise.
	* tree-ssa-loop-ivopts.c (tree_ssa_iv_optimize): Likewise.
	* tree-ssa-loop-manip.c (get_loops_exits): Likewise.
	* tree-ssa-loop-niter.c (estimate_numbers_of_iterations): Likewise.
	(free_numbers_of_iterations_estimates): Likewise.
	* tree-ssa-loop-prefetch.c (tree_ssa_prefetch_arrays): Likewise.
	* tree-ssa-loop-split.c (tree_ssa_split_loops): Likewise.
	* tree-ssa-loop-unswitch.c (tree_ssa_unswitch_loops): Likewise.
	* tree-ssa-loop.c (gate_oacc_kernels): Likewise.
	(pass_scev_cprop::execute): Likewise.
	* tree-ssa-propagate.c (clean_up_loop_closed_phi): Likewise.
	* tree-ssa-sccvn.c (do_rpo_vn): Likewise.
	* tree-ssa-threadupdate.c
	(jump_thread_path_registry::thread_through_all_blocks): Likewise.
	* tree-vectorizer.c (vectorize_loops): Likewise.
	* tree-vrp.c (vrp_asserts::find_assert_locations): Likewise.
---
 gcc/cfgloop.c                                 |  19 +--
 gcc/cfgloop.h                                 | 140 +++++++++++++-----
 gcc/cfgloopmanip.c                            |   7 +-
 .../aarch64/falkor-tag-collision-avoidance.c  |   4 +-
 gcc/config/mn10300/mn10300.c                  |   4 +-
 gcc/config/s390/s390.c                        |   4 +-
 gcc/doc/loop.texi                             |  16 +-
 gcc/gimple-loop-interchange.cc                |   3 +-
 gcc/gimple-loop-jam.c                         |   3 +-
 gcc/gimple-loop-versioning.cc                 |   6 +-
 gcc/gimple-ssa-split-paths.c                  |   3 +-
 gcc/graphite-isl-ast-to-gimple.c              |   5 +-
 gcc/graphite.c                                |   6 +-
 gcc/ipa-fnsummary.c                           |   2 +-
 gcc/ipa-pure-const.c                          |   3 +-
 gcc/loop-doloop.c                             |   8 +-
 gcc/loop-init.c                               |   5 +-
 gcc/loop-invariant.c                          |  14 +-
 gcc/loop-unroll.c                             |   7 +-
 gcc/modulo-sched.c                            |   5 +-
 gcc/predict.c                                 |   5 +-
 gcc/profile.c                                 |   3 +-
 gcc/sel-sched-ir.c                            |  12 +-
 gcc/tree-cfg.c                                |  13 +-
 gcc/tree-if-conv.c                            |   3 +-
 gcc/tree-loop-distribution.c                  |   2 +-
 gcc/tree-parloops.c                           |   3 +-
 gcc/tree-predcom.c                            |   3 +-
 gcc/tree-scalar-evolution.c                   |  16 +-
 gcc/tree-ssa-dce.c                            |   3 +-
 gcc/tree-ssa-live.c                           |   3 +-
 gcc/tree-ssa-loop-ch.c                        |   3 +-
 gcc/tree-ssa-loop-im.c                        |   7 +-
 gcc/tree-ssa-loop-ivcanon.c                   |   3 +-
 gcc/tree-ssa-loop-ivopts.c                    |   3 +-
 gcc/tree-ssa-loop-manip.c                     |   3 +-
 gcc/tree-ssa-loop-niter.c                     |   8 +-
 gcc/tree-ssa-loop-prefetch.c                  |   3 +-
 gcc/tree-ssa-loop-split.c                     |   7 +-
 gcc/tree-ssa-loop-unswitch.c                  |   3 +-
 gcc/tree-ssa-loop.c                           |   6 +-
 gcc/tree-ssa-propagate.c                      |   3 +-
 gcc/tree-ssa-sccvn.c                          |   3 +-
 gcc/tree-ssa-threadupdate.c                   |   3 +-
 gcc/tree-vectorizer.c                         |   4 +-
 gcc/tree-vrp.c                                |   3 +-
 46 files changed, 195 insertions(+), 197 deletions(-)

Comments

Martin Sebor July 23, 2021, 4:10 p.m. UTC | #1
On 7/23/21 2:35 AM, Kewen.Lin wrote:
> Hi,
> 
> Comparing to v2, this v3 removed the new CTOR with struct loops *loops
> as Richi clarified.  I'd like to support it in a separated follow up
> patch by extending the existing CTOR with an optional argument loop_p
> root.

Looks very nice (and quite a bit work)!  Thanks again!

Not to make even more work for you, but it occurred to me that
the declaration of the loop control variable could be simplified
by the use of auto like so:

   for (auto loop: loops_list (cfun, ...))

I spotted what looks to me like a few minor typos in the docs
diff:

diff --git a/gcc/doc/loop.texi b/gcc/doc/loop.texi
index a135656ed01..27697b08728 100644
--- a/gcc/doc/loop.texi
+++ b/gcc/doc/loop.texi
@@ -79,14 +79,14 @@ and its subloops in the numbering.  The index of a 
loop never changes.

  The entries of the @code{larray} field should not be accessed directly.
  The function @code{get_loop} returns the loop description for a loop with
-the given index.  @code{number_of_loops} function returns number of
-loops in the function.  To traverse all loops, use @code{FOR_EACH_LOOP}
-macro.  The @code{flags} argument of the macro is used to determine
-the direction of traversal and the set of loops visited.  Each loop is
-guaranteed to be visited exactly once, regardless of the changes to the
-loop tree, and the loops may be removed during the traversal.  The newly
-created loops are never traversed, if they need to be visited, this
-must be done separately after their creation.
+the given index.  @code{number_of_loops} function returns number of loops
+in the function.  To traverse all loops, use range-based for loop with

Missing article:

    use <ins>a </a>range-based for loop

+class @code{loop_list} instance. The @code{flags} argument of the macro

Is that loop_list or loops_list?

IIUC, it's also not a macro anymore, right?  The flags argument
is passed to the loop_list ctor, no?

Martin

> 
> Bootstrapped and regtested again on powerpc64le-linux-gnu P9,
> x86_64-redhat-linux and aarch64-linux-gnu, also
> bootstrapped again on ppc64le P9 with bootstrap-O3 config.
> 
> Is it ok for trunk?
> 
> BR,
> Kewen
> -----
> gcc/ChangeLog:
> 
> 	* cfgloop.h (as_const): New function.
> 	(class loop_iterator): Rename to ...
> 	(class loops_list): ... this.
> 	(loop_iterator::next): Rename to ...
> 	(loops_list::Iter::fill_curr_loop): ... this and adjust.
> 	(loop_iterator::loop_iterator): Rename to ...
> 	(loops_list::loops_list): ... this and adjust.
> 	(loops_list::Iter): New class.
> 	(loops_list::iterator): New type.
> 	(loops_list::const_iterator): New type.
> 	(loops_list::begin): New function.
> 	(loops_list::end): Likewise.
> 	(loops_list::begin const): Likewise.
> 	(loops_list::end const): Likewise.
> 	(FOR_EACH_LOOP): Remove.
> 	(FOR_EACH_LOOP_FN): Remove.
> 	* cfgloop.c (flow_loops_dump): Adjust FOR_EACH_LOOP* with range-based
> 	for loop with loops_list instance.
> 	(sort_sibling_loops): Likewise.
> 	(disambiguate_loops_with_multiple_latches): Likewise.
> 	(verify_loop_structure): Likewise.
> 	* cfgloopmanip.c (create_preheaders): Likewise.
> 	(force_single_succ_latches): Likewise.
> 	* config/aarch64/falkor-tag-collision-avoidance.c
> 	(execute_tag_collision_avoidance): Likewise.
> 	* config/mn10300/mn10300.c (mn10300_scan_for_setlb_lcc): Likewise.
> 	* config/s390/s390.c (s390_adjust_loops): Likewise.
> 	* doc/loop.texi: Likewise.
> 	* gimple-loop-interchange.cc (pass_linterchange::execute): Likewise.
> 	* gimple-loop-jam.c (tree_loop_unroll_and_jam): Likewise.
> 	* gimple-loop-versioning.cc (loop_versioning::analyze_blocks): Likewise.
> 	(loop_versioning::make_versioning_decisions): Likewise.
> 	* gimple-ssa-split-paths.c (split_paths): Likewise.
> 	* graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl): Likewise.
> 	* graphite.c (canonicalize_loop_form): Likewise.
> 	(graphite_transform_loops): Likewise.
> 	* ipa-fnsummary.c (analyze_function_body): Likewise.
> 	* ipa-pure-const.c (analyze_function): Likewise.
> 	* loop-doloop.c (doloop_optimize_loops): Likewise.
> 	* loop-init.c (loop_optimizer_finalize): Likewise.
> 	(fix_loop_structure): Likewise.
> 	* loop-invariant.c (calculate_loop_reg_pressure): Likewise.
> 	(move_loop_invariants): Likewise.
> 	* loop-unroll.c (decide_unrolling): Likewise.
> 	(unroll_loops): Likewise.
> 	* modulo-sched.c (sms_schedule): Likewise.
> 	* predict.c (predict_loops): Likewise.
> 	(pass_profile::execute): Likewise.
> 	* profile.c (branch_prob): Likewise.
> 	* sel-sched-ir.c (sel_finish_pipelining): Likewise.
> 	(sel_find_rgns): Likewise.
> 	* tree-cfg.c (replace_loop_annotate): Likewise.
> 	(replace_uses_by): Likewise.
> 	(move_sese_region_to_fn): Likewise.
> 	* tree-if-conv.c (pass_if_conversion::execute): Likewise.
> 	* tree-loop-distribution.c (loop_distribution::execute): Likewise.
> 	* tree-parloops.c (parallelize_loops): Likewise.
> 	* tree-predcom.c (tree_predictive_commoning): Likewise.
> 	* tree-scalar-evolution.c (scev_initialize): Likewise.
> 	(scev_reset): Likewise.
> 	* tree-ssa-dce.c (find_obviously_necessary_stmts): Likewise.
> 	* tree-ssa-live.c (remove_unused_locals): Likewise.
> 	* tree-ssa-loop-ch.c (ch_base::copy_headers): Likewise.
> 	* tree-ssa-loop-im.c (analyze_memory_references): Likewise.
> 	(tree_ssa_lim_initialize): Likewise.
> 	* tree-ssa-loop-ivcanon.c (canonicalize_induction_variables): Likewise.
> 	* tree-ssa-loop-ivopts.c (tree_ssa_iv_optimize): Likewise.
> 	* tree-ssa-loop-manip.c (get_loops_exits): Likewise.
> 	* tree-ssa-loop-niter.c (estimate_numbers_of_iterations): Likewise.
> 	(free_numbers_of_iterations_estimates): Likewise.
> 	* tree-ssa-loop-prefetch.c (tree_ssa_prefetch_arrays): Likewise.
> 	* tree-ssa-loop-split.c (tree_ssa_split_loops): Likewise.
> 	* tree-ssa-loop-unswitch.c (tree_ssa_unswitch_loops): Likewise.
> 	* tree-ssa-loop.c (gate_oacc_kernels): Likewise.
> 	(pass_scev_cprop::execute): Likewise.
> 	* tree-ssa-propagate.c (clean_up_loop_closed_phi): Likewise.
> 	* tree-ssa-sccvn.c (do_rpo_vn): Likewise.
> 	* tree-ssa-threadupdate.c
> 	(jump_thread_path_registry::thread_through_all_blocks): Likewise.
> 	* tree-vectorizer.c (vectorize_loops): Likewise.
> 	* tree-vrp.c (vrp_asserts::find_assert_locations): Likewise.
>
diff mbox series

Patch

diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index f094538b9ff..d16591b2e1b 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -162,14 +162,12 @@  flow_loop_dump (const class loop *loop, FILE *file,
 void
 flow_loops_dump (FILE *file, void (*loop_dump_aux) (const class loop *, FILE *, int), int verbose)
 {
-  class loop *loop;
-
   if (!current_loops || ! file)
     return;
 
   fprintf (file, ";; %d loops found\n", number_of_loops (cfun));
 
-  FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
+  for (class loop *loop : loops_list (cfun, LI_INCLUDE_ROOT))
     {
       flow_loop_dump (loop, file, loop_dump_aux, verbose);
     }
@@ -559,8 +557,7 @@  sort_sibling_loops (function *fn)
   free (rc_order);
 
   auto_vec<loop_p, 3> siblings;
-  loop_p loop;
-  FOR_EACH_LOOP_FN (fn, loop, LI_INCLUDE_ROOT)
+  for (class loop *loop : loops_list (fn, LI_INCLUDE_ROOT))
     if (loop->inner && loop->inner->next)
       {
 	loop_p sibling = loop->inner;
@@ -836,9 +833,7 @@  disambiguate_multiple_latches (class loop *loop)
 void
 disambiguate_loops_with_multiple_latches (void)
 {
-  class loop *loop;
-
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       if (!loop->latch)
 	disambiguate_multiple_latches (loop);
@@ -1457,7 +1452,7 @@  verify_loop_structure (void)
   auto_sbitmap visited (last_basic_block_for_fn (cfun));
   bitmap_clear (visited);
   bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       unsigned n;
 
@@ -1503,7 +1498,7 @@  verify_loop_structure (void)
   free (bbs);
 
   /* Check headers and latches.  */
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       i = loop->num;
       if (loop->header == NULL)
@@ -1629,7 +1624,7 @@  verify_loop_structure (void)
     }
 
   /* Check the recorded loop exits.  */
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       if (!loop->exits || loop->exits->e != NULL)
 	{
@@ -1723,7 +1718,7 @@  verify_loop_structure (void)
 	  err = 1;
 	}
 
-      FOR_EACH_LOOP (loop, 0)
+      for (class loop *loop : loops_list (cfun, 0))
 	{
 	  eloops = 0;
 	  for (exit = loop->exits->next; exit->e; exit = exit->next)
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 5e699276c88..741df44ea51 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -658,55 +658,141 @@  enum li_flags
   LI_ONLY_INNERMOST = 4		/* Iterate only over innermost loops.  */
 };
 
-/* The iterator for loops.  */
+/* Provide the functionality of std::as_const to support range-based for
+   to use const iterator.  (We can't use std::as_const itself because it's
+   a C++17 feature.)  */
+template <typename T>
+constexpr const T &
+as_const (T &t)
+{
+  return t;
+}
+
+/* A list for visiting loops, which contains the loop numbers instead of
+   the loop pointers.  The scope is restricted in function FN and the
+   visiting order is specified by FLAGS.  */
 
-class loop_iterator
+class loops_list
 {
 public:
-  loop_iterator (function *fn, loop_p *loop, unsigned flags);
+  loops_list (function *fn, unsigned flags);
+
+  template <typename T> class Iter
+  {
+  public:
+    Iter (const loops_list &l, unsigned idx) : list (l), curr_idx (idx)
+    {
+      fill_curr_loop ();
+    }
+
+    T operator* () const { return curr_loop; }
+
+    Iter &
+    operator++ ()
+    {
+      if (curr_idx < list.to_visit.length ())
+	{
+	  /* Bump the index and fill a new one.  */
+	  curr_idx++;
+	  fill_curr_loop ();
+	}
+      else
+	gcc_assert (!curr_loop);
+
+      return *this;
+    }
+
+    bool
+    operator!= (const Iter &rhs) const
+    {
+      return this->curr_idx != rhs.curr_idx;
+    }
+
+  private:
+    /* Fill the current loop starting from the current index.  */
+    void fill_curr_loop ();
+
+    /* Reference to the loop list to visit.  */
+    const loops_list &list;
+
+    /* The current index in the list to visit.  */
+    unsigned curr_idx;
 
-  inline loop_p next ();
+    /* The loop implied by the current index.  */
+    loop_p curr_loop;
+  };
 
+  using iterator = Iter<loop_p>;
+  using const_iterator = Iter<const loop_p>;
+
+  iterator
+  begin ()
+  {
+    return iterator (*this, 0);
+  }
+
+  iterator
+  end ()
+  {
+    return iterator (*this, to_visit.length ());
+  }
+
+  const_iterator
+  begin () const
+  {
+    return const_iterator (*this, 0);
+  }
+
+  const_iterator
+  end () const
+  {
+    return const_iterator (*this, to_visit.length ());
+  }
+
+private:
   /* The function we are visiting.  */
   function *fn;
 
   /* The list of loops to visit.  */
   auto_vec<int, 16> to_visit;
-
-  /* The index of the actual loop.  */
-  unsigned idx;
 };
 
-inline loop_p
-loop_iterator::next ()
+/* Starting from current index CURR_IDX (inclusive), find one index
+   which stands for one valid loop and fill the found loop as CURR_LOOP,
+   if we can't find one, set CURR_LOOP as null.  */
+
+template <typename T>
+inline void
+loops_list::Iter<T>::fill_curr_loop ()
 {
   int anum;
 
-  while (this->to_visit.iterate (this->idx, &anum))
+  while (this->list.to_visit.iterate (this->curr_idx, &anum))
     {
-      this->idx++;
-      loop_p loop = get_loop (fn, anum);
+      loop_p loop = get_loop (this->list.fn, anum);
       if (loop)
-	return loop;
+	{
+	  curr_loop = loop;
+	  return;
+	}
+      this->curr_idx++;
     }
 
-  return NULL;
+  curr_loop = nullptr;
 }
 
-inline
-loop_iterator::loop_iterator (function *fn, loop_p *loop, unsigned flags)
+/* Set up the loops list to visit according to the specified
+   function scope FN and iterating order FLAGS.  */
+
+inline loops_list::loops_list (function *fn, unsigned flags)
 {
   class loop *aloop;
   unsigned i;
   int mn;
 
-  this->idx = 0;
   this->fn = fn;
   if (!loops_for_fn (fn))
-    {
-      *loop = NULL;
-      return;
-    }
+    return;
 
   this->to_visit.reserve_exact (number_of_loops (fn));
   mn = (flags & LI_INCLUDE_ROOT) ? 0 : 1;
@@ -766,20 +852,8 @@  loop_iterator::loop_iterator (function *fn, loop_p *loop, unsigned flags)
 	    }
 	}
     }
-
-  *loop = this->next ();
 }
 
-#define FOR_EACH_LOOP(LOOP, FLAGS) \
-  for (loop_iterator li(cfun, &(LOOP), FLAGS); \
-       (LOOP); \
-       (LOOP) = li.next ())
-
-#define FOR_EACH_LOOP_FN(FN, LOOP, FLAGS) \
-  for (loop_iterator li(FN, &(LOOP), FLAGS); \
-       (LOOP); \
-       (LOOP) = li.next ())
-
 /* The properties of the target.  */
 struct target_cfgloop {
   /* Number of available registers.  */
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index 2af59fedc92..28087a14e0f 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -1572,12 +1572,10 @@  create_preheader (class loop *loop, int flags)
 void
 create_preheaders (int flags)
 {
-  class loop *loop;
-
   if (!current_loops)
     return;
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     create_preheader (loop, flags);
   loops_state_set (LOOPS_HAVE_PREHEADERS);
 }
@@ -1587,10 +1585,9 @@  create_preheaders (int flags)
 void
 force_single_succ_latches (void)
 {
-  class loop *loop;
   edge e;
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       if (loop->latch != loop->header && single_succ_p (loop->latch))
 	continue;
diff --git a/gcc/config/aarch64/falkor-tag-collision-avoidance.c b/gcc/config/aarch64/falkor-tag-collision-avoidance.c
index de214e4a0f7..d9b1b3fe835 100644
--- a/gcc/config/aarch64/falkor-tag-collision-avoidance.c
+++ b/gcc/config/aarch64/falkor-tag-collision-avoidance.c
@@ -808,8 +808,6 @@  record_loads (tag_map_t &tag_map, struct loop *loop)
 void
 execute_tag_collision_avoidance ()
 {
-  struct loop *loop;
-
   df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
   df_chain_add_problem (DF_UD_CHAIN);
   df_compute_regs_ever_live (true);
@@ -824,7 +822,7 @@  execute_tag_collision_avoidance ()
   calculate_dominance_info (CDI_DOMINATORS);
   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
 
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       tag_map_t tag_map (512);
 
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 6f842a3ad32..d9229ff5cc6 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -3234,8 +3234,6 @@  mn10300_loop_contains_call_insn (loop_p loop)
 static void
 mn10300_scan_for_setlb_lcc (void)
 {
-  loop_p loop;
-
   DUMP ("Looking for loops that can use the SETLB insn", NULL_RTX);
 
   df_analyze ();
@@ -3248,7 +3246,7 @@  mn10300_scan_for_setlb_lcc (void)
      if an inner loop is not suitable for use with the SETLB/Lcc insns, it may
      be the case that its parent loop is suitable.  Thus we should check all
      loops, but work from the innermost outwards.  */
-  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
     {
       const char * reason = NULL;
 
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index b1d3b99784d..a98e1beebf1 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -14479,15 +14479,13 @@  s390_adjust_loop_scan_osc (struct loop* loop)
 static void
 s390_adjust_loops ()
 {
-  struct loop *loop = NULL;
-
   df_analyze ();
   compute_bb_for_insn ();
 
   /* Find the loops.  */
   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
 
-  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
     {
       if (dump_file)
 	{
diff --git a/gcc/doc/loop.texi b/gcc/doc/loop.texi
index a135656ed01..27697b08728 100644
--- a/gcc/doc/loop.texi
+++ b/gcc/doc/loop.texi
@@ -79,14 +79,14 @@  and its subloops in the numbering.  The index of a loop never changes.
 
 The entries of the @code{larray} field should not be accessed directly.
 The function @code{get_loop} returns the loop description for a loop with
-the given index.  @code{number_of_loops} function returns number of
-loops in the function.  To traverse all loops, use @code{FOR_EACH_LOOP}
-macro.  The @code{flags} argument of the macro is used to determine
-the direction of traversal and the set of loops visited.  Each loop is
-guaranteed to be visited exactly once, regardless of the changes to the
-loop tree, and the loops may be removed during the traversal.  The newly
-created loops are never traversed, if they need to be visited, this
-must be done separately after their creation.
+the given index.  @code{number_of_loops} function returns number of loops
+in the function.  To traverse all loops, use range-based for loop with
+class @code{loop_list} instance. The @code{flags} argument of the macro
+is used to determine the direction of traversal and the set of loops
+visited.  Each loop is guaranteed to be visited exactly once, regardless
+of the changes to the loop tree, and the loops may be removed during the
+traversal.  The newly created loops are never traversed, if they need to
+be visited, this must be done separately after their creation.
 
 Each basic block contains the reference to the innermost loop it belongs
 to (@code{loop_father}).  For this reason, it is only possible to have
diff --git a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc
index 7a88faa2c07..a9044182a59 100644
--- a/gcc/gimple-loop-interchange.cc
+++ b/gcc/gimple-loop-interchange.cc
@@ -2089,8 +2089,7 @@  pass_linterchange::execute (function *fun)
     return 0;
 
   bool changed_p = false;
-  class loop *loop;
-  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
     {
       vec<loop_p> loop_nest = vNULL;
       vec<data_reference_p> datarefs = vNULL;
diff --git a/gcc/gimple-loop-jam.c b/gcc/gimple-loop-jam.c
index 4842f0dff80..271139a1d87 100644
--- a/gcc/gimple-loop-jam.c
+++ b/gcc/gimple-loop-jam.c
@@ -486,13 +486,12 @@  adjust_unroll_factor (class loop *inner, struct data_dependence_relation *ddr,
 static unsigned int
 tree_loop_unroll_and_jam (void)
 {
-  class loop *loop;
   bool changed = false;
 
   gcc_assert (scev_initialized_p ());
 
   /* Go through all innermost loops.  */
-  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
     {
       class loop *outer = loop_outer (loop);
 
diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc
index 4b70c5a4aab..3fd086c0c65 100644
--- a/gcc/gimple-loop-versioning.cc
+++ b/gcc/gimple-loop-versioning.cc
@@ -1428,8 +1428,7 @@  loop_versioning::analyze_blocks ()
      versioning at that level could be useful in some cases.  */
   get_loop_info (get_loop (m_fn, 0)).rejected_p = true;
 
-  class loop *loop;
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       loop_info &linfo = get_loop_info (loop);
 
@@ -1650,8 +1649,7 @@  loop_versioning::make_versioning_decisions ()
   AUTO_DUMP_SCOPE ("make_versioning_decisions",
 		   dump_user_location_t::from_function_decl (m_fn->decl));
 
-  class loop *loop;
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       loop_info &linfo = get_loop_info (loop);
       if (decide_whether_loop_is_versionable (loop))
diff --git a/gcc/gimple-ssa-split-paths.c b/gcc/gimple-ssa-split-paths.c
index 2dd953d5ef9..1470de279d6 100644
--- a/gcc/gimple-ssa-split-paths.c
+++ b/gcc/gimple-ssa-split-paths.c
@@ -473,13 +473,12 @@  static bool
 split_paths ()
 {
   bool changed = false;
-  loop_p loop;
 
   loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
   initialize_original_copy_tables ();
   calculate_dominance_info (CDI_DOMINATORS);
 
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       /* Only split paths if we are optimizing this loop for speed.  */
       if (!optimize_loop_for_speed_p (loop))
diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
index c202213f39b..30370859460 100644
--- a/gcc/graphite-isl-ast-to-gimple.c
+++ b/gcc/graphite-isl-ast-to-gimple.c
@@ -1535,9 +1535,8 @@  graphite_regenerate_ast_isl (scop_p scop)
       if_region->false_region->region.entry->flags |= EDGE_FALLTHRU;
       /* remove_edge_and_dominated_blocks marks loops for removal but
 	 doesn't actually remove them (fix that...).  */
-      loop_p loop;
-      FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
-	if (! loop->header)
+      for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
+	if (!loop->header)
 	  delete_loop (loop);
     }
 
diff --git a/gcc/graphite.c b/gcc/graphite.c
index 6c4fb42282b..a26d5a3a818 100644
--- a/gcc/graphite.c
+++ b/gcc/graphite.c
@@ -377,8 +377,7 @@  canonicalize_loop_closed_ssa (loop_p loop, edge e)
 static void
 canonicalize_loop_form (void)
 {
-  loop_p loop;
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       edge e = single_exit (loop);
       if (!e || (e->flags & (EDGE_COMPLEX|EDGE_FAKE)))
@@ -494,10 +493,9 @@  graphite_transform_loops (void)
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      loop_p loop;
       int num_no_dependency = 0;
 
-      FOR_EACH_LOOP (loop, 0)
+      for (class loop *loop : loops_list (cfun, 0))
 	if (loop->can_be_parallel)
 	  num_no_dependency++;
 
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 95d28757f95..883773abe12 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -2923,7 +2923,7 @@  analyze_function_body (struct cgraph_node *node, bool early)
       if (dump_file && (dump_flags & TDF_DETAILS))
 	flow_loops_dump (dump_file, NULL, 0);
       scev_initialize ();
-      FOR_EACH_LOOP (loop, 0)
+      for (class loop *loop : loops_list (cfun, 0))
 	{
 	  predicate loop_iterations = true;
 	  sreal header_freq;
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index f045108af21..f1724e4f46d 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -1087,9 +1087,8 @@  end:
 	    }
 	  else
 	    {
-	      class loop *loop;
 	      scev_initialize ();
-	      FOR_EACH_LOOP (loop, 0)
+	      for (class loop *loop : loops_list (cfun, 0))
 		if (!finite_loop_p (loop))
 		  {
 		    if (dump_file)
diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c
index dda7b9e268f..12288bd64d8 100644
--- a/gcc/loop-doloop.c
+++ b/gcc/loop-doloop.c
@@ -789,18 +789,14 @@  doloop_optimize (class loop *loop)
 void
 doloop_optimize_loops (void)
 {
-  class loop *loop;
-
   if (optimize == 1)
     {
       df_live_add_problem ();
       df_live_set_all_dirty ();
     }
 
-  FOR_EACH_LOOP (loop, 0)
-    {
-      doloop_optimize (loop);
-    }
+  for (class loop *loop : loops_list (cfun, 0))
+    doloop_optimize (loop);
 
   if (optimize == 1)
     df_remove_problem (df_live);
diff --git a/gcc/loop-init.c b/gcc/loop-init.c
index 1fde0ede441..1f75f509f53 100644
--- a/gcc/loop-init.c
+++ b/gcc/loop-init.c
@@ -137,7 +137,6 @@  loop_optimizer_init (unsigned flags)
 void
 loop_optimizer_finalize (struct function *fn, bool clean_loop_closed_phi)
 {
-  class loop *loop;
   basic_block bb;
 
   timevar_push (TV_LOOP_FINI);
@@ -167,7 +166,7 @@  loop_optimizer_finalize (struct function *fn, bool clean_loop_closed_phi)
       goto loop_fini_done;
     }
 
-  FOR_EACH_LOOP_FN (fn, loop, 0)
+  for (class loop *loop : loops_list (fn, 0))
     free_simple_loop_desc (loop);
 
   /* Clean up.  */
@@ -229,7 +228,7 @@  fix_loop_structure (bitmap changed_bbs)
      loops, so that when we remove the loops, we know that the loops inside
      are preserved, and do not waste time relinking loops that will be
      removed later.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       /* Detect the case that the loop is no longer present even though
          it wasn't marked for removal.
diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c
index bdc7b59dd5f..059ef8fe7f4 100644
--- a/gcc/loop-invariant.c
+++ b/gcc/loop-invariant.c
@@ -2136,7 +2136,7 @@  calculate_loop_reg_pressure (void)
   rtx link;
   class loop *loop, *parent;
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     if (loop->aux == NULL)
       {
 	loop->aux = xcalloc (1, sizeof (class loop_data));
@@ -2203,7 +2203,7 @@  calculate_loop_reg_pressure (void)
   bitmap_release (&curr_regs_live);
   if (flag_ira_region == IRA_REGION_MIXED
       || flag_ira_region == IRA_REGION_ALL)
-    FOR_EACH_LOOP (loop, 0)
+    for (class loop *loop : loops_list (cfun, 0))
       {
 	EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi)
 	  if (! bitmap_bit_p (&LOOP_DATA (loop)->regs_ref, j))
@@ -2217,7 +2217,7 @@  calculate_loop_reg_pressure (void)
       }
   if (dump_file == NULL)
     return;
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       parent = loop_outer (loop);
       fprintf (dump_file, "\n  Loop %d (parent %d, header bb%d, depth %d)\n",
@@ -2251,8 +2251,6 @@  calculate_loop_reg_pressure (void)
 void
 move_loop_invariants (void)
 {
-  class loop *loop;
-
   if (optimize == 1)
     df_live_add_problem ();
   /* ??? This is a hack.  We should only need to call df_live_set_all_dirty
@@ -2271,7 +2269,7 @@  move_loop_invariants (void)
     }
   df_set_flags (DF_EQ_NOTES + DF_DEFER_INSN_RESCAN);
   /* Process the loops, innermost first.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       curr_loop = loop;
       /* move_single_loop_invariants for very large loops is time consuming
@@ -2284,10 +2282,8 @@  move_loop_invariants (void)
 	move_single_loop_invariants (loop);
     }
 
-  FOR_EACH_LOOP (loop, 0)
-    {
+  for (class loop *loop : loops_list (cfun, 0))
       free_loop_data (loop);
-    }
 
   if (flag_ira_loop_pressure)
     /* There is no sense to keep this info because it was most
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 66d93487e29..f11c9c396ae 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -214,10 +214,8 @@  report_unroll (class loop *loop, dump_location_t locus)
 static void
 decide_unrolling (int flags)
 {
-  class loop *loop;
-
   /* Scan the loops, inner ones first.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       loop->lpt_decision.decision = LPT_NONE;
       dump_user_location_t locus = get_loop_location (loop);
@@ -278,14 +276,13 @@  decide_unrolling (int flags)
 void
 unroll_loops (int flags)
 {
-  class loop *loop;
   bool changed = false;
 
   /* Now decide rest of unrolling.  */
   decide_unrolling (flags);
 
   /* Scan the loops, inner ones first.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       /* And perform the appropriate transformations.  */
       switch (loop->lpt_decision.decision)
diff --git a/gcc/modulo-sched.c b/gcc/modulo-sched.c
index e72e46db387..fc761cf60c5 100644
--- a/gcc/modulo-sched.c
+++ b/gcc/modulo-sched.c
@@ -1353,7 +1353,6 @@  sms_schedule (void)
   int maxii, max_asap;
   partial_schedule_ptr ps;
   basic_block bb = NULL;
-  class loop *loop;
   basic_block condition_bb = NULL;
   edge latch_edge;
   HOST_WIDE_INT trip_count, max_trip_count;
@@ -1397,7 +1396,7 @@  sms_schedule (void)
 
   /* Build DDGs for all the relevant loops and hold them in G_ARR
      indexed by the loop index.  */
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       rtx_insn *head, *tail;
       rtx count_reg;
@@ -1543,7 +1542,7 @@  sms_schedule (void)
   }
 
   /* We don't want to perform SMS on new loops - created by versioning.  */
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       rtx_insn *head, *tail;
       rtx count_reg;
diff --git a/gcc/predict.c b/gcc/predict.c
index d751e6cecce..5876b6e44a8 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -1949,7 +1949,7 @@  predict_loops (void)
 
   /* Try to predict out blocks in a loop that are not part of a
      natural loop.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       basic_block bb, *bbs;
       unsigned j, n_exits = 0;
@@ -4111,8 +4111,7 @@  pass_profile::execute (function *fun)
     profile_status_for_fn (fun) = PROFILE_GUESSED;
  if (dump_file && (dump_flags & TDF_DETAILS))
    {
-     class loop *loop;
-     FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+     for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
        if (loop->header->count.initialized_p ())
          fprintf (dump_file, "Loop got predicted %d to iterate %i times.\n",
        	   loop->num,
diff --git a/gcc/profile.c b/gcc/profile.c
index 1fa4196fa16..6357fb37cfd 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -1466,13 +1466,12 @@  branch_prob (bool thunk)
   if (flag_branch_probabilities
       && (profile_status_for_fn (cfun) == PROFILE_READ))
     {
-      class loop *loop;
       if (dump_file && (dump_flags & TDF_DETAILS))
 	report_predictor_hitrates ();
 
       /* At this moment we have precise loop iteration count estimates.
 	 Record them to loop structure before the profile gets out of date. */
-      FOR_EACH_LOOP (loop, 0)
+      for (class loop *loop : loops_list (cfun, 0))
 	if (loop->header->count > 0 && loop->header->count.reliable_p ())
 	  {
 	    gcov_type nit = expected_loop_iterations_unbounded (loop);
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index eef9d6969f4..3dff69f21ce 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -6247,10 +6247,8 @@  make_regions_from_the_rest (void)
 /* Free data structures used in pipelining of loops.  */
 void sel_finish_pipelining (void)
 {
-  class loop *loop;
-
   /* Release aux fields so we don't free them later by mistake.  */
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     loop->aux = NULL;
 
   loop_optimizer_finalize ();
@@ -6271,11 +6269,11 @@  sel_find_rgns (void)
 
   if (current_loops)
     {
-      loop_p loop;
+      unsigned flags = flag_sel_sched_pipelining_outer_loops
+			 ? LI_FROM_INNERMOST
+			 : LI_ONLY_INNERMOST;
 
-      FOR_EACH_LOOP (loop, (flag_sel_sched_pipelining_outer_loops
-			    ? LI_FROM_INNERMOST
-			    : LI_ONLY_INNERMOST))
+      for (class loop *loop : loops_list (cfun, flags))
 	make_regions_from_loop_nest (loop);
     }
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c8b0f7b33e1..0d082851f2f 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -312,12 +312,11 @@  replace_loop_annotate_in_block (basic_block bb, class loop *loop)
 static void
 replace_loop_annotate (void)
 {
-  class loop *loop;
   basic_block bb;
   gimple_stmt_iterator gsi;
   gimple *stmt;
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       /* First look into the header.  */
       replace_loop_annotate_in_block (loop->header, loop);
@@ -2027,12 +2026,8 @@  replace_uses_by (tree name, tree val)
   /* Also update the trees stored in loop structures.  */
   if (current_loops)
     {
-      class loop *loop;
-
-      FOR_EACH_LOOP (loop, 0)
-	{
+      for (class loop *loop : loops_list (cfun, 0))
 	  substitute_in_loop_info (loop, name, val);
-	}
     }
 }
 
@@ -7752,9 +7747,9 @@  move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
 
   /* Fix up orig_loop_num.  If the block referenced in it has been moved
      to dest_cfun, update orig_loop_num field, otherwise clear it.  */
-  class loop *dloop;
+  class loop *dloop = NULL;
   signed char *moved_orig_loop_num = NULL;
-  FOR_EACH_LOOP_FN (dest_cfun, dloop, 0)
+  for (class loop *dloop : loops_list (dest_cfun, 0))
     if (dloop->orig_loop_num)
       {
 	if (moved_orig_loop_num == NULL)
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 345488e2a19..1bf68455f72 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -3300,14 +3300,13 @@  pass_if_conversion::gate (function *fun)
 unsigned int
 pass_if_conversion::execute (function *fun)
 {
-  class loop *loop;
   unsigned todo = 0;
 
   if (number_of_loops (fun) <= 1)
     return 0;
 
   auto_vec<gimple *> preds;
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     if (flag_tree_loop_if_convert == 1
 	|| ((flag_tree_loop_vectorize || loop->force_vectorize)
 	    && !loop->dont_vectorize))
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 65aa1df4aba..1f0b6eb3a95 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -3312,7 +3312,7 @@  loop_distribution::execute (function *fun)
 
   /* We can at the moment only distribute non-nested loops, thus restrict
      walking to innermost loops.  */
-  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
     {
       /* Don't distribute multiple exit edges loop, or cold loop when
          not doing pattern detection.  */
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index fe1baef32a7..9d73f241204 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -3989,7 +3989,6 @@  parallelize_loops (bool oacc_kernels_p)
 {
   unsigned n_threads;
   bool changed = false;
-  class loop *loop;
   class loop *skip_loop = NULL;
   class tree_niter_desc niter_desc;
   struct obstack parloop_obstack;
@@ -4020,7 +4019,7 @@  parallelize_loops (bool oacc_kernels_p)
 
   calculate_dominance_info (CDI_DOMINATORS);
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       if (loop == skip_loop)
 	{
diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
index cf85517e1c7..b8ae6b66df9 100644
--- a/gcc/tree-predcom.c
+++ b/gcc/tree-predcom.c
@@ -3419,11 +3419,10 @@  pcom_worker::tree_predictive_commoning_loop (bool allow_unroll_p)
 unsigned
 tree_predictive_commoning (bool allow_unroll_p)
 {
-  class loop *loop;
   unsigned ret = 0, changed = 0;
 
   initialize_original_copy_tables ();
-  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
     if (optimize_loop_for_speed_p (loop))
       {
 	pcom_worker w(loop);
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index b22d49a0ab6..c6a3b7f9bd7 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -2977,16 +2977,12 @@  gather_stats_on_scev_database (void)
 void
 scev_initialize (void)
 {
-  class loop *loop;
-
   gcc_assert (! scev_initialized_p ());
 
   scalar_evolution_info = hash_table<scev_info_hasher>::create_ggc (100);
 
-  FOR_EACH_LOOP (loop, 0)
-    {
-      loop->nb_iterations = NULL_TREE;
-    }
+  for (class loop *loop : loops_list (cfun, 0))
+    loop->nb_iterations = NULL_TREE;
 }
 
 /* Return true if SCEV is initialized.  */
@@ -3015,14 +3011,10 @@  scev_reset_htab (void)
 void
 scev_reset (void)
 {
-  class loop *loop;
-
   scev_reset_htab ();
 
-  FOR_EACH_LOOP (loop, 0)
-    {
-      loop->nb_iterations = NULL_TREE;
-    }
+  for (class loop *loop : loops_list (cfun, 0))
+    loop->nb_iterations = NULL_TREE;
 }
 
 /* Return true if the IV calculation in TYPE can overflow based on the knowledge
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index e2d3b63a30c..226cbc18a2f 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -417,7 +417,6 @@  find_obviously_necessary_stmts (bool aggressive)
   /* Prevent the empty possibly infinite loops from being removed.  */
   if (aggressive)
     {
-      class loop *loop;
       if (mark_irreducible_loops ())
 	FOR_EACH_BB_FN (bb, cfun)
 	  {
@@ -433,7 +432,7 @@  find_obviously_necessary_stmts (bool aggressive)
 		}
 	  }
 
-      FOR_EACH_LOOP (loop, 0)
+      for (class loop *loop : loops_list (cfun, 0))
 	if (!finite_loop_p (loop))
 	  {
 	    if (dump_file)
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index a2aab25e862..16a3f7bb0bb 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -908,8 +908,7 @@  remove_unused_locals (void)
 
   if (cfun->has_simduid_loops)
     {
-      class loop *loop;
-      FOR_EACH_LOOP (loop, 0)
+      for (class loop *loop : loops_list (cfun, 0))
 	if (loop->simduid && !is_used_p (loop->simduid))
 	  loop->simduid = NULL_TREE;
     }
diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c
index dfa5dc87c34..57fa3ee3608 100644
--- a/gcc/tree-ssa-loop-ch.c
+++ b/gcc/tree-ssa-loop-ch.c
@@ -348,7 +348,6 @@  protected:
 unsigned int
 ch_base::copy_headers (function *fun)
 {
-  class loop *loop;
   basic_block header;
   edge exit, entry;
   basic_block *bbs, *copied_bbs;
@@ -365,7 +364,7 @@  ch_base::copy_headers (function *fun)
 
   auto_vec<std::pair<edge, loop_p> > copied;
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       int initial_limit = param_max_loop_header_insns;
       int remaining_limit = initial_limit;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 81b4ec21d6e..a8cc9bc8151 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -1662,7 +1662,7 @@  analyze_memory_references (bool store_motion)
 {
   gimple_stmt_iterator bsi;
   basic_block bb, *bbs;
-  class loop *loop, *outer;
+  class loop *outer;
   unsigned i, n;
 
   /* Collect all basic-blocks in loops and sort them after their
@@ -1706,7 +1706,7 @@  analyze_memory_references (bool store_motion)
 
   /* Propagate the information about accessed memory references up
      the loop hierarchy.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       /* Finalize the overall touched references (including subloops).  */
       bitmap_ior_into (&memory_accesses.all_refs_stored_in_loop[loop->num],
@@ -3133,7 +3133,6 @@  fill_always_executed_in (void)
 static void
 tree_ssa_lim_initialize (bool store_motion)
 {
-  class loop *loop;
   unsigned i;
 
   bitmap_obstack_initialize (&lim_bitmap_obstack);
@@ -3177,7 +3176,7 @@  tree_ssa_lim_initialize (bool store_motion)
      its postorder index.  */
   i = 0;
   bb_loop_postorder = XNEWVEC (unsigned, number_of_loops (cfun));
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     bb_loop_postorder[loop->num] = i++;
 }
 
diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
index b1971f83544..81e9a22be4c 100644
--- a/gcc/tree-ssa-loop-ivcanon.c
+++ b/gcc/tree-ssa-loop-ivcanon.c
@@ -1285,14 +1285,13 @@  canonicalize_loop_induction_variables (class loop *loop,
 unsigned int
 canonicalize_induction_variables (void)
 {
-  class loop *loop;
   bool changed = false;
   bool irred_invalidated = false;
   bitmap loop_closed_ssa_invalidated = BITMAP_ALLOC (NULL);
 
   estimate_numbers_of_iterations (cfun);
 
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       changed |= canonicalize_loop_induction_variables (loop,
 							true, UL_SINGLE_ITER,
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index 12a8a49a307..43668463b21 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -8066,14 +8066,13 @@  finish:
 void
 tree_ssa_iv_optimize (void)
 {
-  class loop *loop;
   struct ivopts_data data;
   auto_bitmap toremove;
 
   tree_ssa_iv_optimize_init (&data);
 
   /* Optimize the loops starting with the innermost ones.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       if (!dbg_cnt (ivopts_loop))
 	continue;
diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
index 28ae1316fa0..15dab0c1451 100644
--- a/gcc/tree-ssa-loop-manip.c
+++ b/gcc/tree-ssa-loop-manip.c
@@ -362,11 +362,10 @@  add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap *loop_exits)
 static void
 get_loops_exits (bitmap *loop_exits)
 {
-  class loop *loop;
   unsigned j;
   edge e;
 
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
       loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 6fabf10a215..84e5ce064fe 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -4559,13 +4559,11 @@  estimated_stmt_executions (class loop *loop, widest_int *nit)
 void
 estimate_numbers_of_iterations (function *fn)
 {
-  class loop *loop;
-
   /* We don't want to issue signed overflow warnings while getting
      loop iteration estimates.  */
   fold_defer_overflow_warnings ();
 
-  FOR_EACH_LOOP_FN (fn, loop, 0)
+  for (class loop *loop : loops_list (fn, 0))
     estimate_numbers_of_iterations (loop);
 
   fold_undefer_and_ignore_overflow_warnings ();
@@ -5031,9 +5029,7 @@  free_numbers_of_iterations_estimates (class loop *loop)
 void
 free_numbers_of_iterations_estimates (function *fn)
 {
-  class loop *loop;
-
-  FOR_EACH_LOOP_FN (fn, loop, 0)
+  for (class loop *loop : loops_list (fn, 0))
     free_numbers_of_iterations_estimates (loop);
 }
 
diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c
index 98062eb4616..b1af922d403 100644
--- a/gcc/tree-ssa-loop-prefetch.c
+++ b/gcc/tree-ssa-loop-prefetch.c
@@ -1980,7 +1980,6 @@  fail:
 unsigned int
 tree_ssa_prefetch_arrays (void)
 {
-  class loop *loop;
   bool unrolled = false;
   int todo_flags = 0;
 
@@ -2025,7 +2024,7 @@  tree_ssa_prefetch_arrays (void)
       set_builtin_decl (BUILT_IN_PREFETCH, decl, false);
     }
 
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "Processing loop %d:\n", loop->num);
diff --git a/gcc/tree-ssa-loop-split.c b/gcc/tree-ssa-loop-split.c
index 3a09bbc39e5..40629227863 100644
--- a/gcc/tree-ssa-loop-split.c
+++ b/gcc/tree-ssa-loop-split.c
@@ -1598,18 +1598,17 @@  split_loop_on_cond (struct loop *loop)
 static unsigned int
 tree_ssa_split_loops (void)
 {
-  class loop *loop;
   bool changed = false;
 
   gcc_assert (scev_initialized_p ());
 
   calculate_dominance_info (CDI_POST_DOMINATORS);
 
-  FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
+  for (class loop *loop : loops_list (cfun, LI_INCLUDE_ROOT))
     loop->aux = NULL;
 
   /* Go through all loops starting from innermost.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       if (loop->aux)
 	{
@@ -1630,7 +1629,7 @@  tree_ssa_split_loops (void)
 	}
     }
 
-  FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
+  for (class loop *loop : loops_list (cfun, LI_INCLUDE_ROOT))
     loop->aux = NULL;
 
   clear_aux_for_blocks ();
diff --git a/gcc/tree-ssa-loop-unswitch.c b/gcc/tree-ssa-loop-unswitch.c
index 04d4553f13e..c4adb52a67c 100644
--- a/gcc/tree-ssa-loop-unswitch.c
+++ b/gcc/tree-ssa-loop-unswitch.c
@@ -90,11 +90,10 @@  static tree get_vop_from_header (class loop *);
 unsigned int
 tree_ssa_unswitch_loops (void)
 {
-  class loop *loop;
   bool changed = false;
 
   /* Go through all loops starting from innermost.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       if (!loop->inner)
 	/* Unswitch innermost loop.  */
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c
index 957ac0f3baa..2255c228780 100644
--- a/gcc/tree-ssa-loop.c
+++ b/gcc/tree-ssa-loop.c
@@ -157,8 +157,7 @@  gate_oacc_kernels (function *fn)
   if (!lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn->decl)))
     return false;
 
-  class loop *loop;
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     if (loop->in_oacc_kernels_region)
       return true;
 
@@ -455,12 +454,11 @@  public:
 unsigned
 pass_scev_cprop::execute (function *)
 {
-  class loop *loop;
   bool any = false;
 
   /* Perform final value replacement in loops, in case the replacement
      expressions are cheap.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     any |= final_value_replacement_loop (loop);
 
   return any ? TODO_cleanup_cfg | TODO_update_ssa_only_virtuals : 0;
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index d93ec90b002..1ac4d050f99 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -1262,7 +1262,6 @@  clean_up_loop_closed_phi (function *fun)
   tree rhs;
   tree lhs;
   gphi_iterator gsi;
-  struct loop *loop;
 
   /* Avoid possibly quadratic work when scanning for loop exits across
    all loops of a nest.  */
@@ -1274,7 +1273,7 @@  clean_up_loop_closed_phi (function *fun)
   calculate_dominance_info  (CDI_DOMINATORS);
 
   /* Walk over loop in function.  */
-  FOR_EACH_LOOP_FN (fun, loop, 0)
+  for (class loop *loop : loops_list (fun, 0))
     {
       /* Check each exit edege of loop.  */
       auto_vec<edge> exits = get_loop_exit_edges (loop);
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 7900df946f4..1bc22950790 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -7637,9 +7637,8 @@  do_rpo_vn (function *fn, edge entry, bitmap exit_bbs,
      loops and the outermost one optimistically.  */
   if (iterate)
     {
-      loop_p loop;
       unsigned max_depth = param_rpo_vn_max_loop_depth;
-      FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
+      for (class loop *loop : loops_list (cfun, LI_ONLY_INNERMOST))
 	if (loop_depth (loop) > max_depth)
 	  for (unsigned i = 2;
 	       i < loop_depth (loop) - max_depth; ++i)
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index f496dd3eb8c..ad1fd115161 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -2561,7 +2561,6 @@  jump_thread_path_registry::thread_through_all_blocks
 {
   bool retval = false;
   unsigned int i;
-  class loop *loop;
   auto_bitmap threaded_blocks;
   hash_set<edge> visited_starting_edges;
 
@@ -2702,7 +2701,7 @@  jump_thread_path_registry::thread_through_all_blocks
   /* Then perform the threading through loop headers.  We start with the
      innermost loop, so that the changes in cfg we perform won't affect
      further threading.  */
-  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+  for (class loop *loop : loops_list (cfun, LI_FROM_INNERMOST))
     {
       if (!loop->header
 	  || !bitmap_bit_p (threaded_blocks, loop->header->index))
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index f1035a83826..ebf237d054a 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -1194,7 +1194,7 @@  vectorize_loops (void)
   /* If some loop was duplicated, it gets bigger number
      than all previously defined loops.  This fact allows us to run
      only over initial loops skipping newly generated ones.  */
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     if (loop->dont_vectorize)
       {
 	any_ifcvt_loops = true;
@@ -1213,7 +1213,7 @@  vectorize_loops (void)
 		  loop4 (copy of loop2)
 		else
 		  loop5 (copy of loop4)
-	   If FOR_EACH_LOOP gives us loop3 first (which has
+	   If loops' iteration gives us loop3 first (which has
 	   dont_vectorize set), make sure to process loop1 before loop4;
 	   so that we can prevent vectorization of loop4 if loop1
 	   is successfully vectorized.  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 0565c9b5073..abcf33c4f26 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -3337,8 +3337,7 @@  vrp_asserts::find_assert_locations (void)
   /* Pre-seed loop latch liveness from loop header PHI nodes.  Due to
      the order we compute liveness and insert asserts we otherwise
      fail to insert asserts into the loop latch.  */
-  loop_p loop;
-  FOR_EACH_LOOP (loop, 0)
+  for (class loop *loop : loops_list (cfun, 0))
     {
       i = loop->latch->index;
       unsigned int j = single_succ_edge (loop->latch)->dest_idx;