web-dev-qa-db-ja.com

コンパイラーはローカルvolatileを定数フォールドできますか?

この単純なコードを考えてみましょう:

void g();

void foo()
{
    volatile bool x = false;
    if (x)
        g();
}

https://godbolt.org/z/I2kBY7

gccclanggへの潜在的な呼び出しを最適化しないことがわかります。これは私の理解では正しいです。抽象的なマシンは、volatile変数がいつでも変更される可能性があると想定しています(たとえば、ハードウェアにマップされているため)。したがって、false初期化をifチェックは間違っているでしょう。

ただし、MSVCはgへの呼び出しを完全に排除します(ただし、volatileへの読み取りと書き込みを維持します!)。これは標準に準拠した動作ですか?


背景:デバッグ出力をオンザフライでオン/オフできるようにするために、この種のコンストラクトを時々使用します:コンパイラは常にメモリから値を読み取る必要があるため、デバッグ中に変数/メモリを変更すると、それに応じて制御フローが変更されます。 MSVC出力は値を再読み取りしますが、それを無視します(たぶん、定数の折りたたみやデッドコードの除去のため)、これはもちろん、ここでの私の意図を無効にします。


編集:

  • volatileへの読み取りと書き込みの排除については、ここで説明します。 コンパイラーがローカルの揮発性変数を最適化することを許可されていますか? (Nathanに感謝します!)これらの読み取りと書き込みが必ず発生することが標準で十分に明確であると思います。しかし、その議論は、コンパイラがそれらの読み取りの結果を当然のこととして受け取り、それに基づいて最適化することが合法かどうかをカバーしていません。これは標準では nder-/unspecified であると思いますが、誰かが私を間違っていると証明した場合は幸いです。

  • もちろん、xを非ローカル変数にして、問題を回避することもできます。この質問は、好奇心から外れています。

25
Max Langhof

[intro.execution](段落番号は異なります)を使用してMSVCの動作を説明できると思います。

自動ストレージ期間を持つ各オブジェクトのインスタンスは、そのブロックへの各エントリに関連付けられています。このようなオブジェクトは存在し、ブロックの実行中およびブロックの一時停止中に最後に保存された値を保持 ...

この規格では、揮発性のglvalueを介した読み取りの削除は許可されていませんが、上記の段落は、値falseを予測できると解釈できます。


ところで、C標準(N1570 6.2.4/2)は、

オブジェクトは存在し、一定のアドレスを持ち、その存続期間を通して最後に格納された値を保持します。34


34)揮発性オブジェクトの場合、最後のストアはプログラムで明示的である必要はありません。

Cメモリ/オブジェクトモデルの自動ストレージ期間を持つオブジェクトへの非明示的なストアがあるかどうかは不明です。

2
Language Lawyer

TL; DRコンパイラーは、揮発性アクセスごとに必要なことをすべて実行できます。しかし、ドキュメントはあなたに伝えなければなりません。


この規格では、プログラムが許可する「揮発性アクセス」およびその他の「観察可能な動作」(「副作用」を介して達成される)のシーケンスを、実装が「as-if」ルールに従って尊重する必要があると定義しています。

しかし、標準は言う(私の太字の強調):

草案、プログラミング言語C++の標準
ドキュメント番号:N4659
日付:2017-03-21

§10.1.7.1 cv-qualifiers

5 揮発性glvalueを介したアクセスのセマンティクスは実装定義です。 […]

同様に、インタラクティブデバイス(太字を強調)の場合:

§4.6プログラムの実行

5整形式プログラムを実行する適合実装は、同じプログラムと同じ入力を持つ抽象マシンの対応するインスタンスの可能な実行の1つと同じ観察可能な動作を生成するものとします。 [...]

7適合実装の最小要件は次のとおりです。

(7.1)—揮発性のglvalueを介したアクセスは、抽象マシンのルールに従って厳密に評価されます。
(7.2)—プログラムの終了時に、ファイルに書き込まれたすべてのデータは、抽象的なセマンティクスに従ってプログラムを実行した場合に生じる可能性のある結果の1つと同一でなければなりません。
(7.3)—対話型デバイスの入力と出力のダイナミクスは、プログラムが入力を待つ前にプロンプ​​ト出力が実際に配信されるような方法で行われるものとします。 インタラクティブデバイスを構成するものは実装定義です。

これらはまとめて、プログラムの観察可能な動作と呼ばれます。 [...]

(とにかくプログラムに対して生成される特定のコードは、規格では指定されていません。)

したがって、規格では、揮発性アクセスは抽象的なマシンの副作用の抽象的なシーケンスと、その結果として一部のコード(多分)が定義する観察可能な動作から除外できないと述べていますが、オブジェクトコードや実際の世界には何も反映されません。コンパイラーのドキュメントに揮発性アクセスの構成要素が示されていない限り、動作。インタラクティブデバイス用の同上。

揮発性vis対visに関心がある場合は、抽象マシンの副作用の抽象シーケンスおよび/または一部のコードが定義する可能性のある結果として発生する可能性のある動作次にそう言う。しかし、生成される対応するオブジェクトコードに興味がある場合は、コンパイラとコンパイルのコンテキストでそれを解釈する必要があります。

Chronically人々は、揮発性アクセスの場合、抽象的なマシンの評価/読み取りが実装された読み取りを引き起こし、抽象的なマシンの割り当て/書き込みが実装された書き込みを引き起こすと誤って信じています。 この信念が存在しないため、実装のドキュメントにそういう根拠はありません。実装が実際に「揮発性アクセス」時に何かを実行すると述べている場合、人々は、何か、おそらく特定のオブジェクトコードの生成を期待することは正当化されます。

2
philipxy