diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 741df44ea51..f7148df1758 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -669,13 +669,15 @@ as_const (T &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. */ + the loop pointers. If the loop ROOT is offered (non-null), the visiting + will start from it, otherwise it would start from loops_for_fn (FN) + instead. The scope is restricted in function FN and the visiting order + is specified by FLAGS. */ class loops_list { public: - loops_list (function *fn, unsigned flags); + loops_list (function *fn, unsigned flags, loop_p root = nullptr); template class Iter { @@ -782,71 +784,94 @@ loops_list::Iter::fill_curr_loop () } /* Set up the loops list to visit according to the specified - function scope FN and iterating order FLAGS. */ + function scope FN and iterating order FLAGS. If ROOT is + not null, the visiting would start from it, otherwise it + will start from tree_root of loops_for_fn (FN). */ -inline loops_list::loops_list (function *fn, unsigned flags) +inline loops_list::loops_list (function *fn, unsigned flags, loop_p root) { class loop *aloop; - unsigned i; int mn; + struct loops *loops = loops_for_fn (fn); + gcc_assert (!root || loops); + this->fn = fn; - if (!loops_for_fn (fn)) + if (!loops) return; + loop_p tree_root = root ? root : loops->tree_root; + this->to_visit.reserve_exact (number_of_loops (fn)); - mn = (flags & LI_INCLUDE_ROOT) ? 0 : 1; + mn = (flags & LI_INCLUDE_ROOT) ? -1 : tree_root->num; - if (flags & LI_ONLY_INNERMOST) - { - for (i = 0; vec_safe_iterate (loops_for_fn (fn)->larray, i, &aloop); i++) - if (aloop != NULL - && aloop->inner == NULL - && aloop->num >= mn) + /* The helper function for LI_FROM_INNERMOST and LI_ONLY_INNERMOST + visiting, ONLY_PUSH_INNERMOST_P indicates whether only push + the innermost loop, it's true for LI_ONLY_INNERMOST visiting + while false for LI_FROM_INNERMOST visiting. */ + auto visit_from_innermost = [&] (bool only_push_innermost_p) + { + /* Push the loops to LI->TO_VISIT in postorder. */ + + /* Early handle tree_root without any inner loops, make later + processing simpler, that is the while loop can only care + about loops which aren't possible to be tree_root. */ + if (!tree_root->inner) + { + if (tree_root->num != mn) + this->to_visit.quick_push (tree_root->num); + return; + } + + for (aloop = tree_root; + aloop->inner != NULL; + aloop = aloop->inner) + continue; + + while (1) + { + gcc_assert (aloop != tree_root); + if (!only_push_innermost_p || aloop->inner == NULL) this->to_visit.quick_push (aloop->num); - } - else if (flags & LI_FROM_INNERMOST) - { - /* Push the loops to LI->TO_VISIT in postorder. */ - for (aloop = loops_for_fn (fn)->tree_root; - aloop->inner != NULL; - aloop = aloop->inner) - continue; - while (1) - { - if (aloop->num >= mn) - this->to_visit.quick_push (aloop->num); + if (aloop->next) + { + for (aloop = aloop->next; + aloop->inner != NULL; + aloop = aloop->inner) + continue; + } + else if (loop_outer (aloop) == tree_root) + break; + else + aloop = loop_outer (aloop); + } + + /* Reconsider tree_root since the previous loop doesn't handle it. */ + if (!only_push_innermost_p && tree_root->num != mn) + this->to_visit.quick_push (tree_root->num); + }; - if (aloop->next) - { - for (aloop = aloop->next; - aloop->inner != NULL; - aloop = aloop->inner) - continue; - } - else if (!loop_outer (aloop)) - break; - else - aloop = loop_outer (aloop); - } - } + if (flags & LI_ONLY_INNERMOST) + visit_from_innermost (true); + else if (flags & LI_FROM_INNERMOST) + visit_from_innermost (false); else { /* Push the loops to LI->TO_VISIT in preorder. */ - aloop = loops_for_fn (fn)->tree_root; + aloop = tree_root; while (1) { - if (aloop->num >= mn) + if (aloop->num != mn) this->to_visit.quick_push (aloop->num); if (aloop->inner != NULL) aloop = aloop->inner; else { - while (aloop != NULL && aloop->next == NULL) + while (aloop != tree_root && aloop->next == NULL) aloop = loop_outer (aloop); - if (aloop == NULL) + if (aloop == tree_root) break; aloop = aloop->next; }