Tutorial 続き(2)

前回、LLVM tutorial の例は main がないので実行できない、と書いた。が、正確には「llvm-as, lliを使っては実行できない」と書くべきであった。
LLVM の ExecutionEngine を使うと、C++ から関数単位で実行できるので、main はなくてもよい。

結局何がやれたかというと、「C++ で、実行時に LLVM の関数を生成して、それを実行できた」ということ。今は LLVM の関数は完全にC++のプログラムの中に静的に書いているだけなので面白くも何ともないが、これを外部から何かデータを受け取って、解釈し、LLVM の関数を生成してやるようにすれば、、。

Makefile:

tut2_exe: tut2_exe.cpp
	c++ -g tut2_exe.cpp `/usr/local/bin/llvm-config --cxxflags --ldflags --libs core --libs jit --libs linker --libs interpreter` -o tut2_exe

tut2_exe.cpp:

#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/PassManager.h"
#include "llvm/CallingConv.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ModuleProvider.h"

#include "llvm/Transforms/Scalar.h"

using namespace llvm;

Module* makeLLVMModule();

int main(int argc, char**argv) {
  Module* Mod = makeLLVMModule();
  if (argc != 4) {
    cerr << "Usage: tut2 x y z\n";
    return 1;
  }

  verifyModule(*Mod, PrintMessageAction);

  // Now we create the JIT.
  ExistingModuleProvider* MP = new ExistingModuleProvider(Mod);
  ExecutionEngine* EE = ExecutionEngine::create(MP, false);

  outs() << "We just constructed this LLVM module:\n\n" << *Mod;
  outs().flush();
  // get mul_add fuction
  Constant* c = Mod->getOrInsertFunction("mul_add",
                                         IntegerType::get(32),
                                         IntegerType::get(32),
                                         IntegerType::get(32),
                                         IntegerType::get(32),
                                         NULL);
  Function* mul_add = cast<Function>(c);

  int x = atoi(argv[1]);
  int y = atoi(argv[2]);
  int z = atoi(argv[3]);

  std::vector<GenericValue> args1(3);
  args1[0].IntVal = APInt(32, x);
  args1[1].IntVal = APInt(32, y);
  args1[2].IntVal = APInt(32, z);

  GenericValue gv = EE->runFunction(mul_add, args1);
  outs() << "Result: " << gv.IntVal << "\n";
  delete Mod;
  return 0;
}

Module* makeLLVMModule() {
  Module* mod = new Module("tut2");
  Constant* c = mod->getOrInsertFunction("mul_add",
                                         /*ret type*/
                                         IntegerType::get(32),
                                         /*args*/
                                         IntegerType::get(32),
                                         IntegerType::get(32),
                                         IntegerType::get(32),
                                         /*varargs terminated with null*/
                                         NULL);
  Function* mul_add = cast<Function>(c);
  mul_add->setCallingConv(CallingConv::C);
  Function::arg_iterator args = mul_add->arg_begin();
  Value* x = args++;
  x->setName("x");
  Value* y = args++;
  y->setName("y");
  Value* z = args++;
  z->setName("z");

  BasicBlock* block = BasicBlock::Create("entry", mul_add);
  IRBuilder<> builder(block);

  Value* tmp = builder.CreateBinOp(Instruction::Mul, x, y, "tmp");
  Value* tmp2 = builder.CreateBinOp(Instruction::Add, tmp, z, "tmp2");
  builder.CreateRet(tmp2);

  return mod;
}

syoyo さんの勉強会資料、http://llvm.org/devmtg/2008-08-23/llvmjittut.pdf の意味がやっと分かるようになったよ。