15

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();
GabiMe
  • 18,105
  • 28
  • 76
  • 113

3 Answers3

11

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.

Community
  • 1
  • 1
Nathan Howell
  • 4,627
  • 1
  • 22
  • 30
  • 1
    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 ? – GabiMe Mar 16 '10 at 10:03
  • 1
    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 Mar 16 '10 at 15:24
  • I wish I could up vote this more. I spent about an hour hunting this issue down. Guess I need to learn to RTFM a little better. :) Thanks again! – Hans Van Slooten Jul 10 '11 at 07:33
  • 1
    Looks like as of LLVM 6.0.0 you need to include this file instead: `#include "llvm/ExecutionEngine/MCJIT.h"` – Shivanshu Goyal Jul 22 '18 at 05:55
3
#include "llvm/ExecutionEngine/Interpreter.h"
GabiMe
  • 18,105
  • 28
  • 76
  • 113
  • 1
    This made the the HowToUseJIT example stop crashing on Windows 10 with Visual Studio 2017. x64 debug build. Kaleidoscope-Ch4 is still crashing. I think that example only search for external function declarations, but still trying to find the root cause. – Damian Jan 15 '19 at 03:43
  • @Damian Any Lucks ? – proton Oct 18 '20 at 20:02
3

Including that header (llvm/ExecutionEngine/Interpreter.h) forces a static initialisation of the JIT. Not the best design decision, but at least it works.

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
SK-logic
  • 9,605
  • 1
  • 23
  • 35