Reputation: 45
I have a "MyFunction" I keep obsessing over if I should or shouldn't use goto on it and in similar (hopefully rare) circumstances. So I'm trying to establish a hard-and-fast habit for this situation. To-do or not-to-do.
int MyFunction()
{ if (likely_condition)
{
condition_met:
// ...
return result;
}
else /*unlikely failure*/
{ // meet condition
goto condition_met;
}
}
I was intending to net the benefits of the failed conditional jump instruction for the likely case. However I don't see how the compiler could know which to streamline for case probability without something like this.
Upvotes: 4
Views: 362
Reputation: 96311
It looks like the code should work as you expect as long as condition_met:
doesn't skip variable initializations.
No, and you don't even know that the obfuscated version compiles into more optimal code. Compiler optimizations (and processor branch prediction) are getting very smart in recent times.
3.
int MyFunction()
{
if (!likely_condition)
{
// meet condition
}
condition_met:
// ...
return result;
}
or, if it helps your compiler (check the assembly)
int MyFunction()
{
if (likely_condition); else
{
// meet condition
}
condition_met:
// ...
return result;
}
Upvotes: 4
Reputation: 1
I would highly recommend using the __builtin_expect()
macro (GCC) or alike for your particular C++ compiler (see Portable branch prediction hints) instead of using goto
:
int MyFunction()
{ if (__builtin_expect(likely_condition))
{
// ...
return result;
}
else /*unlikely failure*/
{ // meet condition
}
}
As others also mentioned goto
is error prone and evil from the bones.
Upvotes: 1
Reputation: 490768
It appears to me that the optimization you're trying to do is mostly obsolete. Most modern processors have branch prediction built in, so (assuming it's used enough to notice) they track how often a branch is taken or not and predict whether the branch is likely to be taken or not based on its past pattern of being taken or not. In this case, speed depends primarily on how accurate that prediction is, not whether the prediction is for taken vs. not taken.
As such, you're probably best off with rather simpler code:
int MyFunction() {
if (!likely_condition) {
meet_condition();
}
// ...
return result;
}
Upvotes: 5
Reputation: 93930
A modern CPU will take that branch either way with equal performance if it makes the correct branch prediction. So if that is in an inner loop, the performance of if (unlikely) { meet condition } common code;
will match what you have written.
Also, if you spell out the common code in both branches the compiler will generate code that is identical to what you have written: The common case will be emitted for the if
clause and the else
clause will jmp
to the common code. You see this all the time with simpler terminal cases like *out = whatever; return result;
. When debugging it can be hard to tell which return
you're looking at because they've all been merged.
Upvotes: 4