Interestingly, when written in C, gcc compiles the inner loop to (comments mine):
.L11:
movl (%r12,%rdx,4), %eax ; load value of data[c] in eax
leal (%rsi,%rax), %ecx ; (sum is in rsi)
; add data[c] to sum, store in ecx
; yes, this is (ab)using the
; "load effective address" instruction as an
; "add a to b and store in c" instruction
cmpl $128, %eax ; compare data[c] to 128
cmovge %ecx, %esi ; if above comparison was true,
; set rsi (sum) to ecx, computed above
addq $1, %rdx ; c = c+1
.L9:
cmpq $134217727, %rdx ; this is the for end clause
jbe .L11
jmp .L12
In effect, it's adding data[c] to sum, storing it in a register and storing the result back in sum if data[c] was larger than 128, all with no jumps except for the loop itself and that jump is mispredicted exactly once. I don't see why java's JIT can't do the same.
In the answers to the original question, somebody mentioned that gcc will convert branches into conditional moves, but only at -O3. I never use -O3, because it's frequently slower than -O2. In another answer, somebody pointed out that the ternary operator always generates a conditional move, which I never knew.
Comments
Interestingly, when written in C, gcc compiles the inner loop to (comments mine):
In effect, it's adding data[c] to sum, storing it in a register and storing the result back in sum if data[c] was larger than 128, all with no jumps except for the loop itself and that jump is mispredicted exactly once. I don't see why java's JIT can't do the same.In the answers to the original question, somebody mentioned that gcc will convert branches into conditional moves, but only at -O3. I never use -O3, because it's frequently slower than -O2. In another answer, somebody pointed out that the ternary operator always generates a conditional move, which I never knew.