3 ms·
A couple weeks ago I managed to get a nice setup for viewing Java JIT disassembly[1], and did a bunch of ad-hoc tests on OpenJDK 21 (and some on whatever build
by dzaima 3y ago
A couple weeks ago I managed to get a nice setup for viewing Java JIT disassembly[1], and did a bunch of ad-hoc tests on OpenJDK 21 (and some on whatever build of 23 was on openjdk.org). do manage to vectorize a decent amount of vectorizable loops, but semi-often missed some improvements, and some trivial things didn't vectorize at all (most amusingly, a loop summing an int[] to an int didn't get vectorized, while int[] to long is). Scalar code codegen is also quite mediocre.
GCC & clang, in comparison, often produce assembly which I'd consider optimal, or close to it, for vectorizable loops, and are noticably better than OpenJDK for scalar code.
[1]: it's a bit messy to use but: https://github.com/dzaima/grr#java-jit https://github.com/dzaima/grr#java-jit
- saagarjha 3y agoGCC and clang produce far from optimal code when vectorizing. Anyone doing serious work is unlikely to rely on the autovectorizer without consulting the output religiously.
- dzaima 3y agoThere are certainly a lot of things they may do suboptimally (in my experience: when there's register pressure; things that aren't nicely elementwise (bit arrays); preparation & tail handling can get pretty excessive; basically no tuning for making better use of ports) and of course you should always be checking the output (this is true for any optimization effort, vectorized or not), but for most things IME they do just fine (assuming the thing in question is vectorized at all). At the very least it's still miles above OpenJDK.
- saagarjha 3y agoI've only really seen decent results on the simplest of examples, like a bounded loop with a basic operation in it (like, adding all the numbers in an array). As soon as you go beyond that I see much worse code: reloading things inside the loop body that really should have been hoisted out, spilling for no good reason, weird contortions to shove certain things into scalar registers in the middle only to take them out again. And, of course, if your control flow is not trivial the compiler will often not recognize the loop as vectorizable at all.
- dzaima 3y agoUnknown-bound loops are not vectorizable in general (at least not sanely; you'd need masked stores, aligned writes, and a bunch of handling for different cases of bound computation). I haven't seen many cases of missed hoisting (outside of register pressure, where it's not really "missed") or pointless moving to scalar (at least with clang; I've looked at gcc much less), nor control flow be much of an issue either, both compilers can handle conditional loads & stores where available.