RFR(M): 8223051: support loops with long (64b) trip counts

Roland Westrelin rwestrel at redhat.com
Thu Apr 30 07:45:18 UTC 2020


https://bugs.openjdk.java.net/browse/JDK-8223051
http://cr.openjdk.java.net/~roland/8223051/webrev.00/

This transforms a long counted loop into a strip mined loop nest. That
is roughly:

for (long l = long_start; l < long_stop; l += long_stride) {
}

into

for (long l = long_start; l < long_stop; ) {
  int int_stride = (int)long_stride;
  int int_stop = MIN(long_stop - l, max_jint - int_stride);
  l += int_stop;
  for (int i = 0; i < int_stop; i += int_stride) {
  }
}

This is implemented as a separate transformation from loop strip mining
of JDK-8186027. I used the logic from JDK-8186027 as inspiration but
it's really quite different.

If JDK-8186027's loop strip mining is enabled the loop nest above can be
further transformed into:

for (long l = long_start; l < long_stop; ) {
  for (int i = 0; i < int_stop; i += int_stride) {
    for (int j = i; j < LoopStripMiningIter; j+= int_stride) {
    }
  }
}

I refactored the code of PhaseIdealLoop::is_counted_loop() so it was
straightforward to add a PhaseIdealLoop::is_long_counted_loop() that
shares some logic with PhaseIdealLoop::is_counted_loop().

is_long_counted_loop() starts by looking at the shape of the loop and if
its shape is that of a counted loop with a long induction variable, then
an outer loop is added with a long induction variable. An int induction
variable is constructed for the inner loop. At this point the loop nest
is only partially constructed.

is_long_counted_loop() then attempts the conversion of the inner loop
into an int counted loop with a call to is_counted_loop(). If that fails
for some rare corner case, is_long_counted_loop() backs off and
transforms the loop nest back so it's a single long loop again.

If the inner loop is successfully converted into a counted loop,
is_long_counted_loop() finishes building the loop nest. This is
different from JDK-8186027's loop strip mining which builds the loop
nest in 2 phases: first a skeleton outer loop and after loop opts, the
fully built loop nest.

I also added stressing code that turns:

for (int i = int_start; i < int_stop; i += int_stride) {
}

into:

for (long l = (long)int_start; l < (long)int_stop; l += (long)int_stride) {
}

that can then be converted into the loop nest above. The reason for this
is that I was concerned long loops were too uncommon in the wild for
this change to be properly tested.

I had to change the asserts in loopopts.cpp, because all nodes that are
added when the loop nest is constructed have the same dom depth.

This change doesn't handle RCE. I'll work on that next.

Roland.



More information about the hotspot-compiler-dev mailing list