Live data from Hacker News

Why is 2 * (i * i) faster than 2 * i * i in Java?

stackoverflow.com

21–30 of 109 posts

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#21

I thought at first this was because integer squaring is potentially faster than general integer multiplication and the compiler wasn't seeing the square operation in the second case, but that's not the explanation here.

There isn’t an integer square opcode on any major processor architecture though, right?

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#22
post #9

That just might be the most dedicated answer I've ever seen on Stack Overflow.

It is a good answer, but my favorite by far is an answer about branch prediction to explain why processing a sorted array is faster than unsorted: https://stackoverflow.com/q/11227809/938695

Would be awesome if that answer was updated to explain Spectre (it’s 85% of the way there).

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#23
post #5

You should translate your program to C++ and build with clang ; it turns the loop into a single constant load. https://godbolt.org/z/slznbU

Did you read TFA? The author did that (though using GCC), and the reason the optimizer does what you see is undefined behavior due to signed integer overflow.

> does what you see is undefined behavior

Just to be clear, undefined behavior means the standard allows implementations to do what they they feel is the right thing to do under that scenario, and the outcome will still comply with the standard.

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#24

So it's an issue of the optimizer; as is often the case, it unrolls too aggressively and shoots itself in the foot, all the while missing out on various other opportunities. In my experience, loop unrolling should basically never be done except in extremely degenerate cases; I remember not long ago someone I know who also optimises Asm remarking "it should've died along with the RISC fad". The original goal was to re…

Fully agree.

In most cases on modern systems, small loops should remain compact as possible, to stay in the uop cache. The "for" loop overhead (the inc, cmp, and jmp instructions) effectively execute in parallel. Modern systems are highly out-of-order and the for-loop overhead is virtually nil.

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#25
post #5

You should translate your program to C++ and build with clang ; it turns the loop into a single constant load. https://godbolt.org/z/slznbU

It's usually a good idea to turn loop bound into a variable when benchmarking a compiler, lest it optimizes the whole thing away like in this case.

So if the compiler is too good you want to trick it to produce less optimal code so you can benchmark it fairly? Isn't it part of the benchmark to allow the compiler reduce the whole expression to a compile time constant?

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#26
post #5

You should translate your program to C++ and build with clang ; it turns the loop into a single constant load. https://godbolt.org/z/slznbU

Did you read TFA? The author did that (though using GCC), and the reason the optimizer does what you see is undefined behavior due to signed integer overflow.

Did you understand the comment? The author used GCC, and GCC is only able to vectorize the loop. But clang on the other hand, essentially turned this O(n) algorithm to calculate a particular sum into an O(1) result.

> the reason the optimizer does what you see is undefined behavior due to signed integer overflow

Yes undefined behavior gives the optimizer the right in this case to transform the code into anything, including a nonsense answer, or a trap instruction. But the optimizer did not; it produced the right answer under 2's complement arithmetic.

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#27
post #26

Earlier quoted context omitted.

Did you read TFA? The author did that (though using GCC), and the reason the optimizer does what you see is undefined behavior due to signed integer overflow.

Did you understand the comment? The author used GCC, and GCC is only able to vectorize the loop. But clang on the other hand, essentially turned this O(n) algorithm to calculate a particular sum into an O(1) result. > the reason the optimizer does what you see is undefined behavior due to signed integer overflow Yes undefined behavior gives the optimizer the right in this case to transform the code into anything, inc…

I did read the comment, but it wasn't clear which of the two possibilities you meant. I wanted a clarification. Thanks.

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#29
post #3

TIL about printing ASM from debug JVMs.

If you use Oracle Studio you can even see it on the IDE.

https://www.youtube.com/watch?v=_cFwDnKvgfw

There are also other tools like JITWatch.

https://github.com/AdoptOpenJDK/jitwatch/wiki/Videos-and-Sli...

https://vimeo.com/181925278

Re: Why is 2 * (i * i) faster than 2 * i * i in Java?

#30

So it's an issue of the optimizer; as is often the case, it unrolls too aggressively and shoots itself in the foot, all the while missing out on various other opportunities. In my experience, loop unrolling should basically never be done except in extremely degenerate cases; I remember not long ago someone I know who also optimises Asm remarking "it should've died along with the RISC fad". The original goal was to re…

In addition to the optimisations already mentioned, loop unrolling also typically enables vectorisation in compilers. You might argue that for vectorisation it is not exactly necessary to have the relevant oerations next to each other in a continuous instruction stream, but it makes the vectorisation pass a lot nicer and simpler (if it can be called that to begin with).
Post reply on HN