Is there any portable way of doing branch prediction hints? Consider the following example:
if (unlikely_condition) {
/* ..A.. */
} else {
/* ..B.. */
}
Is this any different than doing:
if (!unlikely_condition) {
/* ..B.. */
} else {
/* ..A.. */
}
Or is the only way to use compiler specific hints? (e.g. __builtin_expect on GCC)
Will compilers treat the if
conditions any differently based on the ordering of the conditions?
Just be consistant with what you do. I like to use
But the compiler should treat this equally.
Optimization is inherently a compiler thing, so you have to use compiler functionality to help it. The language itself doesn't care about (or mandate) optimizations.
So the best you can do without compiler-specific extensions is organize your code in such a way where your compilers will "do the right thing" without help. But if you want to be sure, tap in to compiler extensions. (You might try abstracting them behind the preprocessor, so your code remains portable.)
What's wrong with checking for a specific compiler via
#ifdef
and hiding these things behind a custom macro? You can#define
it to expand to the plain expression in cases you don't have a compiler that supports these optimization hints. I recently did something similar with explicit cache prefetches which GCC supports via an intrinsic function.The canonical way to do static branch prediction is that
if
is predicted not-branched (i.e. everyif
clause is executed, notelse
), and loops and backward-goto
s are taken. So, don't put the common case inelse
if you expect static prediction to be significant. Getting around an untaken loop isn't as easy; I've never tried but I suppose putting it an anelse
clause should work pretty portably.Many compilers support some form of
#pragma unroll
, but it will still be necessary to guard it with some kind of#if
to protect other compilers.Branch prediction hints can theoretically express a complete description of how to transform a program's flow-control graph and arrange the basic blocks in executable memory… so there are a variety of things to express, and most won't be very portable.
As GNU recommends in the documentation for
__builtin_expect
, profile-guided optimization is superior to hints, and with less effort.In most cases, the following code
is actually
Note that if A is true, "code A" is already in the pipeline. The processor will see the "jmp p2" command ahead, and will load p2 code to the pipeline.
If A is false, the "code !A" may not be in the pipleline, therefore it may be slower.
Conclusions:
: