LLVM で JIT を作成する場合、C オペコード実装をどのように再利用しますか?
-
21-08-2019 - |
質問
llvm のチュートリアルと例では、コンパイラは次のような呼び出しを行うことで LLVM IR を出力します。
return Builder.CreateAdd(L, R, "addtmp");
しかし、多くのインタプリタは次のように書かれています。
switch (opcode) {
case ADD:
result = L + R;
break;
...
LLVM IR で各オペコードを再実装せずに、これらの各コード スニペットを抽出して LLVM で JIT を作成するにはどうすればよいでしょうか?
解決
まず、すべてのコード スニペットを取得し、それらを独自の関数にリファクタリングします。したがって、コードは次のようになります。
void addOpcode(uint32_t *result, uint32_t L, uint32_t R) {
*result = L + R;
}
switch (opcode) {
case ADD:
addOpcode(&result, L, R);
break;
....
さて、これを実行した後もインタープリタは実行されるはずです。次に、すべての新しい関数を取得して、独自のファイルに配置します。次に、llvm-gcc または Clang を使用してそのファイルをコンパイルし、ネイティブ コードを生成する代わりに、 「cpp」バックエンド (-march -cpp)。これにより、コンパイル単位のバイト コードをインスタンス化する C++ コードが生成されます。オプションを指定して特定の機能に限定することも可能です。おそらく「-cppgen module」を使用するとよいでしょう。
ここで、インタープリタ ループに戻り、元のコードを直接実行するのではなく、生成された C++ コードへの呼び出しを結合し、それをいくつかのオプティマイザとネイティブ コードジェネレータに渡します。JIT については感謝します ;-) この例は、次の vm_ops など、いくつかの LLVM プロジェクトで見ることができます。 llvm-lua.
所属していません StackOverflow