# -*- Mode: Cython -*-
# distutils: language = c++
# Use LLVM's JIT engine to load up some bitcode and execute it.
# lotsa clues from here:
# http://stackoverflow.com/questions/1838304/call-the-llvm-jit-from-c-program
from libcpp.string cimport string
# --------------------------------------------------------------------------------
# minimal declarations to get to the LLVM API.
# --------------------------------------------------------------------------------
cdef extern from "llvm/LLVMContext.h" namespace "llvm":
cdef cppclass LLVMContext:
LLVMContext()
cdef extern from "llvm/Support/TargetSelect.h" namespace "llvm":
cdef bint InitializeNativeTarget()
cdef extern from "llvm/Module.h" namespace "llvm":
cdef cppclass Module:
pass
cdef extern from "llvm/Support/MemoryBuffer.h" namespace "llvm":
cdef cppclass MemoryBuffer:
char * getBufferStart()
size_t getBufferSize()
# note naming hack to get to the static method (also note that we lose the
# namespace in the override).
cdef MemoryBuffer * MemoryBuffer_getMemBuffer "llvm::MemoryBuffer::getMemBuffer" (string)
cdef extern from "llvm/Bitcode/ReaderWriter.h" namespace "llvm":
cdef Module * ParseBitcodeFile (MemoryBuffer * Buffer, LLVMContext Context, string * ErrMsg)
cdef extern from "llvm/Function.h" namespace "llvm":
cdef cppclass Function:
pass
cdef extern from "llvm/ExecutionEngine/JIT.h" namespace "llvm":
cdef cppclass ExecutionEngine:
Function * FindFunctionNamed (char *FnName)
void * getPointerToFunction (Function *)
# static method
cdef ExecutionEngine * ExecutionEngine_create "llvm::ExecutionEngine::create" (Module *)
# --------------------------------------------------------------------------------
# global initialization
cdef bint init_nt = InitializeNativeTarget()
cdef LLVMContext * context = new LLVMContext()
class LLVMError (Exception):
pass
# 1) put this into a file, 'fact.c'
#
# int factorial (int x)
# {
# if (X == 0) {
# return 1;
# } else {
# return x * factorial (x-1);
# }
# }
#
# 2) clang -emit-llvm -O3 -S ~/fact.c
# This will compile to llvm assembly, optimized. Note that LLVM can actually turn it into a loop!
#
# 3) llvm-as fact.s
# This will compile the assembly to bitcode
#
# 4) run 'tryme' with the path to the resultant bitcode file (fact.s.bc).
ctypedef int iifun (int)
def tryme (path):
cdef MemoryBuffer * mb
cdef Module * module
cdef ExecutionEngine * engine
cdef Function * function
cdef string * error = new string()
cdef string * bitcode
cdef iifun * myfun
cdef bytes bc
bc = open (path, 'rb').read()
bitcode = new string (<char *>bc, <size_t>len(bc))
mb = MemoryBuffer_getMemBuffer (bitcode[0])
print 'mb.size = ', mb.getBufferSize()
module = ParseBitcodeFile (mb, context[0], error)
if not module:
raise LLVMError ("ParseBitcodeFile", error.c_str())
engine = ExecutionEngine_create (module)
if not engine:
raise LLVMError ("ExecutionEngine::create")
function = engine.FindFunctionNamed ("factorial")
if function:
myfun = <iifun*> engine.getPointerToFunction (function)
print myfun(5)