if (c)
x = v;
else
y = v;
..but why not "improve" this by using the C ternary operator ? : as follows:
*(c ? &x : &y) = v;
Now, how does this shape up when compiled on an x86 with gcc -O2 ? Well, the first example compiles down to a test and a branch where as the second example uses a conditional move instruction (cmove) and avoids the test and branch and is faster code. Result!
OK, so this isn't rocket science, but does show that a little bit of abuse of the ternary operator can save me a few cycles if the compiler is clued up to use cmove.
This is just awful. Make the compiler smarter and leave this code alone.
ReplyDeleteI did say it was a hack ;-)
ReplyDeleteThis is nice, but I'm often hesitant to design around GCC's heuristics.
ReplyDeleteI'm not going to advocate the use of it. It just was a small C mind doodle really.
ReplyDeleteIn C++ one can do this directly:
ReplyDelete( c ? x : y) = v;
And the resulting assembler is just like the if statement using g++ -O2
DeleteBut doesn't the hack version force the compiler to use actual memory for x and y, where the normal version would allow it to use registers for those?
ReplyDeleteIs the hack version *really* faster in a real-world-ish test case (where x and y aren't declared as volatile or otherwise forced to land in memory locations?)
Good observation Kamal. Not sure. I suspect I need to really see how it works in real world examples. We can learn from this is never make rash statements that one saves cycles until one has used the code in real examples rather than simple tests.
DeleteNice. I might have to add this to my list of evil C interview questions. ;-)
ReplyDeleteIn which case, perhaps you should also consider: http://smackerelofopinion.blogspot.com/2009/07/abusing-c-for-fun.html
DeleteHow about just:
ReplyDeletec ? x = v : y = v;
c ? x = v : y = v; produces "error: lvalue required as left operand of assignment", so I suggest using instead the following:
Deletec ? (x = v) : (y = v);
or even the more uglier:
c ? 1, x = y : 1, y = v;
These compile down to a jump and no cmove.
I'm sure there are many other things to worry about before you care about optimizing this use-case.
ReplyDeletePersonally I'm all for making the code easily readable. But then I prefer C++ to C.
I agree, I don't want to promote bad code style to save a cycle or two. I thought it was an interesting abuse of C really.
DeleteThis works fine in other architectures and compiler?
ReplyDeleteLinus Torvalds posted an interesting discussion on the CMOVE instruction here. He appears to be deprecating its use:
ReplyDeletehttp://yarchive.net/comp/linux/cmov.html
I wonder how relevant that is to newer Intel CPUs? I need to investigate that.
Delete