6 ms·
Out of curiosity, how have you managed to do that? I've noticed even with GCC or Clang's -O3 option I'm still getting jumps rather than conditional moves.
by hamsham 7y ago
Out of curiosity, how have you managed to do that? I've noticed even with GCC or Clang's -O3 option I'm still getting jumps rather than conditional moves.
- aidenn0 7y agoI was using SBCL[1], not GCC nor clang. For that I found that a very short case statement with trivial expressions seems to work. e.g. in a UTF-8 decoder, masking the bits and then having a case statement rather than an if/then/else (i.e. COND in lisp) construct on them. As another side note, for the UTF-8 decoder case, it was easy to make ASCII-only text fairly fast with the jumps (it's trivial for the branch predictor), but mixed text suffered greatly. 1: http://sbcl.org/ http://sbcl.org/
- fsfod 7y agoClang\LLVM has some heuristics where it will convert cmovs generated by earlier passes back in to jumps https://reviews.llvm.org/D34769 https://reviews.llvm.org/D34769. Also the compilers can't always prove its safe to evaluate both sides of a ternary operator which would be needed to use a cmov. Here's a compiler explorer sample for clang and GCC that shows all these problems https://godbolt.org/z/IpZfZv https://godbolt.org/z/IpZfZv, you change the -x86-cmov-converter option to true re-enable clangs cmov converter which will disable cmov in the last function.
- BeeOnRope 7y agoYeah I have spent a long time fighting to get cmov into code that wants it. The cmov1 case in your example ends up getting a cmov1 because the compiler was able to apply the cmov to the pointer rather than to the read value (essentially transforming it to `return (cond ? v1 : v2)->i`). It's fragile though, if you change it a bit it stops working: https://godbolt.org/z/hs71Jb https://godbolt.org/z/hs71Jb It isn't clear if it stops because the heuristics aren't in favor any more (you'd need 2 cmov-y things to handle the +1), or because the compiler no longer sees the transformation is possible at all. gcc even fails if you add +1 to both sides which should be almost as simple as the original: https://godbolt.org/z/y7PIcU https://godbolt.org/z/y7PIcU I have tried to use the "unconditionally deference" trick many times to convince a cmov, but it seems it doesn't always work because the compiler might re-optimize it back to only doing the read inside the branch/conditional, so later phases don't see the read as safe.