1. ホーム
  2. c++

[解決済み] コンパイラ/最適化ツールで高速なプログラムを作るためのコーディングプラクティス

2022-09-13 17:08:13

質問

何年も前、Cコンパイラは特に賢いものではありませんでした。 回避策として K&R が発明したのが レジスタ キーワードを発明し、コンパイラにこの変数を内部レジスタに保持するのは良いアイデアかもしれないと示唆しました。 また、より良いコードを生成するために、三次演算子も作りました。

時が経つにつれて、コンパイラは成熟していきました。 コンパイラは非常に賢くなり、フロー分析によって、レジスタに保持する値について、あなたができることよりも優れた判断を下すことができるようになりました。 レジスタのキーワードは重要ではなくなりました。

FORTRANはある種の操作ではCより速いことがありますが、これは以下の理由によります。 エイリアス の問題のためです。 理論的には、注意深くコーディングすることで、この制限を回避し、オプティマイザーがより高速なコードを生成できるようにすることができます。

コンパイラやオプティマイザがより高速なコードを生成できるようにするために、どのようなコーディング手法がありますか?

  • 使用しているプラットフォームとコンパイラーを特定すると、ありがたいです。
  • なぜその手法がうまくいくように見えるのでしょうか。
  • サンプルコードを推奨します。

以下は 関連質問

[編集]をクリックします。 この質問は、プロファイリング、最適化のための全体的なプロセスに関するものではありません。 プログラムが正しく書かれ、完全な最適化でコンパイルされ、テストされ、実稼働に移されたと仮定してください。 あなたのコードには、オプティマイザが可能な限り最高の仕事をすることを妨げる構成があるかもしれません。 これらの禁止事項を取り除き、オプティマイザーがさらに高速なコードを生成できるようにするために、リファクタリングで何ができるでしょうか?

編集 オフセット関連リンク

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

出力引数ではなく、ローカル変数に書き込む! これはエイリアシングのスローダウンを回避するための大きな助けになります。たとえば、あなたのコードが次のような場合

void DoSomething(const Foo& foo1, const Foo* foo2, int numFoo, Foo& barOut)
{
    for (int i=0; i<numFoo, i++)
    {
         barOut.munge(foo1, foo2[i]);
    }
}

の場合、コンパイラはfoo1 != barOutを知らないので、ループのたびにfoo1を再読み込みしなければなりません。また、barOutへの書き込みが終了するまでfoo2[i]を読み込むことができません。制限付きポインターをいじり始めることもできますが、これを実行することは同じくらい効果的です(そしてはるかに明確です)。

void DoSomethingFaster(const Foo& foo1, const Foo* foo2, int numFoo, Foo& barOut)
{
    Foo barTemp = barOut;
    for (int i=0; i<numFoo, i++)
    {
         barTemp.munge(foo1, foo2[i]);
    }
    barOut = barTemp;
}

馬鹿げているように聞こえますが、ローカル変数はどの引数ともメモリ上で重なることはありえないので、コンパイラはよりスマートに処理することができるのです。これは、恐ろしいロードヒットストア (このスレッドで Francis Boivin によって言及された) を回避するのを助けることができます。