Search code examples
c++compilationlogical-operatorsoperator-precedenceboolean-expression

Why the generated assembler of certain boolean expressions contains a conditional jump?


Consider this code:

bool res_true();
bool res_false();

bool test1(const bool cond)
{
    return (cond && res_true()) || (!cond && res_false());
}

bool test2(const bool cond)
{
    return cond ? res_true() : res_false();
}

Both test1() and test2() select a certain boolean result between res_true(),res_false() basing on a boolean input cond. I know that c++ compilers nowadays can be pretty smart, but I usually tended to use the test1() form -despite less readable- because in my naivety I thought that in that case there were just logic boolean operations, with no conditional jumps; they are bad, right? Well today I tried that in compiler explorer and saw that the generated output is very similar for both the functions: test1() contains a conditional jump (moreover, depending on compiler and enabled optimizations, the generated assembler of test1() can be worst than the one of test2()), why is that?


Solution

  • That's because the default c++ boolean operators || and && are short-circuited (with guaranteed left-to-right evaluation), so a logical expression may or may not be fully evaluated depending on the results of his sub-expressions. for example in:

    f() || g()
    

    f() will be called first and g() won't be called if f() was true; similarly in:

    f() && g()
    

    g() won't be called if f() was false, so the generated assembler must contain a conditional jump to ensure to short-circuit the expression.