1. ホーム
  2. c++

[解決済み] なぜC++コンパイラはこの条件付きブール代入を無条件代入として最適化しないのでしょうか?

2022-05-14 01:07:19

疑問点

次のような関数を考えてみましょう。

void func(bool& flag)
{
    if(!flag) flag=true;
}

flag が有効なブール値を持っている場合、これは無条件にそれを true に設定するのと同じです。

void func(bool& flag)
{
    flag=true;
}

しかし、gccもclangもこのように最適化せず、以下のように -O3 最適化レベルでは以下のようになります。

_Z4funcRb:
.LFB0:
    .cfi_startproc
    cmp BYTE PTR [rdi], 0
    jne .L1
    mov BYTE PTR [rdi], 1
.L1:
    rep ret

私の質問は、コードが特殊すぎて最適化する気になれないだけなのか、それとも、以下のように、最適化が望ましくない正当な理由があるのか、ということです。 flag への参照ではなく volatile ? 唯一の理由は flag が何らかの形で非 true -または false の値を読み込む時点で未定義の動作にならないようにする必要がありますが、これが可能かどうかはわかりません。

どのように解決するのですか?

により、プログラムのパフォーマンスに悪影響を与える可能性があります。 キャッシュコヒーレンス を考慮する必要があります。に書き込むと flag その都度 func() が呼び出されるたびに、そのキャッシュラインを汚してしまいます。これは、書き込まれた値が、書き込む前に宛先アドレスで見つかったビットと正確に一致するかどうかに関係なく起こります。


EDIT

hvd は、別の 良い理由 を提示しました。それは提案された最適化に対してより説得力のある議論です。なぜなら、私の (元の) 回答がパフォーマンスの側面のみを扱ったのに対し、未定義の動作になる可能性があるからです。

もう少し考えた後、なぜコンパイラーは、変換が特定のコンテキストにとって安全であることを証明できない限り、無条件の書き込みを導入することを強く禁止されるべきなのか、もう 1 つの例を提案することができます。このコードを考えてみてください。

const bool foo = true;

int main()
{
    func(const_cast<bool&>(foo));
}

無条件に書き込むと func() において、これは間違いなく未定義の動作を引き起こします (読み取り専用メモリへの書き込みは、書き込みの効果がそうでなくても no-op であったとしても、プログラムを終了させます)。