JDK-8344085 : C2 SuperWord: improve vectorization for small loop iteration count
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 24
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2024-11-13
  • Updated: 2025-05-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
SuperWord is relatively well suited for high iteration count, where we spend most time in the super-unrolled main-loop. This gives us good throughput.

But for small iteration count, there are some issues:
- We align the loop in pre-loop. This can be up to vector-length (number of elements in vector) many iterations.
- Then we check at the zero-trip guard of the main-loop if we have enough iterations left to enter the super-unrolled main-loop. This would require that we have super-unroll-factor * vector-length many iterations left. If we have fewer, we directly go into the post-loop and never enter vectorized code at all.
- This is why we have filed JDK-8307084: if we don't have enough iterations for the super-unrolled main-loop, we should at least enter the vectorized post-loop. That has lower throughput, but is still good for not just cleanup after the main-loop but also for small iteration counts where we cannot use the main-loop.

One idea was JDK-8308994. That may work for some platforms - though it is maybe not worth the complexity. Still, they gathered some interesting data in the plots / benchmarks, see:
https://github.com/openjdk/jdk/pull/14581
Look at the saw-tooth plots it produces: we see that there are different phases.

We should have such a nice benchmark, so that we can experiment well.

Another issue is the pre-loop: it aligns the vectors for the main-loop. But it seems that on modern CPU's such alignment is not as performance relevant as on older CPU's. So here we really waste some possible iterations we might need to enter vectorized loops.
Comments
[~pminborg] sees performance issues in MemorySegment loops, especially for small iteration counts: JDK-8343773 This is not surprising, just another reason to keep working on this issue. I had another Idea: For small iteration counts, alignment is probably not very important. JDK-8355094 showed that especially for larger iteration counts alignment is very important, since it avoids having split loads or stores, which increases the micro-opt count in the CPU pipeline. But if we only have very few iterations anyway, it may be better to spend one more iteration in vectorized code rather than doing all of those iterations in pre-loop for alignment and post-loop for cleanup. FYI: we can already simulate disabling automatic alignment with: -XX:+UnlockDiagnosticVMOptions -XX:SuperWordAutomaticAlignment=0 I predict that this could improve speed for small iteration counts, but worsen performance for large iteration counts, as split-memops become more relevant.
28-05-2025

[~qamai] I'm not sure we can drop the pre-loop completely. RangeCheck elimination sometimes also uses the pre/post loop. Basically we restrict the main-loop to the "safe" region where we know the RC passes, leaving the before and after to pre/post loop. But at least we could limit the pre-loop to a single iteration - that should be relatively easy.
21-11-2024

I think dropping the pre-loop is reasonable. I think clang also does not introduce a pre-loop: https://godbolt.org/z/Whf38edj9 Another benefit of dropping the pre-loop is that it is then easier to reason about the trip count of the main loop. Currently, we cannot fully unroll this loop after vectorization: for (int i = 0; i < 64; i++) { a[i] = b[i]; } Or eliminate the post-loop in these kinds of loop: for (int i = 0; i < x * 64; i++) { a[i] = b[i]; }
16-11-2024