1. ホーム
  2. c++

[解決済み] <は<=より速いのか?

2022-03-15 16:40:31

質問

if (a < 901) よりも速い if (a <= 900) ?

この単純な例と全く同じではありませんが、ループ複雑なコードで若干のパフォーマンスの変化があります。これは、生成されたマシンコードと関係があるのでしょうけど、もしそうだとしたら、それは本当なのでしょうか?

解決方法は?

いいえ、ほとんどのアーキテクチャで高速化できません。特に指定はありませんが、x86では、積分比較は通常2つの機械語命令で実装されます。

  • A test または cmp を設定する命令です。 EFLAGS
  • そして Jcc (ジャンプ)命令 は、比較タイプ(とコードレイアウト)によります。
  • jne - 等しくない場合はジャンプ --> ZF = 0
  • jz - ゼロ(イコール)ならジャンプ --> ZF = 1
  • jg - 大きければジャンプ --> ZF = 0 and SF = OF
  • (その他...)

(簡潔にするために編集) コンパイルは $ gcc -m32 -S -masm=intel test.c

    if (a < b) {
        // Do something 1
    }

にコンパイルします。

    mov     eax, DWORD PTR [esp+24]      ; a
    cmp     eax, DWORD PTR [esp+28]      ; b
    jge     .L2                          ; jump if a is >= b
    ; Do something 1
.L2:

そして

    if (a <= b) {
        // Do something 2
    }

にコンパイルします。

    mov     eax, DWORD PTR [esp+24]      ; a
    cmp     eax, DWORD PTR [esp+28]      ; b
    jg      .L5                          ; jump if a is > b
    ; Do something 2
.L5:

つまり、両者の違いは jg に対して jge という命令があります。この2つは同じ時間がかかります。


異なるジャンプ命令で同じ時間がかかることを示すものは何もない、というコメントについて述べたいと思います。 これは少し難しいのですが、私が答えられることは以下の通りです。の中で インテル® インストラクション・セット・リファレンス というように、1つの共通命令でまとめられています。 Jcc (条件を満たした場合にジャンプ)。の下でも同じようにグループ化されています。 最適化リファレンスマニュアル は、付録Cに記載されています。レイテンシーとスループット

<ブロッククオート

レイテンシー - に必要なクロックサイクルの数。 実行コアがμopsを構成する全ての実行を完了するまでに 1つの命令。

<ブロッククオート

スループット - に必要なクロックサイクルの数。 イシューポートが同じ命令を受け入れることができるまで待機します。 また 多くの命令では、命令のスループットが レイテンシーよりかなり小さい

の値は Jcc があります。

      Latency   Throughput
Jcc     N/A        0.5

に以下の脚注を付けています。 Jcc :

  1. 条件付きジャンプ命令の選択は、3.4.1節「分岐予測の最適化」の推奨事項に基づいて、分岐の予測性を向上させる必要があります。分岐の予測に成功した場合のレイテンシは jcc は事実上ゼロです。

そのため、Intelのドキュメントでは、1つを扱うことはありません。 Jcc 命令と他の命令とで、何ら異なる点はありません。

命令を実装するための実際の回路を考えてみると、単純なAND/ORゲートで EFLAGS というように、条件を満たしているかどうかを判断します。2ビットをテストする命令が、1ビットをテストする命令よりも時間がかかる理由はありません(クロック周期よりもはるかに小さいゲートの伝搬遅延は無視します)。


Edit: 浮動小数点

これはx87浮動小数点にも当てはまります:(上記とほぼ同じコードですが double の代わりに int .)

        fld     QWORD PTR [esp+32]
        fld     QWORD PTR [esp+40]
        fucomip st, st(1)              ; Compare ST(0) and ST(1), and set CF, PF, ZF in EFLAGS
        fstp    st(0)
        seta    al                     ; Set al if above (CF=0 and ZF=0).
        test    al, al
        je      .L2
        ; Do something 1
.L2:

        fld     QWORD PTR [esp+32]
        fld     QWORD PTR [esp+40]
        fucomip st, st(1)              ; (same thing as above)
        fstp    st(0)
        setae   al                     ; Set al if above or equal (CF=0).
        test    al, al
        je      .L5
        ; Do something 2
.L5:
        leave
        ret