diff --git a/llvm/_core.c b/llvm/_core.c index 1aaa62e..54e5764 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -1049,6 +1049,36 @@ _wrap_objobjint2obj(LLVMOffsetOfElement, LLVMTargetDataRef, LLVMTypeRef, llvmwrap_ull) +/*===----------------------------------------------------------------------===*/ +/* Engine Builder */ +/*===----------------------------------------------------------------------===*/ + +_wrap_obj2obj(LLVMCreateEngineBuilder, LLVMModuleRef, LLVMEngineBuilderRef) +_wrap_obj2none(LLVMDisposeEngineBuilder, LLVMEngineBuilderRef) +_wrap_obj2none(LLVMEngineBuilderForceJIT, LLVMEngineBuilderRef) +_wrap_obj2none(LLVMEngineBuilderForceInterpreter, LLVMEngineBuilderRef) +_wrap_objint2none(LLVMEngineBuilderSetOptLevel, LLVMEngineBuilderRef) + +static PyObject * +_wLLVMEngineBuilderCreate(PyObject *self, PyObject *args) +{ + LLVMEngineBuilderRef obj; + if (!(obj = (LLVMEngineBuilderRef)get_object_arg(args))) + return NULL; + + char * outmsg = 0; + + PyObject * ret; + ret = LLVMEngineBuilderCreate(obj, &outmsg); + + if( outmsg ){ // check if error message is set. + ret = PyBytes_FromString(outmsg); + free(outmsg); + } + + return ctor_LLVMExecutionEngineRef(ret); +} + /*===----------------------------------------------------------------------===*/ /* Execution Engine */ /*===----------------------------------------------------------------------===*/ @@ -1879,6 +1909,15 @@ static PyMethodDef core_methods[] = { _method( LLVMElementAtOffset ) _method( LLVMOffsetOfElement ) + /* Engine Builder */ + + _method( LLVMCreateEngineBuilder ) + _method( LLVMDisposeEngineBuilder ) + _method( LLVMEngineBuilderForceJIT ) + _method( LLVMEngineBuilderForceInterpreter ) + _method( LLVMEngineBuilderSetOptLevel ) + _method( LLVMEngineBuilderCreate ) + /* Execution Engine */ _method( LLVMCreateExecutionEngine ) _method( LLVMDisposeExecutionEngine ) diff --git a/llvm/ee.py b/llvm/ee.py index a54698d..24b9325 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -145,7 +145,7 @@ class GenericValue(object): core.check_is_type(ty) ptr = _core.LLVMCreateGenericValueOfPointer(ty.ptr, intval) return GenericValue(ptr) - + def __init__(self, ptr): self.ptr = ptr @@ -172,6 +172,47 @@ def _unpack_generic_values(objlist): return _util.unpack_gen(objlist, check_is_generic_value) +#===----------------------------------------------------------------------=== +# Engine builder +#===----------------------------------------------------------------------=== + +class EngineBuilder(object): + @staticmethod + def new(module): + core.check_is_module(module) + _util.check_is_unowned(module) + obj = _core.LLVMCreateEngineBuilder(module.ptr) + return EngineBuilder(obj, module) + + def __init__(self, ptr, module): + self.ptr = ptr + self._module = module + + def __del__(self): + _core.LLVMDisposeEngineBuilder(self.ptr) + + def force_jit(self): + _core.LLVMEngineBuilderForceJIT(self.ptr) + return self + + def force_interpreter(self): + _core.LLVMEngineBuilderForceInterpreter(self.ptr) + return self + + def opt(self, level): + ''' + level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] + ''' + assert level in range(4) + _core.LLVMEngineBuilderSetOptLevel(self.ptr, level) + return self + + def create(self): + ret = _core.LLVMEngineBuilderCreate(self.ptr) + if isinstance(ret, basestring): + raise llvm.LLVMException(ret) + return ExecutionEngine(ret, self._module) + #===----------------------------------------------------------------------=== # Execution engine #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 86067c0..0b5a874 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -69,13 +69,20 @@ #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" + + // LLVM-C includes #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" // our includes #include "extra.h" +#include "llvm_c_extra.h" + +namespace llvm{ +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(EngineBuilder, LLVMEngineBuilderRef) +} /* * For use in LLVMDumpPasses to dump passes. */ @@ -104,6 +111,58 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod) +{ + using namespace llvm; + return wrap(new EngineBuilder(unwrap(mod))); +} + +void LLVMDisposeEngineBuilder(LLVMEngineBuilderRef eb) +{ + delete llvm::unwrap(eb); +} + +void LLVMEngineBuilderForceJIT(LLVMEngineBuilderRef eb) +{ + using namespace llvm; + unwrap(eb)->setEngineKind(EngineKind::JIT); +} + +void LLVMEngineBuilderForceInterpreter(LLVMEngineBuilderRef eb) +{ + using namespace llvm; + unwrap(eb)->setEngineKind(EngineKind::Interpreter); +} + +void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level) +{ + using namespace llvm; + const CodeGenOpt::Level level_map[] = { + CodeGenOpt::None, + CodeGenOpt::Less, + CodeGenOpt::Default, + CodeGenOpt::Aggressive, + }; + + unwrap(eb)->setOptLevel(level_map[level]); +} + + +LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, char **err) +{ + using namespace llvm; + std::string errstring; + LLVMExecutionEngineRef ret; + + ret = wrap(unwrap(eb)->setErrorStr(&errstring).create()); + + if ( !errstring.empty() ) { + *err = strdup(errstring.c_str()); + return 0; + } else { + return ret; + } +} int LLVMPassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef pmb) { @@ -189,7 +248,8 @@ LLVMTypeRef LLVMStructTypeIdentified(const char * name) return wrap(StructType::create(getGlobalContext(), name)); } -void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, unsigned elemct, int is_packed) +void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, + unsigned elemct, int is_packed) { using namespace llvm; ArrayRef elemtys_aryref(unwrap(elemtys), elemct); diff --git a/llvm/extra.h b/llvm/extra.h index 27fadfc..9c73098 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -39,10 +39,44 @@ #include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm_c_extra.h" + #ifdef __cplusplus extern "C" { #endif +/* + * Wraps new EngineBuilder + */ +LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod); + +/* + * Wraps delete EngineBuilder + */ +void LLVMDisposeEngineBuilder(LLVMEngineBuilderRef eb); + + +/* + * Wraps EngineBuilder::setEngineKind(EngineKind::JIT) + */ +void LLVMEngineBuilderForceJIT(LLVMEngineBuilderRef eb); + +/* + * Wraps EngineBuilder::setEngineKind(EngineKind::Interpreter) + */ +void LLVMEngineBuilderForceInterpreter(LLVMEngineBuilderRef eb); + + +/* + * Wraps EngineBuilder::setOptLevel + */ +void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level); + +/* + * Wraps EngineBuilder::setErrorStr and EngineBuilder::create + */ +LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, char **err); + /* * Wraps PassManagerBuilder::OptLevel */ diff --git a/llvm/llvm_c_extra.h b/llvm/llvm_c_extra.h new file mode 100644 index 0000000..fc2b711 --- /dev/null +++ b/llvm/llvm_c_extra.h @@ -0,0 +1,29 @@ +#ifndef LLVM_C_EXTRA_H_ +#define LLVM_C_EXTRA_H_ + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + +// Resurrect from llvm-c/Core.h +#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ +inline ty *unwrap(ref P) { \ + return reinterpret_cast(P); \ +} \ + \ +inline ref wrap(const ty *P) { \ + return reinterpret_cast(const_cast(P)); \ +} + +typedef struct LLVMOpaqueEngineBuilder *LLVMEngineBuilderRef; + + +#ifdef __cplusplus + } +#endif + +#endif //LLVM_C_EXTRA_H_ + diff --git a/llvm/wrap.c b/llvm/wrap.c index 3653061..25ea30c 100644 --- a/llvm/wrap.c +++ b/llvm/wrap.c @@ -77,6 +77,7 @@ _define_std_ctor(LLVMTargetDataRef) _define_std_ctor(LLVMGenericValueRef) _define_std_ctor(LLVMPassManagerBuilderRef) +_define_std_ctor(LLVMEngineBuilderRef) PyObject *ctor_int(int i) { diff --git a/llvm/wrap.h b/llvm/wrap.h index 9fd5636..ca963b0 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -45,11 +45,14 @@ #include "llvm-c/Analysis.h" #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" + // workaround missing bool type #define bool int #include "llvm-c/Transforms/PassManagerBuilder.h" #undef bool +#include "llvm_c_extra.h" + /* Project-wide setting */ #if PY_MAJOR_VERSION >= 3 #define LLVM_PY_USE_PYCAPSULE @@ -88,8 +91,9 @@ _declare_std_ctor(LLVMExecutionEngineRef) _declare_std_ctor(LLVMTargetDataRef) _declare_std_ctor(LLVMGenericValueRef) -// extra LLVM class not defined in LLVM-C +// extra LLVM classes _declare_std_ctor(LLVMPassManagerBuilderRef) +_declare_std_ctor(LLVMEngineBuilderRef) /* standard types */ _declare_std_ctor(int) diff --git a/test/enginebuilder.py b/test/enginebuilder.py new file mode 100644 index 0000000..81b6163 --- /dev/null +++ b/test/enginebuilder.py @@ -0,0 +1,56 @@ +from llvm.ee import * +from llvm.core import * +from llvm import _util, LLVMException + +from ctypes import * + +import unittest, logging + +class TestEngineBuilder(unittest.TestCase): + + def make_test_module(self): + module = Module.new("testmodule") + fnty = Type.function(Type.int(), []) + function = module.add_function(fnty, 'foo') + bb_entry = function.append_basic_block('entry') + builder = Builder.new(bb_entry) + builder.ret(Constant.int(Type.int(), 0xcafe)) + module.verify() + return module + + def run_foo(self, ee, module): + function = module.get_function_named('foo') + retval = ee.run_function(function, []) + self.assertEqual(retval.as_int(), 0xcafe) + + + def test_enginebuilder_basic(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).create() + + with self.assertRaises(LLVMException): + # Ensure the module is owned. + _util.check_is_unowned(module) + + self.run_foo(ee, module) + + def test_enginebuilder_force_jit(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).force_jit().create() + + self.run_foo(ee, module) + + def test_enginebuilder_force_interpreter(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).force_interpreter().create() + + self.run_foo(ee, module) + + def test_enginebuilder_opt(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).opt(3).create() + + self.run_foo(ee, module) + +if __name__ == '__main__': + unittest.main()