2010年03月31日

LLVM の JIT を使ってみる (3)

LLVM の JIT API を使うと、関数を返す(作る)関数が書けます。

肝は ExecutionEngine の getPointerToFunction() API で、JIT 済みの関数(コード)へのポインタを取得できます。



HowToUseJIT.cpp で、ExecutionEngine を作り終わった後に、

  // Now we create the JIT.
  ExecutionEngine* EE = EngineBuilder(M).create();

以下のようなコードを追加してみると、JIT 済みの関数を関数ポインタに受けて、そのまま通常の関数のように使用できることが確認できます。

  int (*foo_ptr)(int);
  int result;

  foo_ptr = (int (*)(int))EE->getPointerToFunction(Add1F);
  result = foo_ptr(123); // 124

後は応用です。以下には必要な部分しか書いてませんが、HowToUseJIT プロジェクトと同じヘッダと設定でビルドできるはずです。

typedef int (*addn_func_t)(int);

addn_func_t create_func(ExecutionEngine& ee, Module& mod, int n, Function **f)
{
  /* 無名関数を作ります。

     [](int x) -> int // C++0x syntax
     {
         return x + n; // n は定数
     }
  */
  LLVMContext& ctx = mod.getContext();
  *f = cast<Function>(mod.getOrInsertFunction("", Type::getInt32Ty(ctx),
                                                  Type::getInt32Ty(ctx),
                                                  (Type *)0));
  BasicBlock *bb = BasicBlock::Create(ctx, "", *f);
  Value *v = ConstantInt::get(Type::getInt32Ty(ctx), n);
  Argument *arg = (*f)->arg_begin();
  Instruction *add = BinaryOperator::CreateAdd(arg, v, "", bb);
  ReturnInst::Create(ctx, add, bb);
  
  return (addn_func_t)ee.getPointerToFunction(*f);
}

int main()
{
  InitializeNativeTarget();

  LLVMContext ctx;
  Module* mod = new Module("", ctx);
  ExecutionEngine* ee = EngineBuilder(mod).create();

  int n = 123;
  Function *fp;

  /* 関数(コード)を作る */
  addn_func_t f = create_func(*ee, *mod, n, &fp);
  int x = 222;
  /* 関数を呼び出す */
  int res = f(x);
  printf("f(%d) = %d\n", x, res);
  /* 関数を削除 */
  ee->freeMachineCodeForFunction(fp);

  delete ee;
  llvm_shutdown();
  return 0;    
}

関数ポインタを返すようにしてみたのですが、どのみち C++ は GC が無いので、モジュール内の関数へのポインタも取っておかないと、バッファなどの後始末ができなくなるので、微妙なインタフェースになってしまいました。

今回はコードだけでしたが、次回はデータやローカル変数などを見てみたいと思います。



トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード