同じレジスタに割り当てられませんでした。これは最適な割り当てでしょうか。使用している点が問題です。これらのレジスタは、呼び出された側が保存しておくべきレジスタです。呼び出された関数では、開始時と終了時にこのレジスタの値を同じにしておかなければなりません。レジスタの値をスタックにプッシュする命令を生成し、関数の終了時にそれらをスタックからポップする命令を生成する必要があります。ように、呼び出し側が保存しておくべきレジスタを使用すると、どちらのプラットフォームでもこの処理を回避できます。レジスタ割り当てアルゴリズムのこのような欠陥は、関数のインライン化によって軽減できる場合があります。ほかにも、実行されないコードの削除、共通部分式の削除、命令スケジューリングなどの最適化を行うことで、レジスタが効率よく割り当られる可能性が高いコードにすることができます。変数の有効期間が重ならないのは実際によくあることなので、そのような変数すべてを同じレジスタに割り当てれば非常に経済的です。変数を格納するレジスタが不足するとどうなるでしょう。その場合は、変数をメモリに吐き出さなければなりません。これを巧みに行う方法があります。変数をすべてスタック上の同じ場所に吐き出します。よってサポートされます。ヒット率が向上して、パフォーマンスが高まる場合があります。残念ながら、言うほど簡単ではありません。最適なレジスタ割り当てを実現できそうですが、実際には、次のようにこれを実現できない理由がたくさんあります。使用可能なレジスタには複雑な制限事項があり、自由に使用できません。各命令では、オペランドに使用できるレジスタに制限があります。そのため、命令を使用する場合には、その命令に必要なオペランドに指定できるレジスタを使用しなければなりません。一部の命令の結果が事前定義されたレジスタに格納されます。命令では、このレジスタに格納された値は揮発性があると想定されます。同じ計算を実行する場合でも、さらに効率の高いレジスタ割り当てが可能な別の命令シーケンスが存在することもあります。命令選択、命令スケジューリング、およびレジスタ割り当ての問題は複雑に絡み合っています。すべての変数がプリミティブ型とは限りません。自動変数の構造体や配列も珍しくありません。このような変数を直接レジスタに割り当てることは考えられませんが、個別に割り当てることはできます。現在のコンパイラではまだ適切に処理されません。関数の呼び出し規約によって、一部の引数に固定割り当てが行われ、他の引数はレジスタの可用性に関係なく割り当ての対象ではなくなります。これについては後ほど解説します。呼び出し側が保存すべきレジスタと呼び出された側が保存すべきレジスタという概念が状況を複雑にしています。変数のアドレスを使用するコードがある場合、アドレスが設定される場所に変数を格納する方が適切です。レジスタにはアドレスがないため、変数はレジスタが使用可能かどうかにかかわらずメモリに格納されることになります。このように説明すると、現在のコンパイラが行うレジスタ割り当てはひどいものだと思われるかもしれません。うまく割り当てが行われ、非常にゆっくりとしてペースですが向上しています。コードを作成しているところを想像してみてください。これらをすべて考慮して記述しているでしょうか。有効にすると、コンパイラがより適切な割り当てを見つけるのに役立ちます。コードには組み込まれません。特定の関数が出力の実行可能ファイルからエクスポートされるように定義されていない場合、コンパイラはその呼び出し規約に反してパフォーマンスを向上できます。このようなことが可能なのは、コンパイラが関数の呼び出しサイトをすべて特定できるためです。呼び出し規約に関係なく関数のすべての引数をレジスタ割り当ての対象にすることで、これを活用しています。レジスタ割り当てを改善できない場合でも、コンパイラは、より効率的な連携を実現するために、パラメーターの並び替えや、未使用のパラメーターの削除などを試みます。ファイルの関数への呼び出しサイトが含まれる場合、関数のアドレスが利用されている場合、またはアドレスが仮想の場合、コンパイラは呼び出し規約を最適化できません。指定しないと、既定ですべての関数とメソッドに外部リンケージが含まれます。そのため、コンパイラはこの手法を適用できません。ファイル内に限って、コンパイラはこの手法を適用できます。アーキテクチャをターゲットとする場合に重要です。効率的ではないためです。つの引数がレジスタを使って渡されるため、非常に効率的です。ターゲットとする場合にのみ実行されます。有効でも、エクスポートされた関数やメソッドでは、コンパイラが先述のすべての場合と同様に特定できない呼び出しサイトもあることから、そのような関数やメソッドの呼び出し規約に反することはできないことに注意してください。レジスタ割り当ての効果は、変数へのアクセス回数を推定する際の正確さによって異なります。ほとんどの関数は条件付きステートメントを含んでおり、これが推定の正確さを損ないます。この推定の微調整には、ガイド付き最適化のプロファイルを使用できます。場合、コンパイラは手続き間レジスタ割り当てを行います。コンパイラは、関数チェーン内で宣言された変数を考慮し、各関数のコードによって課される制約に応じて適切な割り当てを見つけようと試みます。関数全体を意味します)。キーワードが用意されており、プログラマはこれを使用して、レジスタに格納する変数に関するヒントをコンパイラに提供できます。コンパイラは、簡単なレジスタ割り当てが可能でした。ビット浮動小数点レジスタを備えていました)。コンパイラの記述が簡単になります。キーワードが用意されました。レジスタ割り当てアルゴリズムが数多くの実装されたため、このキーワードの存在は今日までにさまざまな混乱を生んでいます。このようなキーワードは用意されていません。おいてはその限りではありません。このキーワードはベンチマークの記述においてのみ使用することをお勧めします。コンパイラは、できる限りこのキーワードを考慮します。レジスタ変数のアドレスを使用できません。クラスに反して、変数をレジスタ以外のアドレス指定可能な場所に格納する必要があります。(生成されるコードの一部がネイティブの場合でも、当然ながらレジスタ割り当てはそのコードに対して行われます)。ランタイムが実行されるまで先送りにされます。優れたレジスタ割り当てアルゴリズムを実装しています。命令スケジューリングレジスタ割り当てと命令スケジューリングは、コンパイラがバイナリを生成する前に行う最後の最適化です。単純な命令を除くすべての命令が、複数のステージを経て実行されます。ユニットによって処理されます。これらのユニットすべてをできる限り活用するために、プロセッサは複数の命令をパイプライン形式で発行し、さまざまな命令がさまざまなステージで同時実行されるようにしています。これにより、大幅にパフォーマンスが向上する場合があります。つの実行準備が間に合わないと、パイプライン全体が停止します。操作の完了の待機など、さまざまです。命令スケジューリングは、この問題を軽減する手法です。コンパイラが関数の命令を分析し、パイプラインを停止する可能性のある命令を判断します。その後、予想される停止のコストを最小限に抑えると同時にプログラムの正常性を維持できる別の命令の順序を探します。これを、命令の順序変更と呼びます。ストリームを予測して、そのオペランドと必要な機能単位の実行に使用できる命令を発行します。結果として、プログラムは元の順序とは異なる順序で実行されます。他の理由で、コンパイラが特定の命令の順序を変更することもあります。インターチェンジと呼びます)。回にして、レジスタからメモリに吐き出されるコストを削減するものです。ミスを削減する例もあります。プログラマとして、コンパイラやプロセッサが行う命令スケジューリングのしくみを知っておく必要はありません。この手法の効果とその処理方法については知っておいた方がよいでしょう。命令スケジューリングではほとんどのプログラムの正常性が維持されますが、直感的ではない意外な結果が生成されることがあります。命令スケジューリングによってコンパイラが不適切なコードを生成する例を示しています。どちらに設定してもかまいません。リストが生成されるようにします。関数の実行時間を計測します。時間計測関数の呼び出しでラップします。値の差異を計算して、関数の実行にかかった時間を推定します。このコードの目的は、コードのパフォーマンスを測定する最適な方法を示すことではなく、命令スケジューリングの危険性を示すことにある点に注意してください。コードを簡単に理解できます。この移動によって、測定値は完全に間違ったものになります。この順序変更は、準拠する実装の標準によって課される最低限の要件に反するものではないため、適切なものです。コンパイラはこのような順序変更を行うのでしょう。(実際、コンパイラにとって、これらの関数は互いにまったく影響を及ぼしません)。キャッシュにその命令に必要なデータの一部が含まれている可能性があります。呼び出すと上書きされる可能性があるため、それに応じてコンパイラがコードの順序を変更しました。コンパイラには、命令スケジューリングだけを無効にし、他の最適化は有効にしておくスイッチはありません。関数がインライン化されている場合に動的実行を行うと発生することもあります。目の呼び出しの実行開始を決めてしまう可能性があります。コンパイラと同じように、大部分のプロセッサでは、開発者が動的実行を無効にすることはできません。公正を期すために補足すると、動的実行によってこの問題が発生することはほとんどありません。いずれにせよ、この問題が発生したかどうかは、どのようにしてわかるでしょう。コンパイラは、この最適化を極めて慎重に実行します。移動しないことがわかりました。呼び出されている任意の関数からインポートした関数を、関数呼び出しの場所とターゲットの場所の間で呼び出す。目の呼び出しを移動しません。目の呼び出しの間で呼び出す。0;}呼び出されている任意の関数のグローバル変数または静的変数に、関数呼び出しの場所とターゲットの場所の間でアクセスする。これは、変数が読み取られているか書き込まれているかを保持します。目の呼び出しを移動しないようにするコードです。コンパイラが命令の順序変更を行わない状況はほかにもあります。この規則に従っていますが、それ以上に保守的に、コードのコンパイルにかかる時間を削減します。インポートした関数には副作用がある場合があります。関数と揮発性変数へのアクセスには副作用があります。キーワードで変数を修飾すると、レジスタ割り当てと命令の順序変更の両方に影響します。(ほとんどの命令は一部のオペランドをレジスタに格納する必要があるため、変数はレジスタに読み込まれます。その目的はその変数を使用する一部の命令の実行のみです)。アクセスが発生します。次に、揮発性変数への書き込みには解放のセマンティクスがあります。アクセスは事前に行われます。目に、揮発性変数からの読み取りには取得のセマンティクスがあります。アクセスは事後に行われます。スイッチを指定した場合だけです。スイッチを指定すると、コンパイラは言語の標準に従います。その場合、このキーワードへの準拠は一切保証されません。既定で指定されています。