RFR(S): 8231291: C2: loop opts before EA should maximally unroll loops
Roland Westrelin
rwestrel at redhat.com
Fri Dec 20 16:56:37 UTC 2019
Hi Vladimir,
Thanks for reviewing this.
> As I understand, the intention of the change you propose is to perform
> complete loop unrolling earlier so EA can benefit from it.
Yes.
> It looks like LoopOptsMaxUnroll is a shortened version of
> IdealLoopTree::iteration_split/iteration_split_impl().
Yes.
> Have you considered factoring out the common code? Right now, its hard
> to correlate the checks for LoopOptsMaxUnroll with iteration_split() and
> there's a risk they'll diverge eventually.
No I haven't. But it seems it's either we duplicate the code as I did or
we add some flag to iteration_split() and make some of the code their
conditional. Wouldn't that affect clarity and for what's overall a
fairly simple change?
> Do you need the following steps from the original version?
>
> ================================================
> // Look for loop-exit tests with my 50/50 guesses from the Parsing stage.
> // Replace with a 1-in-10 exit guess.
> if (!is_root() && is_loop()) {
> adjust_loop_exit_prob(phase);
> }
>
> // Compute loop trip count from profile data
> compute_profile_trip_cnt(phase);
>
> No use of profiling data since full unrolling is happening anyway?
Right.
> ========================
> if (!cl->is_valid_counted_loop()) return true; // Ignore various
> kinds of broken loops
policy_maximally_unroll() has that check.
> ========================
> // Do nothing special to pre- and post- loops
> if (cl->is_pre_loop() || cl->is_post_loop()) return true;
>
> I assume there are no pre-/post-loops exist at that point, so these
> checks are redundant. Turn them into asserts?
I added a check for is_normal_loop() to be safe.
> ========================
> if (cl->is_normal_loop()) {
> if (policy_unswitching(phase)) {
> phase->do_unswitching(this, old_new);
> return true;
> }
> if (policy_maximally_unroll(phase)) {
> // Here we did some unrolling and peeling. Eventually we will
> // completely unroll this loop and it will no longer be a loop.
> phase->do_maximally_unroll(this, old_new);
> return true;
> }
>
> You don't perform loop unswitching at all. So, the order of operations
> changes. Do you see any problems with that?
I'm not sure what to think about that one. Yes, I suppose it could be
that unswitching helps but if we unswitch we have to perform 2 passes of
loop opts to get to the maximally unrolled loop. Isn't that more
disruptive that we would want?
> ========================
>
>
> src/hotspot/share/opto/compile.cpp
> // Perform escape analysis
> if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
> if (has_loops()) {
> // Cleanup graph (remove dead nodes).
> TracePhase tp("idealLoop", &timers[_t_idealLoop]);
> - PhaseIdealLoop::optimize(igvn, LoopOptsNone);
> + PhaseIdealLoop::optimize(igvn, LoopOptsMaxUnroll);
> if (major_progress()) print_method(PHASE_PHASEIDEAL_BEFORE_EA, 2);
> if (failing()) return;
> }
> ConnectionGraph::do_analysis(this, &igvn);
>
> Does it make sense to do more elaborate checks before performing early
> full loop unrolling? Like whether candidates are used inside loop bodies?
We would maximally unroll the loop anyway, only a bit later so I don't
think we need to make this more involved that it needs to be.
new webrev:
http://cr.openjdk.java.net/~roland/8231291/webrev.02/
Roland.
More information about the hotspot-compiler-dev
mailing list