tags:

views:

323

answers:

3

It is probably something basic because I am just starting to learn LLVM..

The following creates a factorial function and tries to git and execute it (I know the generated func is correct because I was able to static compile and execute it). But I get segmentation fault upon execution of the function (in EE->runFunction(TheF, Args))

#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/GenericValue.h"


using namespace llvm;


Module* makeLLVMModule() {
  // Module Construction
  LLVMContext& ctx = getGlobalContext();
  Module* mod = new Module("test", ctx);
  Constant* c = mod->getOrInsertFunction("fact64",
  /*ret type*/                           IntegerType::get(ctx,64),
                                         IntegerType::get(ctx,64),
  /*varargs terminated with null*/       NULL);

  Function* fact64 = cast<Function>(c);
  fact64->setCallingConv(CallingConv::C);
  /* Arg names */
  Function::arg_iterator args = fact64->arg_begin();
  Value* x = args++;
  x->setName("x");


  /* Body */
  BasicBlock* block = BasicBlock::Create(ctx, "entry", fact64);
  BasicBlock* xLessThan2Block= BasicBlock::Create(ctx, "xlst2_block", fact64);
  BasicBlock* elseBlock = BasicBlock::Create(ctx, "else_block", fact64);
  IRBuilder<> builder(block);

  Value *One = ConstantInt::get(Type::getInt64Ty(ctx), 1);
  Value *Two = ConstantInt::get(Type::getInt64Ty(ctx), 2);

  Value* xLessThan2 = builder.CreateICmpULT(x, Two, "tmp");
 //builder.CreateCondBr(xLessThan2, xLessThan2Block, cond_false_2);
  builder.CreateCondBr(xLessThan2, xLessThan2Block, elseBlock);


  /* Recursion */
  builder.SetInsertPoint(elseBlock);
  Value* xMinus1 = builder.CreateSub(x, One, "tmp");
  std::vector<Value*> args1;
  args1.push_back(xMinus1);
  Value* recur_1 = builder.CreateCall(fact64, args1.begin(), args1.end(), "tmp");
  Value* retVal = builder.CreateBinOp(Instruction::Mul, x, recur_1, "tmp");
  builder.CreateRet(retVal);

  /* x<2 */
  builder.SetInsertPoint(xLessThan2Block);
  builder.CreateRet(One);
  return mod;
}

int main(int argc, char**argv) {
  long long x;
  if(argc > 1)
    x = atol(argv[1]);
  else
    x = 4;

  Module* Mod = makeLLVMModule();

  verifyModule(*Mod, PrintMessageAction);
  PassManager PM;
  PM.add(createPrintModulePass(&outs()));
  PM.run(*Mod);

  // Now we going to create JIT
  ExecutionEngine *EE = EngineBuilder(Mod).create();
  // Call the  function with argument x:
  std::vector<GenericValue> Args(1);
  Args[0].IntVal =  APInt(64, x);  
  Function* TheF = cast<Function>(Mod->getFunction("fact64"))  ;

  /* The following CRASHES.. */
  GenericValue GV = EE->runFunction(TheF, Args);
  outs() << "Result: " << GV.IntVal << "\n";
  delete Mod;
  return 0;
}

Edit: The correct way to enable JIT (see the accepted answer below):

1.#include "llvm/ExecutionEngine/Jit.h"`

2.InitializeNativeTarget();
A: 
#include "llvm/ExecutionEngine/Interpreter.h"
bugspy.net
Any insights on why including this solves it?
tstenner
Yes. Good question. Why ?
bugspy.net
+1  A: 

Including that header forces a static initialisation of the JIT. Not the best design decision, but at least it works.

SK-logic
+2  A: 

I would bet that the ExecutionEngine pointer is null.... You are missing a call to InitializeNativeTarget, the documentation says:

InitializeNativeTarget - The main program should call this function to initialize the native target corresponding to the host. This is useful for JIT applications to ensure that the target gets linked in correctly.

Since there is no JIT compiler available without calling InitializeNativeTarget, ModuleBuilder selects the interpreter (if available). Probably not what you wanted. You may want to look at my previous post on this subject.

Nathan Howell
Thanks. Very useful info. Does this means that to use JIT and NOT the interperter I should include ExecutionEngine/JIT.h INSTEAD of llvm/ExecutionEngine/Interpreter.h ?
bugspy.net
Yes, if you want the JIT, include JIT.h and make sure to call InitializeNativeTarget() before creating an ExecutionEngine. You may also want to call EngineBuilder.setEngineKind(EngineKind::JIT) before calling .create() to make sure you're getting a JIT.
Nathan Howell