Loop invariant code motion pitfall in JDK10

Current article illustrates a corner case in regards to loop invariant code motion optimization in JDK10, which at first glance seems to regress in comparison to JDK9. Such optimization tries to move outside the body of a loop statements or expressions which do not depend on the loop itself, without affecting the overall semantics of the program.

I have created a small benchmark which contains a loop of 200,000 iterations that computes, at each iteration, the length of a circle (e.g. 2πR) modulo iteration counter and sums all intermediate results. The R is the radius of the arc (i.e. a constant in our case) and the π is computed based on explicit math computation formula (not using the Math.PI constant).

Apart base scenario, I also added similar benchmark test cases which contain superfluous loop invariant Pi computation formula only to stress the Just in Time Compiler and to check how it can optimize them. Please find the entire source code below.

Since it might be interesting why it behaves so slow in JDK10 in comparison to JDK9 and JDK11, I tried to write simplistic pseudocode version derived from assembly code generated in case of circleLengthModulo_10x() method (the same for circleLengthModulo_5x()).

In essence what it does is to inline the method computePi() in the caller only once, computes the π value using vectorized instructions and unrolling the main Pi loop by a factor of 32 and the post Pi loop by a factor of 2, etc.

As we can easily spot, in JDK10 the more “interesting” fact is that method computePi() is inlined multiple times instead of being removed, since it is superfluous and do not impact the semantics of the program (i.e. its return value is not used in case of first 10 calls). This might explain the performance penalty in such case. For JDK9 and JDK11 computePi() method is inlined exactly once within caller method (i.e. removing useless computePi() methods), which leads to almost the same response time for all included JDK versions, as per provided experiment.

Post navigation

2 thoughts on “Loop invariant code motion pitfall in JDK10”

Jean-Philippe Bempel

6 months ago

Hi for me it’s not loop invariant, but more dead code elemination 🙂
ComputePi() without using the return value is dead code and by inlining the JIT is able to detect that this code has no side effects.
But yes there is a regression in JDK 10 as it is not able to perform this :/