optimizing predictable branches on x86

Nick Piggin nickpiggin@yahoo.com.au
Tue Feb 26 03:34:00 GMT 2008


Hi list,

gcc-4.3 appears to make quite heavy use of cmov to eliminate
conditional branches on x86(-64) architecture, even for those
branches that are determined to be predictable.

The problem with this is that the data dependancy introduced
by the cmov can restrict execution, wheras a predicted branch
will not. The Intel manual says not to use cmov for
predictable branches.

I have a test case which I /believe/ demonstrates that a cond
jump is not a great deal slower in the case where there are
no data dependancy hazards hit, and can be quite a bit faster
in the case where there is a dependancy -- if the branch is
predictable. It also shows that if the branch is unpredictable
then cmov can be a good win (as expected).

Compiled with:
gcc-4.3 -O3 -falign-functions=64 -falign-loops=64 -falign-jumps=64
        -falign-labels=64 -march=core2/opteron

Opteron:
 no deps,   predictable -- C    code took   8.92ns per iteration
 no deps,   predictable -- cmov code took   9.09ns per iteration
 no deps,   predictable -- jmp  code took   9.60ns per iteration[1]
has deps,   predictable -- C    code took  20.04ns per iteration
has deps,   predictable -- cmov code took  18.09ns per iteration
has deps,   predictable -- jmp  code took  14.97ns per iteration[2]
 no deps, unpredictable -- C    code took   8.92ns per iteration
 no deps, unpredictable -- cmov code took   9.09ns per iteration
 no deps, unpredictable -- jmp  code took  15.19ns per iteration[3]
has deps, unpredictable -- C    code took  32.07ns per iteration
has deps, unpredictable -- cmov code took  33.15ns per iteration
has deps, unpredictable -- jmp  code took  69.04ns per iteration[4]

[1] jmp is slightly slower, can it be improved?
[2] nice improvement here
[3] mispredict penalty, cmov is a big win
[4] mispredict which includes load missing cache!

Core2:
 no deps,   predictable -- C    code took   4.24ns per iteration
 no deps,   predictable -- cmov code took   4.27ns per iteration
 no deps,   predictable -- jmp  code took   4.24ns per iteration
has deps,   predictable -- C    code took   6.04ns per iteration
has deps,   predictable -- cmov code took   6.59ns per iteration
has deps,   predictable -- jmp  code took   5.04ns per iteration
 no deps, unpredictable -- C    code took   4.24ns per iteration
 no deps, unpredictable -- cmov code took   4.25ns per iteration
 no deps, unpredictable -- jmp  code took   8.79ns per iteration
has deps, unpredictable -- C    code took  49.78ns per iteration
has deps, unpredictable -- cmov code took  50.28ns per iteration
has deps, unpredictable -- jmp  code took  75.67ns per iteration

Core2 follows a similar pattern, although it's not seeing any
slowdown in the "no deps, predictable, jmp" case like K8 does.

Any comments? (please cc me) Should gcc be using conditional jumps
more often eg. in the case of __builtin_expect())?

Thanks,
Nick
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cmov4.c
Type: text/x-csrc
Size: 4470 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20080226/feee1448/attachment.bin>


More information about the Gcc mailing list