mov edx, [esp+8]
xor eax, eax
mov ecx, array_start
L:
cmp [ecx], edx ; CF = (unsigned) [ecx] < edx
adc eax, 0 ; eax += CF
add ecx, 4
cmp ecx, array_end
jb L
ret
and this version is 40% faster on my machine than the signed version.Of course, you could also go all out and vectorize: vpcmpgtd, then vpaddd for per-column subtotal, then sum the elements at the end, then negate. Combined with the negative index trick, you might be able to get it down to single cycle per 8 ints. Ahh, the joys of micro-optimizing toy loops!
http://people.cs.clemson.edu/~mark/eager.html says ...I've seen it alleged that some mainframe processors in the 1960s and 1970s executed down both paths beyond a branch; but, as far as I'm aware, multiple-path execution has never been done by a commercial processor.
http://196.29.172.66:8080/jspui/bitstream/123456789/4424/1/E...
(I'm quite tempted to get out one of my P55Cs to try it out...)
if (array[i] < boundary) count++;
is slower than count += (array[i] < boundary) ? 1 : 0;
Any reason why compilers can't infer the latter?http://yarchive.net/comp/linux/cmov.html
> In contrast, if you use a predicated instruction, ALL of it is on the critical path. Calculating the conditional is on the critical path. Calculating the value that gets used is obviously ALSO on the critical path, but so is the calculation for the value that DOESN'T get used too. So the cmov - rather than speeding things up - actually slows things down, because it makes more code be dependent on each other.
GCC creates different code for the variations, but the generated code is too complex for me to say which one is faster. edit: with -Os GCC generates identical code too.
if (array[i] < boundary) count+=2;
I had to work hard to make GCC not produce optimal code. Even this if (array[i] < boundary) return count+1; else return count;
came out the same as all the others.Avoiding branch prediction is hardly news. Was the article's author even compiling with optimizations enabled?
Quite possibly not. Which, I guess, is reasonable, since the point was really about cpu instructions and not C compilers. What comes out is more predictable with optimizations off.
Note that the author mentions the optimizer in relation to the second version. I think it might be because that code generates a branch with optimizations off in Visual C++. gcc seems to treat ?: as inherently a cmov and VC++ seems to treat it no differently than an if.
>>The cost of a single increment operation is highly variable. At low boundary values, it is around 0.03 time units per increment. But at high boundary values, the cost drops to one tenth that.
The cost of an increment operation has nothing to do with it. It's very fast and doesn't change. What matters is the cost of flushing the pipeline on every mispredicted branch.
Maybe you're supposed to get that that part is "naive" and ignore it once you've read the whole article?