In general, GCC assumes that conditional expressions in if statements are true - there are exceptions, but they are contextual.
extern int s(int); int f(int i) { if (i == 0) return 1; return s(i); }
produces
f(int): testl %edi, %edi jne .L4 movl $1, %eax ret .L4: jmp s(int)
a
extern int t(int*); int g(int* ip) { if (!ip) return 0; return t(ip); }
gives:
g(int*): testq %rdi, %rdi je .L6 jmp t(int*) .L6: xorl %eax, %eax ret
(see godbolt )
Note that in f the jne branch (suppose the condition is true), and in g condition is considered false.
Now compare with the following:
extern int s(int); extern int t(int*); int x(int i, int* ip) { if (!ip) return 1; if (!i) return 2; if (s(i)) return 3; if (t(ip)) return 4; return s(t(ip)); }
which produces
x(int, int*): testq %rsi, %rsi je .L3
Here we see one of the contextual factors: GCC noticed that he could reuse L2 here, so he decided to consider the final conditional unlikely so that he could emit less code.
Let's look at the assembly of the example you specified:
#define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) extern void raiseError(); int f(int A, int B, int Z) { if (A) return 1; else if (B) return 2; else if (Z) return 3; raiseError(); return -1; }
The assembly is as follows:
f(int, int, int): movl $1, %eax testl %edi, %edi jne .L9 movl $2, %eax testl %esi, %esi je .L11 .L9: ret .L11: testl %edx, %edx je .L12
Note that the generated code branches when! Z is true, he is already behaving as if Z was probable. What happens if we say that Z is likely?
#define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) extern void raiseError(); int f(int A, int B, int Z) { if (A) return 1; else if (B) return 2; else if (likely(Z)) return 3; raiseError(); return -1; }
now we get
f(int, int, int): movl $1, %eax testl %edi, %edi jne .L9 movl $2, %eax testl %esi, %esi je .L11 .L9: ret .L11: movl $3, %eax
The point here is that you should be careful when using these macros and carefully study the code before and after a thorough check to make sure that you get the expected results, and a comparative test (for example, with performance) to make sure that the processor makes predictions that are consistent with the code you generate.