可能/不太可能等同于MSVC

Fra*_*ger 46 compiler-construction optimization gcc visual-studio likely-unlikely

GCC编译器支持__builtin_expect语句,该语句用于定义可能的和不太可能的宏.

例如.

#define likely(expr)    (__builtin_expect(!!(expr), 1))
#define unlikely(expr)  (__builtin_expect(!!(expr), 0))
Run Code Online (Sandbox Code Playgroud)

是否有Microsoft Visual C编译器的等效声明,或等效的东西?

小智 20

根据http://www.akkadia.org/drepper/cpumemory.pdf(第57页),即使CPU正确动态预测,使用静态分支预测仍然有意义.原因是如果正确进行静态预测,将更有效地使用L1i缓存.


Dig*_*oss 19

我说只是平底船

没什么东西跟它一样了.有__assume(),但不要使用它,它是一种不同的优化器指令.

真的,gnu内置包装在宏中的原因是,如果__GNUC__没有定义,你可以自动摆脱它.这些宏没有任何必要的东西,我打赌你不会注意到运行时差.

摘要

*likely在非GNU上摆脱(null out).你不会错过它.

  • 我有一个硬件设备,在进行了函数调用之后,我需要执行像`safeCall(mDevice.doit())`这样的检查,我的`safeCall`是内联的,可以提高性能,但只有当我有可能/不可能的分支时.我想说这些宏可能很有用. (12认同)
  • 虽然你的建议是反对它,但在这种情况下将`_assume`命名为"close"是一种不吉利的措辞,因为它甚至不是很相似.不知情的读者可能会错误地解释_"可能会得到错误的代码".它的意思相当于`__builtin_unreachable`.使用它进行分支提示不仅危险,它始终是_incorrect_. (6认同)
  • "一般来说,你应该更喜欢使用[分支预测](-fprofile-arcs)的实际配置文件反馈,因为程序员在预测他们的程序实际执行情况方面是出了名的." https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html (4认同)
  • 更准确地说,`_assume(cond)` 在语义上在很大程度上等同于 GCC 中的 `if (!(cond)) __builtin_unreachable();`。这意味着使用它作为分支提示允许编译器删除整个“无法访问”的分支和条件,如果它没有副作用。 (3认同)
  • 好吧,我确实错过了"不太可能"的内在.没有PGO(这是一个PITA)*愚蠢的*MSVC几乎*总是*命令指令错误的方式. (2认同)

小智 14

C++ 20标准将包括[[likely]][[unlikely]]分支预测属性.

最新版本的属性提案可以在http://wg21.link/p0479找到

原始属性提案可以在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html找到.

程序员应该更喜欢PGO.如果应用不正确,属性可以轻松降低性能,或者在程序更改时它们稍后变得不正确

  • [获得GCC的__builtin_expect(又称“可能” /`不太可能)之类的机会是什么?](https://blogs.msdn.microsoft.com/vcblog/2016/05/04/new-code-optimizer /)*不实现此功能的参数是它是非标准的。MSVC致力于实现标准功能,而不是以与其他编译器不兼容的方式扩展语言。(过去我们已经做了大量的工作。)有一个标准建议来引入这样的属性。标准化后,我们将予以实施:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0627r0.pdf* (2认同)

nem*_*equ 9

我知道这个问题是关于 Visual Studio 的,但我将尝试回答尽可能多的编译器(包括 Visual Studio)\xe2\x80\xa6

\n

十年后,进步了!截至 Visual Studio 2019 MSVC 仍然不支持类似的东西(即使它是最流行的内置/内在),但正如 Pauli Nieminen 上面提到的,C++20 有likely/unlikely属性,可用于创建可能的/不太可能的宏和 MSVC 通常会很快添加对新 C++ 标准的支持(与 C 不同),因此我希望 Visual Studio 2021 能够支持它们。

\n

目前(2019-10-14)只有GCC支持这些属性,甚至只应用于标签,但至少做一些基本的测试就足够了。这是一个快速实现,您可以在 Compiler Explorer 上测试

\n
#define LIKELY(expr) \\\n  ( \\\n    ([](bool value){ \\\n      switch (value) { \\\n        [[likely]] case true: \\\n          return true; \\\n        [[unlikely]] case false: \\\n          return false; \\\n      } \\\n    }) \\\n  (expr))\n#define UNLIKELY(expr) \\\n  ( \\\n    ([](bool value){ \\\n      switch (value) { \\\n        [[unlikely]] case true: \\\n          return true; \\\n        [[likely]] case false: \\\n          return false; \\\n      } \\\n    }) \\\n  (expr))\n
Run Code Online (Sandbox Code Playgroud)\n

编辑(2022-05-02):MSVC 2022 支持 C++20,包括[[likely]]/ [[unlikely]],但为此生成了绝对糟糕的代码(请参阅这篇文章的评论)...不要在那里使用它。

\n

您可能需要 #ifdef 来支持无法处理它的编译器,但幸运的是大多数编译器都支持__builtin_expect

\n
    \n
  • 海合会3.0
  • \n
  • \n
  • ICC 至少从 13 年开始,可能更久。
  • \n
  • Oracle Development Studio 12.6+,但仅限 C++ 模式。
  • \n
  • ARM 4.1
  • \n
  • IBM XL C/C++ 至少从 10.1 开始,可能更长。
  • \n
  • TI 自 6.1 起
  • \n
  • TinyCC 自 0.9.27 起
  • \n
\n

GCC 9+ 还支持__builtin_expect_with_probability. 它在其他地方不可用,但希望有一天\xe2\x80\xa6 尝试弄清楚是否使用 ilkely/不太可能\xe2\x80\x94 需要大量的猜测,你只需设置概率并且编译器(理论上)做了正确的事情。

\n

另外,clang 支持 a __builtin_unpredictable(从 3.8 开始,但使用 进行测试__has_builtin(__builtin_unpredictable))。由于现在很多编译器都是基于 clang 的,所以它可能也适用于它们。

\n

如果您希望这一切都完成并准备好,您可能会对我的项目之一感兴趣,Hedley。它是一个单一的公共域 C/C++ 头文件,适用于几乎所有编译器,并包含许多有用的宏,包括HEDLEY_LIKELYHEDLEY_UNLIKELYHEDLEY_UNPREDICTABLEHEDLEY_PREDICTHEDLEY_PREDICT_TRUEHEDLEY_PREDICT_FALSE。目前还没有 C++20 版本,但应该很快就会出现\xe2\x80\xa6

\n

即使您不想在项目中使用 Hedley,您可能也想检查那里的实现,而不是依赖上面的列表;我可能会忘记用新信息更新这个答案,但赫德利应该始终保持最新状态。

\n


Mic*_*ael 6

__assume应该是类似的.

但是,如果你想要做到这一点,你应该使用Profile Guided Optimization而不是静态提示.

  • 我认为这可能很危险.据微软称:"由于编译器基于__assume生成代码,如果__assume语句中的表达式在运行时为假,则该代码可能无法正常运行." (11认同)
  • 抱歉,PGO是PITA,特别是在任何体面复杂的图书馆.我更清楚自己代码中的可能性和可能性. (3认同)

Vya*_*ets 6

根据英特尔的分支和循环重组预防错误预测文件:

为了有效地编写代码以利用这些规则,在编写if-else或switch语句时,首先检查最常见的情况,然后逐步处理最不常见的情况.

不幸的是你不能写类似的东西

#define if_unlikely(cond) if (!(cond)); else 
Run Code Online (Sandbox Code Playgroud)

因为VS10的MSVC优化器忽略了这样的"提示".

由于我更喜欢​​在代码中首先处理错误,因此我似乎编写效率较低的代码.幸运的是,第二次CPU遇到分支时,它将使用其统计信息而不是静态提示.

  • 回答Xentrax:你关于MSVC的声明似乎与我的观察不符.我正在使用VS 2010,并在使用普通if时看到编译器生成"jne".但是当使用else时,编译器会生成一个"je",并将else块放在主流之后.因此,使用MSVC,您的定义确实可行.现在,如果我能从MS找到这样的声明,支持的行为...... (7认同)

小智 5

现在微软表示他们已经实现了可能/不可能的属性

但事实上,使用“可能”和不使用之间没有任何区别。

我已经编译了这些代码并产生相同的结果

    int main()
    {
        int i = rand() % 2;
        if (i) [[likely]]
        {
           printf("Hello World!\n");
        }
        else
        {
            printf("Hello World2%d!\n",i);
        }
    }
Run Code Online (Sandbox Code Playgroud)
    int main()
    {
        int i = rand() % 2;
        if (i)
        {
           printf("Hello World!\n");
        }
        else [[likely]]
        {
            printf("Hello World2%d!\n",i);
        }
    }
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

  • 这是对的。[[可能]] 和 [[不太可能]] 都是废话。跟踪与优化器挂钩的功能如下:https://developercommunity2.visualstudio.com/t/unlikelylikely-have-no-effect-i/1383350 (2认同)