6

私はこの質問を読んでいましたが、それは受け入れられた答えです。コメントを読みましたが、最適化が行われた理由がわかりませんでした。

次のコードを使用すると、アセンブリ コードで分岐が発生するのはなぜですか?

x >= start && x <= end

編集:
明確にするために、受け入れられた回答によって生成された最適化の理由を理解したいと思います。私が理解しているのは、コンパイラによって生成されたアセンブリ コードに存在する分岐です。生成されたコードに分岐がある理由を理解したい。

4

1 に答える 1

10

リンクされた質問の表現は根本的に異なることに注意してください

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

ここでの 2 番目のサブ式には副作用があるため、根本的に異なります。説明します。

&&短絡演算子であることに注意してください。これは、 が にx >= start評価される場合false、マシンは の評価に分岐できることx <= endを意味します。

より正確には、コンパイラが の命令を発行するときに、x >= start && x <= endがfalse に評価されたときに分岐する命令を発行できます。x <= endx >= start

ただし、上記のステートメントでcanという言葉を使用することを強調します。この理由は、x <= end副作用がないため、コンパイラがそれを評価して分岐するかどうかは問題ではないためです。

ただし、2 番目の式に副作用がある場合、コンパイラはそれを分岐する必要があります。&&は短絡演算子であるため、に何らかの副作用がa && bある場合は、 が に評価される場合に観察してはなりません。これは、C およびほとんど (すべてではないにしても C に似た言語) での短絡の要件です。bafalse

だから、特に、あなたが見るとき、

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

p++ >= range.start2 番目の式には副作用があることに注意してください。pつまり、(事後)インクリメント1. しかし、その副作用は、 が にp <= range.end評価される場合にのみ観察できtrueます。したがって、コンパイラは、ifが false と評価された場合の評価で分岐する必要があります。p++ >= range.startp <= range.end

これが分岐する理由は、マシンがその式を評価するために、if がp <= range.endに評価されるという事実を使用するためfalseです。その後、式全体が に評価されることを自動的に認識し、副作用があるため評価すべきではありませんfalse。したがって、式の 2 番目の部分を評価するために分岐する必要があります。したがって、アセンブリでは: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に深く感謝いたします。

于 2013-06-14T17:48:55.947 に答える