diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 14143f2..3366d58 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -184,6 +184,30 @@ _wLLVMGetBitcodeFromModule(PyObject *self, PyObject *args) return ret; } +static PyObject * +_wLLVMGetNativeCodeFromModule(PyObject * self, PyObject * args) +{ + PyObject * ret; + unsigned len; + unsigned char * bytes; + LLVMModuleRef m; + + PyObject * arg_m; + int arg_use_asm; + + if (!PyArg_ParseTuple(args, "Oi", &arg_m, &arg_use_asm)) + return NULL; + + m = (LLVMModuleRef) PyCapsule_GetPointer(arg_m, NULL); + + if ( !(bytes = LLVMGetNativeCodeFromModule(m, arg_use_asm, &len)) ) + Py_RETURN_NONE; + + ret = PyBytes_FromStringAndSize((char *)bytes, (Py_ssize_t)len); + delete [] bytes; + return ret; +} + static PyObject * _wLLVMLinkModules(PyObject *self, PyObject *args) { @@ -873,6 +897,8 @@ _wLLVMInitializePasses(PyObject * self, PyObject * args) Py_RETURN_NONE; } +_wrap_none2obj(LLVMInitializeNativeTarget, int) + /*===----------------------------------------------------------------------===*/ /* Passes */ @@ -1335,6 +1361,7 @@ static PyMethodDef core_methods[] = { _method( LLVMGetModuleFromAssembly ) _method( LLVMGetModuleFromBitcode ) _method( LLVMGetBitcodeFromModule ) + _method( LLVMGetNativeCodeFromModule ) _method( LLVMModuleGetPointerSize ) _method( LLVMModuleGetOrInsertFunction ) _method( LLVMLinkModules ) @@ -1717,6 +1744,7 @@ static PyMethodDef core_methods[] = { _method( LLVMDumpPasses ) _method( LLVMAddPassByName ) _method( LLVMInitializePasses ) + _method( LLVMInitializeNativeTarget ) /* Passes */ diff --git a/llvm/core.py b/llvm/core.py index 47b3b8a..7366d41 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -516,6 +516,16 @@ class Module(llvm.Ownable, llvm.Cacheable): id = property(_get_id, _set_id) + def to_native_object(self): + '''returns byte string of the module as native object code + ''' + return _core.LLVMGetNativeCodeFromModule(self.ptr, 0) + + def to_native_assembly(self): + '''returns byte string of the module as native assembly code + ''' + return _core.LLVMGetNativeCodeFromModule(self.ptr, 1) + #===----------------------------------------------------------------------=== # Types #===----------------------------------------------------------------------=== @@ -2126,3 +2136,12 @@ def inline_function(call): check_is_value(call) return _core.LLVMInlineFunction(call.ptr) + + +#===----------------------------------------------------------------------=== +# Initialization +#===----------------------------------------------------------------------=== +if _core.LLVMInitializeNativeTarget(): + raise llvm.LLVMException("No native target!?") + + diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 122d387..5d22200 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -52,6 +52,10 @@ //#include "llvm/TypeSymbolTable.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/CallSite.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Support/TargetSelect.h" + #include "llvm/IntrinsicInst.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/Parser.h" @@ -69,8 +73,6 @@ #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" - - // LLVM-C includes #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" @@ -110,6 +112,72 @@ char *do_print(W obj) p->print(buf); return strdup(buf.str().c_str()); } + +unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, + unsigned * lenp) +{ + using namespace llvm; + assert(lenp); + + InitializeNativeTargetAsmPrinter(); + + Module *modulep = unwrap(module); + assert(modulep); + + // get objectcode into a string + std::string s; + raw_string_ostream buf(s); + + formatted_raw_ostream fso(buf); + + TargetMachine * tm = EngineBuilder(modulep).selectTarget(); + + PassManager pm; + + if (!tm->getTargetData()){ + printf("No target data in target machine"); + return NULL; + } + + //printf("%s\n", modulep->getDataLayout().c_str()); + + pm.add(new TargetData(*tm->getTargetData())); + + bool failed; + if( assembly ) { + failed = tm->addPassesToEmitFile(pm, fso, TargetMachine::CGFT_AssemblyFile); + } else { + failed = tm->addPassesToEmitFile(pm, fso, TargetMachine::CGFT_ObjectFile); + } + + if ( failed ) { + printf("No support\n"); + printf("%s\n", tm->getTargetData()->getStringRepresentation().c_str()); + return NULL; + } + + pm.run(*modulep); + + // flush all streams + fso.flush(); + buf.flush(); + + const std::string& bc = buf.str(); + + // and then into a new buffer + size_t bclen = bc.size(); + unsigned char *bytes = new unsigned char[bclen]; + if (!bytes){ + return NULL; + } + memcpy(bytes, bc.data(), bclen); + + /* return */ + *lenp = bclen; + return bytes; +} + + static llvm::AtomicOrdering atomic_ordering_from_string(const char * ordering) { @@ -353,7 +421,6 @@ void LLVMInitializePasses(){ initializeTarget(registry); } - const char * LLVMDumpPasses() { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index b13c80f..f405679 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,11 @@ extern "C" { #endif +/* + * Wraps TargetMachine::addPassesToEmitFile + */ +unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, + unsigned * lenp); /* * Wraps IRBuilder::CreateFence diff --git a/test/native.py b/test/native.py new file mode 100755 index 0000000..f4287c9 --- /dev/null +++ b/test/native.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +from llvm import * +from llvm.core import * + +import unittest, subprocess + +class TestNative(unittest.TestCase): + + def _make_module(self): + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') + + fty = Type.function(Type.int(), []) + f = m.add_function(fty, name='main') + + bldr = Builder.new(f.append_basic_block('entry')) + bldr.ret(Constant.int(Type.int(), 0xab)) + + return m + + def _compile(self, src): + dst = '/tmp/llvmobj.out' + s = subprocess.call(['cc', '-o', dst, src]) + if s != 0: + raise Exception("Cannot compile") + + s = subprocess.call([dst]) + self.assertEqual(s, 0xab) + + + def test_assembly(self): + m = self._make_module() + output = m.to_native_assembly() + + src = '/tmp/llvmasm.s' + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + + def test_object(self): + m = self._make_module() + output = m.to_native_object() + + src = '/tmp/llvmobj.o' + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + +if __name__ == '__main__': + unittest.main()