LLVM... it LIVES!

Published February 27, 2012
Advertisement
So I decided that I was tired of not working on the VM side of things, and rigged up a simple test harness for LLVM.

Basically, this creates the following situation:

  • getstuff() is a function defined in the native .EXE which returns a simple integer
  • answer() is a function defined in LLVM bitcode at runtime
  • answer() accepts one integer parameter, adds it to the return value of getstuff(), and returns the result
  • The native .EXE will JIT compile answer() to native code, execute it, and print its return value

All this is pretty simple to do:

int _tmain(int argc, _TCHAR* argv[])
{
using namespace llvm;

InitializeNativeTarget();

LLVMContext& Context = getGlobalContext();

Module* module = new Module("EpochJIT", Context);

IRBuilder<> Builder(Context);

std::map NamedValues;


std::vector args(1, Type::getInt32Ty(Context));
FunctionType* functype = FunctionType::get(Type::getInt32Ty(Context), args, false);

Function* func = Function::Create(functype, Function::ExternalLinkage, "answer", module);

std::vector Args;
Args.push_back("a");

unsigned Idx = 0;
for(Function::arg_iterator AI = func->arg_begin(); Idx != Args.size(); ++AI, ++Idx)
{
AI->setName(Args[Idx]);
NamedValues[Args[Idx]] = AI;
}

BasicBlock* block = BasicBlock::Create(Context, "entry", func);
Builder.SetInsertPoint(block);

std::vector noargs;
FunctionType* getstufffunctype = FunctionType::get(Type::getInt32Ty(Context), noargs, false);
Function* getstufffunc = Function::Create(getstufffunctype, Function::ExternalLinkage, "getstuff", module);

Value* stuff = Builder.CreateCall(getstufffunc);

Value* addition = Builder.CreateAdd(NamedValues["a"], stuff, "addtmp");

Builder.CreateRet(addition);

verifyFunction(*func);

module->dump();

std::string ErrStr;
ExecutionEngine* ee = EngineBuilder(module).setErrorStr(&ErrStr).create();
if(!ee)
{
std::cout << ErrStr << std::endl;
return 1;
}

void* fptr = ee->getPointerToFunction(func);
int (*fp)(int) = (int (*)(int))fptr;

std::wcout << fp(2) << std::endl;

return 0;
}


And the results speak for themselves:

LLVM Test.png
1 likes 6 comments

Comments

_the_phantom_
Ah, LLVM.. I've played with it a bit, such a quality library and if/when I get around to needing/wanting my own scripting language it is hands down my first choice for the backend.
February 27, 2012 07:02 PM
ApochPiQ
Yeah, I've been extremely impressed by the library so far. Very clean design and stupid powerful.

I honestly was pleasantly surprised to discover that it's possible to go from AST to JIT'ed native code in a lazy evening's worth of work.
February 27, 2012 07:13 PM
nolongerhere
I was going to use it for a BASIC dialect I made a while back but I couldn't figure it out and the documentation wasn't of much help.
:/
I might have to relook at it since you claim that it is so easy to use!
February 28, 2012 01:11 AM
_the_phantom_
Only problem I had at the time was the release didn't support VS2010 out of the box, but that's long since been fixed.

What I found helpful was following the tutorial series on making their toy language; it was a decent intro to the lib and gave you something to jump from into the docs.
February 28, 2012 01:25 AM
evanofsky
I wanted to mess with LLVM, but don't you have to install 4 GB of stuff just to get it up and running?
February 28, 2012 08:15 PM
_the_phantom_
Well, the compile of the LLVM project does take up a fair chunk of space when you factor in all the .obj files etc; the final library directory I think I was using was somewhere around 700meg, the 'build' directory does apprently take up 8gb however you do have to weight that against how good the library is and what it can do.

In short; while big that really isn't an issue.
February 29, 2012 12:22 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement