我正在阅读这个问题,它已被接受。我阅读了评论,但我无法弄清楚产生优化的原因。
为什么在使用以下代码时,汇编代码中会出现分支?
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 的语言)中短路的要求。a
false
所以,特别是当你看
define POINT_IN_RANGE_AND_INCREMENT(p, range)
(p <= range.end && p++ >= range.start)
请注意,第二个表达式p++ >= range.start
有副作用。即,(后)递增p
。但是只有在评估为1
时才能观察到这种副作用。因此,编译器必须对if评估为 false的评估进行分支。p <= range.end
true
p++ >= range.start
p <= 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的富有洞察力的评论。