2011-06-21 17 views
22

高度なコンパイル言語用のバイトコードを作成しています。プロファイリングと最適化を少し行った後、現在使用しているswitch文が現在の最大パフォーマンスオーバーヘッドになっていることが明らかになりましたバイトコードの場合にジャンプします。ラベルのアドレス(MSVC)

私たちは、通常はオンになっている命令IDではなく、各ケースラベルのアドレスを取り出し、バイトコード自体のストリームに格納することを検討しました。これを行うと、ジャンプテーブルをスキップして、現在実行中の命令のコードの場所に直接ジャンプすることができます。これはGCCでうまく動作しますが、MSVCはこのような機能をサポートしていないようです。

インラインアセンブリを使用してラベルのアドレスを取得(および移動)しようとしましたが、動作しますが、インラインアセンブリを使用すると、MSVCオプティマイザによって関数全体が回避されます。

オプティマイザがコードに対して実行できるようにする方法はありますか?残念ながら、インラインアセンブリでも別の関数のラベルを参照する方法がないため、インラインアセンブリをラベルが作成された関数以外の別の関数に抽出することはできません。どのような考えやアイデアですか?あなたのご意見は大変ありがとうございます。

+3

関数ポインタを試しましたか? –

+0

バイトコードのラベルのアドレスではなく、関数のアドレスを入れてみましょうか?次に、各命令IDに対して1つの機能があります。 fetch-executeループが大規模なfunction-with-labelsに含まれていない限り –

+0

私はそれぞれのケースで関数を使用し、ラベルアドレスの代わりに関数ポインタを使用するとうまくいくでしょう。しかし、関数呼び出しオーバーヘッドが非常に大きいので、たとえ関数が簡単であっても(引数なし、返りません)、パフォーマンスの向上は無効になるような気がします。私はそれを試してみるだろうと、投稿していただきありがとうございます。 – Trevor

答えて

15

MSVCでこれを行うための唯一の方法は、(基本的にはx64のためにあなたをbuggers)インラインアセンブリを使用することです:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
case_1: 
    void* p; 
    __asm{ mov [p],offset case_1 } 
    printf("0x%p\n",p); 
    return 0; 
} 

あなたはこのような何かを行う上で計画している場合は、その最良の方法は、書くことだろうアセンブリー内のインタプリタ全体がリンカを介してメインバイナリにリンクされます(これはLuaJITが行ったものですが、JITコードを実行していない場合、VMが非常に高速である主な理由です)。

LuaJIT is open-sourceだから、そのルートに行くといくつかのヒントが表示されることがあります。あるいは、あなたがそのソースを調べたいと思うかもしれません(作成者がthe principleを使用しています)、MSVCビルドがあれば、それをどのように達成したかを見ることができます。そうでなければGCCに悩まされています(isn ' t悪いこと、それはすべての主要なプラットフォームで動作します)。

3

実際のコードをケースラベルの代わりに関数に移動するだけのようです。バイトコードは簡単にダイレクトコールに変換できます。私。バイトコード1はCALL BC1に変換されます。直接呼び出しを生成しているので、関数ポインタのオーバーヘッドはありません。ほとんどのCPUのパイプラインは、そのような無条件の直接分岐に従うことができます。

結果として、各バイトコードの実際の実装が最適化され、バイトコードからマシンコードへの変換は些細な1:1変換です。 CALLはそれぞれ5バイト(x86-32と仮定している)なので、少しのコード拡張がありますが、これは大きな問題ではありません。

9

Windowsで構築するためにErlangが行うことを見てください。彼らはビルドのほとんどのためにMSVCを使い、1つのファイルに対してGCCを使って値としてのラベル拡張を利用します。結果として得られたオブジェクトコードは、MSVCリンカとの互換性を保つためにハッキングされます。

http://www.erlang.org/doc/installation_guide/INSTALL-WIN32.html

関連する問題