我正在阅读这个问题,它已被接受。我阅读了评论,但我无法弄清楚产生优化的原因。
为什么在使用以下代码时,汇编代码中会出现分支?
x >= start && x <= end
编辑:
为清楚起见,我想了解接受的答案产生的优化原因。据我了解,这是编译器生成的汇编代码中存在的分支。我想了解为什么生成的代码中有一个分支。
我正在阅读这个问题,它已被接受。我阅读了评论,但我无法弄清楚产生优化的原因。
为什么在使用以下代码时,汇编代码中会出现分支?
x >= start && x <= end
编辑:
为清楚起见,我想了解接受的答案产生的优化原因。据我了解,这是编译器生成的汇编代码中存在的分支。我想了解为什么生成的代码中有一个分支。
请注意,链接的问题具有根本不同的表达方式
x >= start && x++ <= end
这是根本不同的,因为这里的第二个子表达式有副作用。我会解释的。
请注意,这&&是一个短路运算符。这意味着如果x >= start评估为false,则机器可以对 的评估进行分支x <= end。
更准确地说,当编译器发出指令时x >= start && x <= end,它可以发出指令以在评估为假x <= end时进行分支。x >= start
但是,我强调在上述陈述中使用了can这个词。这样做的原因是因为x <= end没有副作用,因此编译器是否分支对其进行评估并不重要。
但是,如果第二个表达式确实有副作用,编译器必须对其进行分支。因为&&是一个短路运算符,所以 in a && b, ifb有任何副作用,如果计算结果为;则不能观察到它们。这是 C 和大多数(如果不是所有类似 C 的语言)中短路的要求。afalse
所以,特别是当你看
define POINT_IN_RANGE_AND_INCREMENT(p, range)
(p <= range.end && p++ >= range.start)
请注意,第二个表达式p++ >= range.start有副作用。即,(后)递增p。但是只有在评估为1时才能观察到这种副作用。因此,编译器必须对if评估为 false的评估进行分支。p <= range.endtruep++ >= range.startp <= range.end
这导致分支的原因是因为机器要评估该表达式,它使用这样一个事实,即如果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的富有洞察力的评论。