c++ - 为什么在比较范围内的数字时,汇编代码中会出现分支?

标签 c++ c performance math optimization

我正在阅读 this问题,这是公认的答案。我阅读了评论,但无法弄清楚产生优化的原因。

为什么在使用下面的代码时,汇编代码中会出现分支?

x >= start && x <= end

编辑:
为了清楚起见,我想了解接受的答案产生优化的原因。据我了解,这是编译器生成的汇编代码中存在的分支。我想了解为什么生成的代码中有一个分支。

最佳答案

请注意,链接的问题有一个根本不同的表达方式

x >= start && x++ <= end

这是根本不同的,因为这里的第二个子表达式有副作用。我会解释。

请注意 &&short-circuit operator .这意味着如果 x >= start评估为 false ,机器可以分支评估x <= end .

更准确地说,当编译器为 x >= start && x <= end 发出指令时,它可以发出指令以在 x <= end 上分支什么时候x >= start计算结果为假。

但是,我在上述陈述中强调了可以这个词的使用。这样做的原因是因为x <= end没有副作用,因此编译器是否分支评估它并不重要。

但是,如果第二个表达式确实有副作用,编译器必须对其进行分支。自 &&是短路运算符,在 a && b 中, 如果 b有任何副作用,如果a,它们绝不能被观察到评估为 false ;这是 C 和大多数(如果不是所有类 C 语言的话)短路的要求。

所以,特别是,当你看

define POINT_IN_RANGE_AND_INCREMENT(p, range) 
    (p <= range.end && p++ >= range.start)

注意第二个表达式 p++ >= range.start有副作用。即,(后)递增 p通过 1 .但只有在 p <= range.end 时才能观察到这种副作用评估为 true .因此,编译器必须p++ >= range.start 的求值进行分支。如果p <= range.end计算结果为假。

这导致分支的原因是因为机器计算该表达式时,它使用了 if p <= range.end 的事实。 评估为 false , 然后它会自动知道整个表达式的计算结果为 false因此它不应该评估p++ >= range.start因为它有副作用。因此,它必须分支计算表达式的第二部分。所以在汇编中:

Ltmp1301:
 ldr    r1, [sp, #172] @ 4-byte Reload
 ldr    r1, [r1]
 cmp    r0, r1
 bls    LBB44_32
 mov    r6, r0         @ if the result of the compare is false 
 b      LBB44_33       @ branch over evaluating the second expression
                       @ to avoid the side effects of p++
LBB44_32:
 ldr    r1, [sp, #188] @ 4-byte Reload
 adds   r6, r0, #1
Ltmp1302:
 ldr    r1, [r1]
 cmp    r0, r1
 bhs    LBB44_36

深表感激Oli Charlesworth有见地的评论。

关于c++ - 为什么在比较范围内的数字时,汇编代码中会出现分支?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17114371/

相关文章:

c++ - 虚拟最佳实践

c - 如何在 FreeBSD 中获取打开的 posix 共享内存段列表

c++ - 后期绑定(bind)有什么优点?举一个 C++ 函数指针上下文中的例子

冲突类型错误

android - libGDX 中缓慢的模型批量渲染

c++ - 为什么使用 CvScalar

c++ - 检查连接状态 - Ignite 的 C++ odbc 驱动程序

c++ - boost .asio : can I do async_read and async_write simultaneously from one thread?

php - 存储每日页面浏览量以及总数的最有效方式

c++ - 与其他跨平台正则表达式库相比,Oniguruma 有多好?