Reputation: 28428
GCC compiler supports __builtin_expect statement that is used to define likely and unlikely macros.
eg.
#define likely(expr) (__builtin_expect(!!(expr), 1))
#define unlikely(expr) (__builtin_expect(!!(expr), 0))
Is there an equivalent statement for the Microsoft Visual C compiler, or something equivalent ?
Upvotes: 64
Views: 28868
Reputation: 17472
I know this question is about Visual Studio, but I'm going to try to answer for as many compilers as I can (including Visual Studio)…
A decade later there is progress! As of Visual Studio 2019 MSVC still doesn't support anything like this (even though it's the most popular builtin/intrinsic), but as Pauli Nieminen mentioned above C++20 has likely
/ unlikely
attributes which can be used to create likely/unlikely macros and MSVC usually adds support for new C++ standards pretty quickly (unlike C) so I expect Visual Studio 2021 to support them.
Currently (2019-10-14) only GCC supports these attributes, and even then only applied to labels, but it is sufficient to at least do some basic testing. Here is a quick implementation which you can test on Compiler Explorer:
#define LIKELY(expr) \
( \
([](bool value){ \
switch (value) { \
[[likely]] case true: \
return true; \
[[unlikely]] case false: \
return false; \
} \
}) \
(expr))
#define UNLIKELY(expr) \
( \
([](bool value){ \
switch (value) { \
[[unlikely]] case true: \
return true; \
[[likely]] case false: \
return false; \
} \
}) \
(expr))
Edit (2022-05-02): MSVC 2022 supports C++20, including [[likely]]
/[[unlikely]]
, but generates absolutely terrible code for this (see the comments on this post)... don't use it there.
You'll probably want to #ifdef around it to support compilers that can't handle it, but luckily most compilers support __builtin_expect
:
GCC 9+ also supports __builtin_expect_with_probability
. It's not available anywhere else, but hopefully one day… It takes a lot of the guesswork out of trying to figure out whether to use ilkely/unlikely or not—you just set the probability and the compiler (theoretically) does the right thing.
Also, clang supports a __builtin_unpredictable
(since 3.8, but test for it with __has_builtin(__builtin_unpredictable)
). Since a lot of compilers are based on clang these days it probably works in them, too.
If you want this all wrapped up and ready to go, you might be interested in one of my projects, Hedley. It's a single public-domain C/C++ header which works on pretty much all compilers and contains lots of useful macros, including HEDLEY_LIKELY
, HEDLEY_UNLIKELY
, HEDLEY_UNPREDICTABLE
, HEDLEY_PREDICT
, HEDLEY_PREDICT_TRUE
, and HEDLEY_PREDICT_FALSE
. It doesn't have the C++20 version quite yet, but it should be there soon…
Even if you don't want to use Hedley in your project, you might want to check the the implementations there instead of relying on the lists above; I'll probably forget to update this answer with new information, but Hedley should always be up-to-date.
Upvotes: 9
Reputation: 13634
As the question is old, the answers saying there's no [[likely]]
/ [[unlikely]]
in MSVC, or that there's no impact are obsolete.
Latest MSVC supports [[likely]]
/ [[unlikely]]
in /std:c++20
and /std:c++latest
modes.
See demo on Godbolt's compiler explorer that shows the difference.
As can be seen from the link above, one visible effect on x86/x64 for if-else
statement is that the conditional jump forward will be for unlikely branch. Before C++20 and supporting VS version the same could be achieved by placing the likely branch into if
part, and the unlikely branch into else
part, negating the condition as needed.
Note that the effect of such optimization is minimal. For frequently called code in a tight loop, the dynamic branch prediction would do the right thing anyway.
Upvotes: 2
Reputation: 61
Now MS said they have implemented likely/unlikely attributes
But in fact there isn't any different between using "likely" or not using.
I have compiled these codes and is produce same result.
int main()
{
int i = rand() % 2;
if (i) [[likely]]
{
printf("Hello World!\n");
}
else
{
printf("Hello World2%d!\n",i);
}
}
int main()
{
int i = rand() % 2;
if (i)
{
printf("Hello World!\n");
}
else [[likely]]
{
printf("Hello World2%d!\n",i);
}
}
int pdb._main (int argc, char **argv, char **envp);
0x00401040 push ebp
0x00401041 mov ebp, esp
0x00401043 push ecx
0x00401044 call dword [rand] ; pdb.__imp__rand
; 0x4020c4
0x0040104a and eax, 0x80000001
0x0040104f jns 0x401058
0x00401051 dec eax
0x00401052 or eax, 0xfffffffe ; 4294967294
0x00401055 add eax, 1
0x00401058 je 0x40106d
0x0040105a push str.Hello_World ; pdb.___C__0O_NFOCKKMG_Hello_5World__CB_6
; 0x402108 ; const char *format
0x0040105f call pdb._printf ; int printf(const char *format)
0x00401064 add esp, 4
0x00401067 xor eax, eax
0x00401069 mov esp, ebp
0x0040106b pop ebp
0x0040106c ret
0x0040106d push 0
0x0040106f push str.Hello_World2_d ; pdb.___C__0BB_DODJFBPJ_Hello_5World2__CFd__CB_6
; 0x402118 ; const char *format
0x00401074 call pdb._printf ; int printf(const char *format)
0x00401079 add esp, 8
0x0040107c xor eax, eax
0x0040107e mov esp, ebp
0x00401080 pop ebp
0x00401081 ret
Upvotes: 5
Reputation: 146053
There is nothing like it. There is __assume(), but don't use it, it's a different kind of optimizer directive.
Really, the reason the gnu builtin is wrapped in a macro is so you can just get rid of it automatically if __GNUC__
is not defined. There isn't anything the least bit necessary about those macros and I bet you will not notice the run time difference.
Just get rid of (null out) *likely
on non-GNU. You won't miss it.
Upvotes: 17
Reputation: 1120
C++20 standard will include [[likely]]
and [[unlikely]]
branch prediction attributes.
The latest revision of attribute proposal can be found from http://wg21.link/p0479
The original attribute proposal can be found from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html
Programmers should prefer PGO. Attributes can easily reduce performance if applied incorrectly or they later become incorrect when program changes.
Upvotes: 26
Reputation: 529
According to Branch and Loop Reorganization to Prevent Mispredicts document from Intel:
In order to effectively write your code to take advantage of these rules, when writing if-else or switch statements, check the most common cases first and work progressively down to the least common.
Unfortunately you cannot write something like
#define if_unlikely(cond) if (!(cond)); else
because MSVC optimizer as of VS10 ignores such "hint".
As I prefer to deal with errors first in my code, I seem to write less efficient code. Fortunately, second time CPU encounters the branch it will use its statistics instead of a static hint.
Upvotes: 7
Reputation: 55395
__assume should be similar.
However, if you want to do this really well you should use Profile Guided Optimization rather than static hints.
Upvotes: 6
Reputation: 209
According to http://www.akkadia.org/drepper/cpumemory.pdf (page 57), it still makes sense to use static branch prediction even if CPU predicts correctly dynamically. The reason for that is that L1i cache will be used even more efficiently if static prediction was done right.
Upvotes: 20