最近、私はインタビューで Q に続いて尋ねられました: レジスタ変数が格納される場所 (RAM またはレジスタ) を実際に決定するのは誰ですか?
私はグーグルで検索しました。コンパイラが決定した答えです。しかし、コンパイラはどのように決定できますか? 私の理解では、実行時に決定する必要があります。
別のマシンでプログラムをコンパイルして実行した場合、コンパイラはレジスタ ストレージ クラスの値を格納する場所をどのように決定できますか。
最近、私はインタビューで Q に続いて尋ねられました: レジスタ変数が格納される場所 (RAM またはレジスタ) を実際に決定するのは誰ですか?
私はグーグルで検索しました。コンパイラが決定した答えです。しかし、コンパイラはどのように決定できますか? 私の理解では、実行時に決定する必要があります。
別のマシンでプログラムをコンパイルして実行した場合、コンパイラはレジスタ ストレージ クラスの値を格納する場所をどのように決定できますか。
registerストレージ クラス指定子は、変数へのアクセスを「できるだけ速く」する必要があるというコンパイラへのヒントであり、(レジスタ アーキテクチャでは) そのストレージをレジスタに割り当てる必要があることを意味します。これにより、変数のアドレスを取得するなど、いくつかのことが禁止されます。レジスタにはアドレスがありません。ただし、コンパイラはこのヒントを自由に無視できます (§6.7.1¶5):
ストレージ クラス指定子を使用したオブジェクトの識別子の宣言は、オブジェクト
registerへのアクセスが可能な限り高速であることを示唆しています。そのような提案が有効である範囲は、実装によって定義されます。
コードをコンパイルするとき、コンパイラは、ローカル変数と算術演算を CPU レジスタとスタック メモリの演算にマップする方法を選択する必要があります。これをレジスタ割り当てと呼びます。これらの決定はコンパイル時に行われ、関数のコンパイル済みコードに組み込まれます。
私たちが言ったことを正確に実行し、何も最適化しない非常に単純なコンパイラがあるとします。このコードを与えると:
int x;
x = 2;
x += 5;
次に、x86 マシンで次の出力が表示されることを期待できます。
sub esp, 4 ; allocate stack space for an integer
mov dword [esp], 2
add dword [esp], 5
しかし、次のように書くと:
register int x;
x = 2;
x += 5;
次に、次のことが期待できます。
mov eax, 2
add eax, 5
後者は、メモリ アクセスよりもレジスタ アクセスを優先するため、より効率的です。実際には、最新のコンパイラには、このストレージ クラス指定子を不要にするインテリジェントなレジスタ割り当てアルゴリズムがあります。
コンパイル時にコンパイラによっていくつかのタイプの最適化が行われ、これらの最適化に応じて、要求が許可または拒否されます。
コンパイルの最後の 3 番目のフェーズ --- 中間コードの生成は、中間の 3 アドレス (オペコード) ベースのコーディングを生成する基礎を保持します。これは、コンパイラ最適化の最後の 2 番目のフェーズでさらに最適化されます。コンパイラの最後のフェーズ ---
target code generationレジスタ ストレージ クラス変数にレジスタが付与されるかどうかが保証されます。
変数へのレジスタアクセスを許可する要求はプログラムによって行われますが、最終的に、レジスタ内の変数のメモリの割り当てを決定するのはコンパイラです:-
CPU 内のレジスタの可用性。
より安定した最適化など