3 ms·
I've now looked at it more closely, and tested on Skylake and Haswell. I don't think the case described in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67153 h
by nkurz 11y ago
I've now looked at it more closely, and tested on Skylake and Haswell. I don't think the case described in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67153 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67153 is actually a bug in either the compiler or the processor. Rather, it's the behavior you would expect if the compiler (at compile time) guesses wrong about whether a branch is likely to be taken or not.
Which choice is fastest on the depends on the runtime word list, and thus there is no reason to fault the compiler for either choice. For the processor, the difference is simply that a "branch not taken" is faster than a branch taken. The fast version involves a loop that executes in a single cycle:
77.21 │210:┌─→add $0x4,%rcx
0.66 │ │ cmp %rcx,%r8
│ │↓ je 260
4.20 │219:│ mov (%rcx),%edi
0.88 │ │ test %r9d,%edi
│ └──jne 210
The cmp/je and test/jne instructions fuse into on µop each, so that (incredibly) the processor can execute the remaining 4 fused µops at an iteration per cycle. If the loop is rearranged so that the middle branch is taken, each iteration takes a minimum of 2 cycles instead.
The solution (as the author mentions in a parenthetical) is to give more information to the compiler with "__builtin_expect". I wasn't able to test on Sandy Bridge or earlier, but my strong guess would be that Haswell and Skylake have a potential speedup, rather than a regression. I'll try to add a comment to the bug later tonight.