2

タイトルが少し不明確かもしれないので、ここに説明があります:

問題:

a = b + c * d;

私の実装では、これら2つの「指示」に解決されます

mul(c, d, temp)
add(b, temp, a)

私は現在、一時オブジェクトを使用して一時値を格納しています。これにより、一時値をRAMに格納し、必要なときに再度フェッチする必要があります。どちらも実際には必要ではなく、パフォーマンスが低下します。

私はVMをC++で実装しているので、私の質問は、一時的な値のメインメモリへの保存を回避し、実際のCPUレジスタに保持するための移植可能な方法があるかどうかです。

キーワードを使用していくつかのテストを行いましregisterたが、パフォーマンスが向上していないことから判断すると、コンパイラはそれを無視していると思います。

最後の手段として、プラットフォーム固有のアセンブリに進んでいきますが、この件についてはほとんど暗闇に包まれているため、これが唯一の可能な方法である場合は、適切な情報を歓迎します。私が示したこの例は基本的なものであり、多くの一時オブジェクトが必要になる状況に遭遇する可能性が高いことを私は理解しています。その場合、使用および使用するレジスタの量を決定する方法が必要です。残りのメモリストレージ...

おそらく、レジスタストレージを要求する方法があり、コンパイラがレジスタを「使い果たした」場合、一時的なものをスタックに自動的にプッシュしますか?私がアセンブリに精通している限り、あなたは特定のレジスタをその名前で「アドレス指定」しますが、コンパイラが潜在的なレジスタ使用の競合をどのように正確に処理するかはわかりません...

4

4 に答える 4

3

とまったく同じようにinline、コンパイラへの推奨事項registerにすぎません。それに続く場合とそうでない場合があり、「通常の」変数を変数として保存する場合と保存しない場合があります。register

C++ 標準は次のように述べています ( 7.1.1、段落 3 ):

レジスタ指定子は、そのように宣言された変数が頻繁に使用されるという実装へのヒントです。[ 注: ヒントは無視できます。ほとんどの実装では、変数のアドレスが取得された場合は無視されます。この使用は非推奨です (D.2 を参照)。— エンドノート]

このような低レベルの最適化を行う前に、適切な分析を実行してシステムのボトルネックを特定し、実際に必要かどうかを確認する必要があります。

また、あなたがプロの asm プログラマーでない場合、コンパイラーはあなたよりもコードを最適化すると確信できます (誰にとっても不快ではなく、一般的な意味での意味です)。

于 2012-08-09T09:17:37.460 に答える
2

C では、関数呼び出し間で値をレジスターに保持するかどうかを制御する方法は提供されていません。

あなたは間違ったことを最適化しようとしています。文字列の解析とエミュレーションの実行に必要な操作には、バイトの読み込み、バイトの比較とテーブルでの検索、比較結果に基づく分岐、ルーチン引数のスタックへのプッシュ、からの復帰など、非常に多くの低レベルのプロセッサ操作が含まれます。ルーチン、シンボル テーブルでの識別子の検索など。メモリからの値の単純なロードは、このプロセスのごく一部です。

解析とエミュレーションを分離して、解析によって仮想マシン言語のコードが生成されたと仮定しても、そのコードを実行するために必要な操作には、メモリから命令のバイトをロードする、それらのバイトをデコードするなど、多くの操作が含まれます。デコードされた命令を実行するコードへの分岐など。

C や C++ などの高水準言語で記述する場合、すべてのエミュレーション コードを 1 つのコンパイル ユニット (1 つのソース ファイルとそれに含まれるヘッダー) で、場合によっては 1 つのルーチン内で記述することをお勧めします。コンパイラのオプティマイザがすべてを認識し、すべてを最適化できること。その場合、命令の読み取り、デコード、および実行を行うメイン ループがある場合、コンパイラは、一時値の値が保持され、反復から反復まで再利用されることを確認する可能性があるため、コンパイラはこれらの一時値をレジスタに格納することを決定する可能性があります。 .

ただし、仮想マシンのエミュレーションは大規模なタスクであるため、コードには非常に多くのオブジェクトが含まれる可能性があります。これには、エミュレートされたマシンのレジスタごとに少なくとも 1 つのオブジェクト (配列要素の可能性が高い) と、マシン状態の他の側面のオブジェクトと、命令のデコードとエミュレーション コードへのディスパッチに使用されるオブジェクトがあります。教室での演習にのみ適した、可能な限り最も単純な仮想マシン エミュレーターでは、ほとんどのオブジェクトがプロセッサ レジスタに収まるほどの数のオブジェクトしかない場合があります。しかし、少し現実的な仮想マシン エミュレーターには非常に多くのオブジェクトがあるため、プロセッサ レジスタに保持できるオブジェクトはほとんどありません。この場合、最適化をオプティマイザに任せて、自分でやろうとしない方がよいでしょう。

于 2012-08-09T10:46:38.297 に答える
2

とにかく、レジスターはあなたが思っているようには機能しません。名前R2は実際には住所と同じ2です。確かに、x86 アセンブリには などの凝った名前がありますECXが、それでもレジスタ 2 です。

また、それらはしばしば物理的ではありません。仮想メモリと同様に、レジスタ名は一時的なものです。最近のプロセッサは、レジスタ値を RAM に保存するのに時間がかかる場合があります。レジスターをリサイクルする前にこれが完了するのを待つこともできますが、より迅速な解決策は、名前をリサイクルして、書き込みが完了するまで古い (現在は名前が付けられていない) レジスターに値を保持させることです。これは、レジスタアドレスの数が物理レジスタの数よりも少なくなる可能性があることを意味します。(もう 1 つの利点は、より新しく高価な CPU がより多くのレジスタを持ち、ISA と互換性があることです)。

そうは言っても、あなたの問題は古典的に解決されます-Fused FMAMultiply and Add。ソース コードはmuladdではなく に変換する必要がありmul_add(c,d,b,a)ます。これにより、C++ コンパイラが FMA 命令を発行できるようになり、一時的な必要性が完全にバイパスされます。

于 2012-08-09T09:55:51.653 に答える