If statement vs if-else statement, which is faster?

Julien__ picture Julien__ · Apr 4, 2017 · Viewed 16.2k times · Source

I argued with a friend the other day about those two snippets. Which is faster and why ?

value = 5;
if (condition) {
    value = 6;
}

and:

if (condition) {
    value = 6;
} else {
    value = 5;
}

What if value is a matrix ?

Note: I know that value = condition ? 6 : 5; exists and I expect it to be faster, but it wasn't an option.

Edit (requested by staff since question is on hold at the moment):

  • please answer by considering either x86 assembly generated by mainstream compilers (say g++, clang++, vc, mingw) in both optimized and non optimized versions or MIPS assembly.
  • when assembly differ, explain why a version is faster and when (e.g. "better because no branching and branching has following issue blahblah")

Answer

CompuChip picture CompuChip · Apr 4, 2017

TL;DR: In unoptimized code, if without else seems irrelevantly more efficient but with even the most basic level of optimization enabled the code is basically rewritten to value = condition + 5.


I gave it a try and generated the assembly for the following code:

int ifonly(bool condition, int value)
{
    value = 5;
    if (condition) {
        value = 6;
    }
    return value;
}

int ifelse(bool condition, int value)
{
    if (condition) {
        value = 6;
    } else {
        value = 5;
    }
    return value;
}

On gcc 6.3 with optimizations disabled (-O0), the relevant difference is:

 mov     DWORD PTR [rbp-8], 5
 cmp     BYTE PTR [rbp-4], 0
 je      .L2
 mov     DWORD PTR [rbp-8], 6
.L2:
 mov     eax, DWORD PTR [rbp-8]

for ifonly, while ifelse has

 cmp     BYTE PTR [rbp-4], 0
 je      .L5
 mov     DWORD PTR [rbp-8], 6
 jmp     .L6
.L5:
 mov     DWORD PTR [rbp-8], 5
.L6:
 mov     eax, DWORD PTR [rbp-8]

The latter looks slightly less efficient because it has an extra jump but both have at least two and at most three assignments so unless you really need to squeeze every last drop of performance (hint: unless you are working on a space shuttle you don't, and even then you probably don't) the difference won't be noticeable.

However, even with the lowest optimization level (-O1) both functions reduce to the same:

test    dil, dil
setne   al
movzx   eax, al
add     eax, 5

which is basically the equivalent of

return 5 + condition;

assuming condition is zero or one. Higher optimization levels don't really change the output, except they manage to avoid the movzx by efficiently zeroing out the EAX register at the start.


Disclaimer: You probably shouldn't write 5 + condition yourself (even though the standard guarantees that converting true to an integer type gives 1) because your intent might not be immediately obvious to people reading your code (which may include your future self). The point of this code is to show that what the compiler produces in both cases is (practically) identical. Ciprian Tomoiaga states it quite well in the comments:

a human's job is to write code for humans and let the compiler write code for the machine.