From 437b1e949012595882f8fbb3065c0c7e4c9b0835 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 29 Jan 2013 17:47:15 -0600 Subject: [PATCH] All of DataLayout, IRBuilder and started on ExecutionEngine. --- newbinding/binding.py | 114 ++++++++- newbinding/capsule.py | 22 +- newbinding/codegen.py | 12 +- newbinding/gen.py | 11 +- .../include/llvm_binding/capsule_context.h | 10 + newbinding/include/llvm_binding/extra.h | 81 +++++- newbinding/src/CodeGen.py | 19 ++ newbinding/src/DataLayout.py | 97 +++++++ newbinding/src/ExecutionEngine.py | 34 +++ newbinding/src/GlobalVariable.py | 8 + newbinding/src/IRBuilder.py | 241 +++++++++++++++++- newbinding/src/Instruction.py | 32 ++- newbinding/src/JITMemoryManager.py | 7 + newbinding/src/Metadata.py | 7 + newbinding/src/Module.py | 3 +- newbinding/src/SmallVector.py | 4 + newbinding/src/TargetSelect.py | 8 + newbinding/src/Type.py | 4 + newbinding/src/Value.py | 1 + newbinding/test2.py | 14 + 20 files changed, 688 insertions(+), 41 deletions(-) create mode 100644 newbinding/src/CodeGen.py create mode 100644 newbinding/src/DataLayout.py create mode 100644 newbinding/src/ExecutionEngine.py create mode 100644 newbinding/src/GlobalVariable.py create mode 100644 newbinding/src/JITMemoryManager.py create mode 100644 newbinding/src/Metadata.py create mode 100644 newbinding/src/TargetSelect.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 6668452..f7d5ac4 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -5,11 +5,15 @@ import codegen as cg _rank = 0 namespaces = {} +RESERVED = frozenset(['None']) + class Namespace(object): def __init__(self, name): self.name = name + self.enums = [] self.classes = [] self.functions = [] + self.includes = set() namespaces[name] = self def Class(self, *bases): @@ -22,6 +26,13 @@ class Namespace(object): self.functions.append(fn) return fn + def Enum(self, name, *value_names): + enum = Enum(*value_names) + enum.parent = self + enum.name = name + self.enums.append(enum) + return enum + @property def fullname(self): return self.name @@ -43,11 +54,16 @@ class BuiltinTypes(_Type): def wrap(self, writer, var): return var + def unwrap(self, writer, var): + return var + Void = BuiltinTypes('void') Unsigned = BuiltinTypes('unsigned') +Uint64 = BuiltinTypes('uint64_t') Bool = BuiltinTypes('bool') ConstStdString = BuiltinTypes('const std::string') PyObjectPtr = BuiltinTypes('PyObject*') +PyObjectPtr.format='O' class Class(_Type): format = 'O' @@ -78,6 +94,7 @@ class Class(_Type): self.enums.append(v) v.name = k v.parent = self + setattr(self, k, v) elif isinstance(v, CustomPythonMethod): self.pymethods.append(v) elif k == '_include_': @@ -108,7 +125,7 @@ class Class(_Type): fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' for meth in self.methods: name = meth.name - func = cg.mangle(meth.fullname) + func = meth.c_name writer.println(fmt % locals()) writer.println('{ NULL },') writer.println('};') @@ -161,9 +178,12 @@ class Class(_Type): return casted class Enum(object): + format = 'O' + def __init__(self, *value_names): self.parent = None self.value_names = value_names + self.includes = set() @property def fullname(self): @@ -191,11 +211,34 @@ class Enum(object): writer.raises(ValueError, 'Invalid enum %s' % v) return ret + def unwrap(self, writer, val): + tostring = 'PyString_AsString(%(val)s)' % locals() + string = writer.declare('const char*', tostring) + ret = writer.declare('%s::%s' % (self.parent, self.name)) + parent = self.parent + iffmt = 'if (string_equal(%(string)s, "%(v)s"))' + for i, v in enumerate(self.value_names): + with writer.block(iffmt % locals()): + fmt = '%(ret)s = %(parent)s::%(v)s;' + writer.println(fmt % locals()) + if i == 0: + iffmt = 'else ' + iffmt + with writer.block('else'): + writer.raises(ValueError, 'Invalid enum.') + return ret + + def compile_cpp(self, writer): + pass + def compile_py(self, writer): with writer.block('class %s:' % self.name): writer.println('_llvm_type_ = "%s"' % self.fullname) for v in self.value_names: - writer.println('%(v)s = "%(v)s"' % locals()) + if v in RESERVED: + k = '%s_' % v + else: + k = v + writer.println('%(k)s = "%(v)s"' % locals()) writer.println() class Method(object): @@ -236,11 +279,15 @@ class Method(object): def realname(self, v): self.__realname = v + @property + def c_name(self): + return cg.mangle("%s_%s" % (self.parent, self.name)) + def __str__(self): return self.fullname def compile_cpp(self, writer): - with writer.py_function(self.fullname): + with writer.py_function(self.c_name): if len(self.signatures) == 1: sig = self.signatures[0] retty = sig[0] @@ -270,13 +317,40 @@ class Method(object): with decl as (this, varargs): unwrap_this = writer.unwrap(this) unwrapped = writer.unwrap_many(varargs) + self.process_ownedptr_args(writer, unwrapped) + func = '.'.join([self.parent.name, self.name]) ret = writer.call('_api.%s' % func, args=(unwrap_this,), varargs=unwrapped) - wrapped = writer.wrap(ret) + + wrapped = writer.wrap(ret, self.is_return_ownedptr()) + writer.return_value(wrapped) writer.println() + def require_only(self, num): + '''Require only "num" of argument. + ''' + assert len(self.signatures) == 1 + sig = self.signatures[0] + ret = sig[0] + args = sig[1:] + arg_ct = len(args) + + for i in range(num, arg_ct): + self._add_signature(ret, *args[:i]) + + return self + + def is_return_ownedptr(self): + retty = self.signatures[0][0] + return isinstance(retty, ownedptr) + + def process_ownedptr_args(self, writer, unwrapped): + argtys = self.signatures[0][1:] + for i, ty in enumerate(argtys): + if isinstance(ty, ownedptr): + writer.release_ownership('%s[%d]' % (unwrapped, i)) class CustomMethod(Method): def __init__(self, methodname, retty, *argtys): @@ -289,7 +363,6 @@ class CustomMethod(Method): writer.return_value(retty.wrap(writer, ret)) - class StaticMethod(Method): def compile_cpp_body(self, writer, retty, argtys): @@ -307,12 +380,24 @@ class StaticMethod(Method): decl = writer.function(self.name, varargs='args') with decl as varargs: unwrapped = writer.unwrap_many(varargs) + self.process_ownedptr_args(writer, unwrapped) + func = '.'.join([self.parent.name, self.name]) ret = writer.call('_api.%s' % func, varargs=unwrapped) - wrapped = writer.wrap(ret) + wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) writer.println() +class CustomStaticMethod(StaticMethod): + def __init__(self, methodname, retty, *argtys): + super(CustomStaticMethod, self).__init__(retty, *argtys) + self.methodname = methodname + + def compile_cpp_body(self, writer, retty, argtys): + args = writer.parse_arguments('args', *argtys) + ret = writer.call(self.methodname, retty.fullname, *args) + writer.return_value(retty.wrap(writer, ret)) + class Function(Method): _kind_ = 'func' @@ -329,10 +414,11 @@ class Function(Method): def compile_py(self, writer): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) + self.process_ownedptr_args(writer, unwrapped) func = self.fullname.split('::', 1)[1].replace('::', '.') ret = writer.call('_api.%s' % func, varargs=unwrapped) - wrapped = writer.wrap(ret) + wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) writer.println() @@ -400,10 +486,14 @@ class ptr(_Type): def __init__(self, element): assert isinstance(element, Class) self.element = element + self.const = False @property def fullname(self): - return '%s*' % self.element + if self.const: + return 'const %s*' % self.element + else: + return '%s*' % self.element @property def format(self): @@ -420,6 +510,13 @@ class ptr(_Type): return writer.pycapsule_new(val, self.element.capsule_name, self.element.fullname) +class ownedptr(ptr): + pass + +def const(ptr): + ptr.const = True + return ptr + class cast(_Type): format = 'O' @@ -458,7 +555,6 @@ class cast(_Type): return ret - class CustomPythonMethod(object): def __init__(self, fn): src = inspect.getsource(fn) diff --git a/newbinding/capsule.py b/newbinding/capsule.py index eaef7da..f489c7f 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -23,10 +23,11 @@ class WeakRef(ref): _pyclasses = {} _addr2obj = WeakValueDictionary() -_owners = {} +_owners = {} # address to weak reference def _sentry(ptr): - assert _capsule.check(ptr) + if not _capsule.check(ptr): + raise ValueError('Must provide a PyCapsule object.') def classof(cap): cls = _capsule.getClassName(cap) @@ -38,17 +39,16 @@ def _capsule_destructor(weak): addr = _capsule.getPointer(cap) cls = _capsule.getClassName(cap) logger.debug("destroy pointer 0x%08X to %s", addr, cls) - weak.dtor(cap) +# weak.dtor(cap) del _owners[addr] def release_ownership(old): addr = _capsule.getPointer(old) - if hasattr(old, '_delete_'): - oldweak = _owners[addr] - oldweak.owning = False # dis-own - del _owners[addr] + oldweak = _owners[addr] + oldweak.owning = False # dis-own + del _owners[addr] -def wrap(cap): +def wrap(cap, owned=False): '''Wrap a PyCapsule with the corresponding Wrapper class. If `cap` is not a PyCapsule, returns `cap` ''' @@ -66,7 +66,8 @@ def wrap(cap): obj = cls(cap) _addr2obj[addr] = obj # cache object by address # set ownership if *cls* defines *_delete_* - if hasattr(cls, '_delete_'): + if not owned and hasattr(cls, '_delete_'): + assert addr not in _owners, "has existing owner" weak = WeakRef(obj, _capsule_destructor) _owners[addr] = weak weak.capsule = cap @@ -84,10 +85,11 @@ def wrap(cap): def downcast(old, new): assert old is not new + assert _capsule.getPointer(old) not in _owners oldcls = classof(old) newcls = classof(new) assert issubclass(newcls, oldcls) - release_ownership(old) + # release_ownership(old) del _addr2obj[_capsule.getPointer(old)] # clear cache return wrap(new) diff --git a/newbinding/codegen.py b/newbinding/codegen.py index 7652447..5a31e38 100644 --- a/newbinding/codegen.py +++ b/newbinding/codegen.py @@ -104,10 +104,9 @@ class CodeWriterBase(object): @contextlib.contextmanager def py_function(self, name): - mangled = mangle(name) self.println('static') self.println('PyObject*') - with self.block('%(mangled)s(PyObject* self, PyObject* args)' % locals()): + with self.block('%(name)s(PyObject* self, PyObject* args)' % locals()): self.used_symbols.add('self') self.used_symbols.add('args') yield @@ -175,7 +174,7 @@ class CppCodeWriter(CodeWriterBase): arglist = ', '.join(args) stmt = '%(func)s(%(arglist)s)' % locals() if retty == 'void': - self.println(stmt) + self.println(stmt + ';') else: return self.declare(retty, stmt) @@ -247,6 +246,9 @@ class PyCodeWriter(CodeWriterBase): yield self.used_symbols = self.old + def release_ownership(self, val): + self.println('capsule.release_ownership(%(val)s)' % locals()) + def unwrap_many(self, args): unwrapped = self.new_symbol('unwrapped') self.println('%(unwrapped)s = map(capsule.unwrap, %(args)s)' % locals()) @@ -255,9 +257,9 @@ class PyCodeWriter(CodeWriterBase): def unwrap(self, val): return self.call('capsule.unwrap', args=(val,), ret='unwrapped') - def wrap(self, val): + def wrap(self, val, owned): wrapped = self.new_symbol('wrapped') - self.println('%(wrapped)s = capsule.wrap(%(val)s)' % locals()) + self.println('%(wrapped)s = capsule.wrap(%(val)s, %(owned)s)' % locals()) return wrapped def call(self, func, args=(), varargs=None, ret='ret'): diff --git a/newbinding/gen.py b/newbinding/gen.py index d9fc14f..47f5655 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -39,6 +39,7 @@ populate_submodules(module, submodules); def populate_headers(println): includes = [ + 'cstring', 'llvm_binding/conversion.h', 'llvm_binding/binding.h', 'llvm_binding/capsule_context.h', @@ -70,6 +71,9 @@ def main(): for cls in ns.classes: print cls units.append(cls) + for enum in ns.enums: + print enum + units.append(enum) # add extra stuffs downcastlist = [] @@ -84,7 +88,7 @@ def main(): units.append(fn) - # generate cpp source + # Generate C++ source with open('%s.cpp' % outputfilename, 'w') as cppfile: println = wrap_println_from_file(cppfile) @@ -93,6 +97,8 @@ def main(): # required headers includes = set() + for ns in namespaces.values(): + includes |= ns.includes for u in units: includes |= u.includes @@ -128,7 +134,7 @@ static for u in units: if isinstance(u, Function): name = u.name - func = codegen.mangle(u.fullname) + func = u.c_name writer.println(fmt % locals()) writer.println('{ NULL },') writer.println('};') @@ -154,6 +160,7 @@ static println(extension_entry % {'module': '_api', 'methtable': 'methtable'}) + # Generate Python source with open('%s.py' % outputfilename, 'w') as pyfile: println = wrap_println_from_file(pyfile) println('import _api, capsule') diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h index ed63e43..6ed1381 100644 --- a/newbinding/include/llvm_binding/capsule_context.h +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -39,6 +39,16 @@ PyObject* pycapsule_new(void* ptr, } +static +PyObject* pycapsule_new(const void* ptr, + const char* basename, + const char* classname=NULL) +{ + // Use const_cast to strip the constantness. + // Let the user take the responsibility. + return pycapsule_new(const_cast(ptr), basename, classname); +} + #endif //LLVMPY_CAPSULE_CONTEXT_H_ diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 9f2bd70..b5edd2c 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -3,7 +3,7 @@ #include #include #include - +#include namespace extra{ using namespace llvm; @@ -97,11 +97,34 @@ PyObject* make_small_vector_from_values(PyObject* self, PyObject* args) } +static +PyObject* make_small_vector_from_unsigned(PyObject* self, PyObject* args) +{ + using llvm::Value; + typedef llvm::SmallVector SmallVector_Unsigned; + + SmallVector_Unsigned* SV = new SmallVector_Unsigned; + Py_ssize_t size = PyTuple_Size(args); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject* item = PyTuple_GetItem(args, i); + if (!item) { + return NULL; + } + unsigned value = PyLong_AsUnsignedLong(item); + if (PyErr_Occurred()){ + return NULL; + } + SV->push_back(value); + } + return pycapsule_new(SV, "llvm::SmallVector"); +} + static PyMethodDef extra_methodtable[] = { #define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } method( make_raw_ostream_for_printing ), method( make_small_vector_from_types ), method( make_small_vector_from_values ), + method( make_small_vector_from_unsigned ), #undef method { NULL } }; @@ -139,11 +162,20 @@ PyObject* iplist_to_pylist(iplist &IPL, const char * capsuleName, className); } +static +bool string_equal(const char *A, const char *B){ + for (; *A and *B; ++A, ++B) { + if (*A != *B) return false; + } + return true; +} + +//////////// static PyObject* Value_use_iterator_to_list(llvm::Value* val) { return iterator_to_pylist(val->use_begin(), val->use_end(), - "llvm::Value", "llvm::User"); + "llvm::Value", "llvm::User"); } static @@ -158,4 +190,47 @@ PyObject* Function_getBasicBlockList(llvm::Function* fn) { return iplist_to_pylist(fn->getBasicBlockList(), "llvm::Value", "llvm::BasicBlock"); -} \ No newline at end of file +} + +/* + * errout --- can be any file object + * + */ +static +llvm::ExecutionEngine* ExecutionEngine_create( + llvm::Module* M, + bool ForceInterpreter = false, + PyObject* errout = 0, + llvm::CodeGenOpt::Level OptLevel = llvm::CodeGenOpt::Default, + bool GVsWithCode = true) +{ + using namespace llvm; + std::string ErrorStr; + ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter, + &ErrorStr, OptLevel, + GVsWithCode); + PyFile_WriteString(ErrorStr.c_str(), errout); + return ee; +} + +/* + * errout --- can be any file object + * + */ +static +llvm::ExecutionEngine* ExecutionEngine_createJIT( + llvm::Module* M, + PyObject* errout = 0, + llvm::JITMemoryManager* JMM = 0, + llvm::CodeGenOpt::Level OL = llvm::CodeGenOpt::Default, + bool GCsWithCode = true, + llvm::Reloc::Model RM = llvm::Reloc::Default, + llvm::CodeModel::Model CMM = llvm::CodeModel::JITDefault) +{ + using namespace llvm; + std::string ErrorStr; + ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL, + GCsWithCode, RM, CMM); + PyFile_WriteString(ErrorStr.c_str(), errout); + return ee; +} diff --git a/newbinding/src/CodeGen.py b/newbinding/src/CodeGen.py new file mode 100644 index 0000000..06821aa --- /dev/null +++ b/newbinding/src/CodeGen.py @@ -0,0 +1,19 @@ +from binding import * +from namespace import llvm + +@llvm.Class() +class Reloc: + Model = Enum('Default', 'Static', 'PIC_', 'DynamicNoPIC') + +@llvm.Class() +class CodeModel: + Model = Enum('Default', 'JITDefault', 'Small', 'Kernel', 'Medium', 'Large') + +@llvm.Class() +class TLSModel: + Model = Enum('GeneralDynamic', 'LocalDynamic', 'InitialExec', 'LocalExec') + +@llvm.Class() +class CodeGenOpt: + 'Actually a namespace' + Level = Enum('None', 'Less', 'Default', 'Aggressive') diff --git a/newbinding/src/DataLayout.py b/newbinding/src/DataLayout.py new file mode 100644 index 0000000..a1ef8bc --- /dev/null +++ b/newbinding/src/DataLayout.py @@ -0,0 +1,97 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from StringRef import StringRef +from Module import Module +from Type import Type, IntegerType, StructType +from SmallVector import SmallVector_Value +from GlobalVariable import GlobalVariable + +DataLayout = llvm.Class() +StructLayout = llvm.Class() + +@DataLayout +class DataLayout: + _include_ = 'llvm/DataLayout.h' + + _new_string = Constructor(cast(str, StringRef)) + _new_module = Constructor(ptr(Module)) + + @CustomPythonStaticMethod + def new(arg): + if isinstance(arg, Module): + return DataLayout._new_module(arg) + else: + return DataLayout._new_string(arg) + + delete = Destructor() + + isLittleEndian = Method(cast(Bool, bool)) + isBigEndian = Method(cast(Bool, bool)) + + getStringRepresentation = Method(cast(StringRef, str)) + + @CustomPythonMethod + def __str__(self): + return self.getStringRepresentation() + + isLegalInteger = Method(cast(Bool, bool), cast(int, Unsigned)) + isIllegalInteger = Method(cast(Bool, bool), cast(int, Unsigned)) + exceedsNaturalStackAlignment = Method(cast(Bool, bool), cast(int, Unsigned)) + fitsInLegalInteger = Method(cast(Bool, bool), cast(int, Unsigned)) + + getPointerABIAlignment = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + getPointerPrefAlignment = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + getPointerSize = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + getPointerSizeInBits = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + + getTypeSizeInBits = Method(cast(Uint64, int), ptr(Type)) + getTypeStoreSize = Method(cast(Uint64, int), ptr(Type)) + getTypeStoreSizeInBits = Method(cast(Uint64, int), ptr(Type)) + getTypeAllocSize = Method(cast(Uint64, int), ptr(Type)) + getTypeAllocSizeInBits = Method(cast(Uint64, int), ptr(Type)) + + getABITypeAlignment = Method(cast(Unsigned, int), ptr(Type)) + getABIIntegerTypeAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) + getCallFrameTypeAlignment = Method(cast(Unsigned, int), ptr(Type)) + getPrefTypeAlignment = Method(cast(Unsigned, int), ptr(Type)) + getPreferredTypeAlignmentShift = Method(cast(Unsigned, int), ptr(Type)) + + _getIntPtrType = Method(ptr(IntegerType), + ref(LLVMContext), cast(int, Unsigned)) + _getIntPtrType.require_only(1) + _getIntPtrType.realname = 'getIntPtrType' + + _getIntPtrType2 = Method(ptr(Type), ptr(Type)) + _getIntPtrType2.realname = 'getIntPtrType' + + @CustomPythonMethod + def getIntPtrType(self, *args): + if isinstance(args[0], LLVMContext): + return self._getIntPtrType(*args) + else: + return self._getIntPtrType(*args) + + _getIndexedOffset = Method(cast(Uint64, int), ptr(Type), + ref(SmallVector_Value)) + _getIndexedOffset.realname = 'getIndexedOffset' + + @CustomPythonMethod + def getIndexedOffset(self, *args): + import extra + args = list(args) + args[1] = extra.make_small_vector_from_values(args[1]) + return self.getIndexedOffset(*args) + + getStructLayout = Method(const(ptr(StructLayout)), ptr(StructType)) + + getPreferredAlignment = Method(cast(Unsigned, int), ptr(GlobalVariable)) + getPreferredAlignmentLog = Method(cast(Unsigned, int), ptr(GlobalVariable)) + +@StructLayout +class StructLayout: + pass diff --git a/newbinding/src/ExecutionEngine.py b/newbinding/src/ExecutionEngine.py new file mode 100644 index 0000000..0fbe387 --- /dev/null +++ b/newbinding/src/ExecutionEngine.py @@ -0,0 +1,34 @@ +from binding import * +from namespace import llvm +from Module import Module +from JITMemoryManager import JITMemoryManager +from CodeGen import CodeGenOpt, Reloc, CodeModel +from DataLayout import DataLayout + +ExecutionEngine = llvm.Class() + +@ExecutionEngine +class ExecutionEngine: + _include_ = ('llvm/ExecutionEngine/ExecutionEngine.h', + 'llvm/ExecutionEngine/JIT.h') # force linking of jit + + delete = Destructor() + + create = CustomStaticMethod('ExecutionEngine_create', + ptr(ExecutionEngine), + ownedptr(Module), cast(bool, Bool), + PyObjectPtr, CodeGenOpt.Level, + cast(bool, Bool)).require_only(1) + + createJIT = CustomStaticMethod('ExecutionEngine_createJIT', + ptr(ExecutionEngine), + ownedptr(Module), PyObjectPtr, + ptr(JITMemoryManager), + CodeGenOpt.Level, + cast(bool, Bool), + Reloc.Model, + CodeModel.Model).require_only(1) + + addModule = Method(Void, ptr(Module)) + getDataLayout = Method(const(ownedptr(DataLayout))) + removeModule = Method(cast(Bool, bool), ptr(Module)) diff --git a/newbinding/src/GlobalVariable.py b/newbinding/src/GlobalVariable.py new file mode 100644 index 0000000..548a8d1 --- /dev/null +++ b/newbinding/src/GlobalVariable.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm +from GlobalValue import GlobalValue + +@llvm.Class(GlobalValue) +class GlobalVariable: + pass + diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py index 41e6681..cea94ce 100644 --- a/newbinding/src/IRBuilder.py +++ b/newbinding/src/IRBuilder.py @@ -2,10 +2,16 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from BasicBlock import BasicBlock -from Instruction import ReturnInst, CallInst -from SmallVector import SmallVector_Value +from Instruction import ReturnInst, CallInst, BranchInst, SwitchInst +from Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode +from Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst +from Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst +from Instruction import LandingPadInst, VAArgInst +from Instruction import AtomicOrdering, SynchronizationScope +from SmallVector import SmallVector_Value, SmallVector_Unsigned from StringRef import StringRef -from Value import Value +from Value import Value, MDNode +from Type import Type, IntegerType IRBuilder = llvm.Class() @@ -24,15 +30,238 @@ class IRBuilder: CreateRetVoid = Method(ptr(ReturnInst)) CreateRet = Method(ptr(ReturnInst), ptr(Value)) - _CreateCall = Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value), + CreateBr = Method(ptr(BranchInst), ptr(BasicBlock)) + + + CreateCondBr = Method(ptr(BranchInst), ptr(Value), ptr(BasicBlock), + ptr(BasicBlock), ptr(MDNode)).require_only(3) + + CreateSwitch = Method(ptr(SwitchInst), ptr(Value), ptr(BasicBlock), + cast(int, Unsigned), ptr(MDNode)).require_only(2) + + CreateIndirectBr = Method(ptr(IndirectBrInst), ptr(Value), + cast(int, Unsigned)).require_only(1) + + CreateInvoke = Method(ptr(InvokeInst), ptr(Value), ptr(BasicBlock), + ptr(BasicBlock), ref(SmallVector_Value), + cast(str, StringRef)).require_only(4) + + CreateResume = Method(ptr(ResumeInst), ptr(Value)) + + CreateUnreachable = Method(ptr(UnreachableInst)) + + def _binop_has_nsw_nuw(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef), + cast(bool, Bool), cast(bool, Bool)] + op = Method(*sig).require_only(2) + return op + + CreateAdd = _binop_has_nsw_nuw() + CreateSub = _binop_has_nsw_nuw() + CreateMul = _binop_has_nsw_nuw() + CreateShl = _binop_has_nsw_nuw() + + def _binop_is_exact(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef), + cast(bool, Bool)] + op = Method(*sig).require_only(2) + return op + + CreateUDiv = _binop_is_exact() + CreateSDiv = _binop_is_exact() + CreateLShr = _binop_is_exact() + CreateAShr = _binop_is_exact() + + def _binop_basic(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef)] + op = Method(*sig).require_only(2) + return op + + CreateURem = _binop_basic() + CreateSRem = _binop_basic() + CreateAnd = _binop_basic() + CreateOr = _binop_basic() + CreateXor = _binop_basic() + + def _float_binop(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef), + ptr(MDNode)] + op = Method(*sig).require_only(2) + return op + + CreateFAdd = _float_binop() + CreateFSub = _float_binop() + CreateFMul = _float_binop() + CreateFDiv = _float_binop() + CreateFRem = _float_binop() + + def _unop_has_nsw_nuw(): + sig = [ptr(Value), ptr(Value), cast(str, StringRef), + cast(bool, Bool), cast(bool, Bool)] + op = Method(*sig).require_only(1) + return op + + CreateNeg = _unop_has_nsw_nuw() + + def _float_unop(): + sig = [ptr(Value), ptr(Value), cast(str, StringRef), ptr(MDNode)] + op = Method(*sig).require_only(1) + return op + + CreateFNeg = _float_unop() + + CreateNot = Method(ptr(Value), + ptr(Value), cast(str, StringRef)).require_only(1) + + + CreateAlloca = Method(ptr(AllocaInst), ptr(Type), ptr(Value), + cast(str, StringRef)).require_only(2) + + CreateLoad = Method(ptr(LoadInst), + ptr(Value), cast(str, StringRef)).require_only(1) + + CreateStore = Method(ptr(StoreInst), ptr(Value), ptr(Value), + cast(bool, Bool)).require_only(2) + + CreateAlignedLoad = Method(ptr(LoadInst), ptr(Value), cast(int, Unsigned), + cast(bool, Bool), cast(str, StringRef)) + CreateAlignedLoad.require_only(2) + + CreateAlignedStore = Method(ptr(StoreInst), ptr(Value), ptr(Value), + cast(int, Unsigned), cast(bool, Bool)) + CreateAlignedStore.require_only(3) + + CreateFence = Method(ptr(FenceInst), + AtomicOrdering, SynchronizationScope).require_only(1) + + CreateAtomicCmpXchg = Method(ptr(AtomicCmpXchgInst), ptr(Value), ptr(Value), + ptr(Value), AtomicOrdering, SynchronizationScope) + CreateAtomicCmpXchg.require_only(4) + + CreateAtomicRMW = Method(ptr(AtomicRMWInst), AtomicRMWInst.BinOp, + ptr(Value), ptr(Value), AtomicOrdering, + SynchronizationScope) + CreateAtomicRMW.require_only(4) + + _CreateGEP = Method(ptr(Value), ptr(Value), ref(SmallVector_Value), + cast(str, StringRef)) + _CreateGEP.require_only(2) + _CreateGEP.realname = 'CreateGEP' + + @CustomPythonMethod + def CreateGEP(self, *args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return self._CreateGEP(*args) + + _CreateInBoundsGEP = Method(ptr(Value), ptr(Value), ref(SmallVector_Value), cast(str, StringRef)) - _CreateCall |= Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value)) + _CreateInBoundsGEP.require_only(2) + _CreateInBoundsGEP.realname = 'CreateInBoundsGEP' + + @CustomPythonMethod + def CreateInBoundsGEP(self, *args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return self._CreateInBoundsGEP(*args) + + CreateStructGEP = Method(ptr(Value), ptr(Value), cast(int, Unsigned), + cast(str, StringRef)).require_only(2) + + CreateGlobalStringPtr = Method(ptr(Value), cast(str, StringRef), + cast(str, StringRef)).require_only(1) + + def _value_type(): + sig = [ptr(Value), ptr(Value), ptr(Type), cast(str, StringRef)] + op = Method(*sig).require_only(2) + return op + + CreateTrunc = _value_type() + CreateZExt = _value_type() + CreateSExt = _value_type() + CreateZExtOrTrunc = Method(ptr(Value), ptr(Value), ptr(IntegerType), + cast(str, StringRef)).require_only(2) + CreateSExtOrTrunc = Method(ptr(Value), ptr(Value), ptr(IntegerType), + cast(str, StringRef)).require_only(2) + CreateFPToUI = _value_type() + CreateFPToSI = _value_type() + CreateUIToFP = _value_type() + CreateSIToFP = _value_type() + CreateFPTrunc = _value_type() + CreateFPExt = _value_type() + CreatePtrToInt = _value_type() + CreateIntToPtr = _value_type() + CreateBitCast = _value_type() + CreateZExtOrBitCast = _value_type() + CreateSExtOrBitCast = _value_type() + # Skip CreateCast + CreateTruncOrBitCast = _value_type() + CreateIntCast = Method(ptr(Value), ptr(Value), ptr(Type), cast(bool, Bool), + cast(str, StringRef)).require_only(3) + CreateFPCast = _value_type() + + _CreateCall = Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value), + cast(str, StringRef)).require_only(2) _CreateCall.realname = 'CreateCall' + # Skip specialized CreateICmp* and CreateFCmp* + + CreateICmp = Method(ptr(Value), CmpInst.Predicate, ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreateFCmp = Method(ptr(Value), CmpInst.Predicate, ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreatePHI = Method(ptr(PHINode), ptr(Type), cast(int, Unsigned), + cast(str, StringRef)).require_only(2) + @CustomPythonMethod def CreateCall(self, *args): import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_values(*valuelist) - return IRBuilder._CreateCall(self, *args) + return self._CreateCall(*args) + + CreateSelect = Method(ptr(Value), ptr(Value), ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreateVAArg = Method(ptr(VAArgInst), ptr(Value), ptr(Type), + cast(str, StringRef)).require_only(2) + + CreateExtractElement = _binop_basic() + + CreateInsertElement = Method(ptr(Value), ptr(Value), ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreateShuffleVector = Method(ptr(Value), ptr(Value), ptr(Value), + ptr(Value), cast(str, StringRef)) + CreateShuffleVector.require_only(3) + + CreateExtractValue = Method(ptr(Value), ptr(Value), ref(SmallVector_Unsigned), + cast(str, StringRef)) + CreateExtractValue.require_only(2) + + CreateInsertValue = Method(ptr(Value), ptr(Value), ptr(Value), + ref(SmallVector_Unsigned), cast(str, StringRef)) + CreateInsertValue.require_only(3) + + CreateLandingPad = Method(ptr(LandingPadInst), ptr(Type), ptr(Value), + cast(int, Unsigned), cast(str, StringRef)) + CreateLandingPad.require_only(3) + + CreateIsNull = Method(ptr(Value), ptr(Value), cast(str, StringRef)) + CreateIsNull.require_only(1) + + CreateIsNotNull = Method(ptr(Value), ptr(Value), cast(str, StringRef)) + CreateIsNotNull.require_only(1) + + CreatePtrDiff = _binop_basic() + + # New in llvm 3.3 + #CreateVectorSplat = Method(ptr(Value), cast(int, Unsigned), ptr(Value), + # cast(str, StringRef)) diff --git a/newbinding/src/Instruction.py b/newbinding/src/Instruction.py index 310e19d..dda6b48 100644 --- a/newbinding/src/Instruction.py +++ b/newbinding/src/Instruction.py @@ -26,9 +26,9 @@ IntrinsicInst = llvm.Class(CallInst) FCmpInst = llvm.Class(CmpInst) ICmpInst = llvm.Class(CmpInst) - BranchInst = llvm.Class(TerminatorInst) IndirectBrInst = llvm.Class(TerminatorInst) +InvokeInst = llvm.Class(TerminatorInst) ResumeInst = llvm.Class(TerminatorInst) ReturnInst = llvm.Class(TerminatorInst) SwitchInst = llvm.Class(TerminatorInst) @@ -56,14 +56,14 @@ FPTruncInst = llvm.Class(CastInst) class Instruction: pass - @AtomicCmpXchgInst class AtomicCmpXchgInst: pass @AtomicRMWInst class AtomicRMWInst: - pass + BinOp = Enum('Xchg', 'Add', 'Sub', 'And', 'Nand', 'Or', 'Xor', 'Max', 'Min', + 'UMax', 'UMin', 'FIRST_BINOP', 'LAST_BINOP', 'BAD_BINOP') @BinaryOperator class BinaryOperator: @@ -75,7 +75,17 @@ class CallInst: @CmpInst class CmpInst: - pass + Predicate = Enum('FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT', 'FCMP_OGE', + 'FCMP_OLT', 'FCMP_OLE', 'FCMP_ONE', 'FCMP_ORD', 'FCMP_UNO', + 'FCMP_UEQ', 'FCMP_UGT', 'FCMP_UGE', 'FCMP_ULT', 'FCMP_ULE', + 'FCMP_UNE', 'FCMP_TRUE', 'FIRST_FCMP_PREDICATE', + 'LAST_FCMP_PREDICATE', + 'BAD_FCMP_PREDICATE', + 'ICMP_EQ', 'ICMP_NE', 'ICMP_UGT', 'ICMP_UGE', 'ICMP_ULT', + 'ICMP_ULE', 'ICMP_SGT', 'ICMP_SGE', 'ICMP_SLT', 'ICMP_SLE', + 'FIRST_ICMP_PREDICATE', + 'LAST_ICMP_PREDICATE', + 'BAD_ICMP_PREDICATE',) @ExtractElementInst class ExtractElementInst: @@ -146,11 +156,14 @@ class ICmpInst: class BranchInst: pass - @IndirectBrInst class IndirectBrInst: pass +@InvokeInst +class InvokeInst: + pass + @ResumeInst class ResumeInst: pass @@ -228,3 +241,12 @@ class FPToUIInst: @FPTruncInst class FPTruncInst: pass + +AtomicOrdering = llvm.Enum('AtomicOrdering', + 'NotAtomic', 'Unordered', 'Monotonic', 'Acquire', + 'Release', 'AcquireRelease', + 'SequentiallyConsistent') + +SynchronizationScope = llvm.Enum('SynchronizationScope', + 'SingleThread', 'CrossThread') + diff --git a/newbinding/src/JITMemoryManager.py b/newbinding/src/JITMemoryManager.py new file mode 100644 index 0000000..f134735 --- /dev/null +++ b/newbinding/src/JITMemoryManager.py @@ -0,0 +1,7 @@ +from binding import * +from namespace import llvm + +@llvm.Class() +class JITMemoryManager: + pass + diff --git a/newbinding/src/Metadata.py b/newbinding/src/Metadata.py new file mode 100644 index 0000000..78dbe15 --- /dev/null +++ b/newbinding/src/Metadata.py @@ -0,0 +1,7 @@ +from binding import * +from namespace import llvm +from Value import MDNode + +@MDNode +class MDNode: + pass diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 730b757..6cd6e2e 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -36,7 +36,8 @@ class Module: appendModuleInlineAsm = Method(Void, cast(str, StringRef)) # Function Accessors - getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), ptr(FunctionType)) + getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), + ptr(FunctionType)) # Utilities dump = Method(Void) diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py index 594faf8..5b48aba 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/SmallVector.py @@ -11,3 +11,7 @@ class SmallVector_Value: _realname_ = 'SmallVector' delete = Destructor() +@llvm.Class() +class SmallVector_Unsigned: + _realname_ = 'SmallVector' + delete = Destructor() diff --git a/newbinding/src/TargetSelect.py b/newbinding/src/TargetSelect.py new file mode 100644 index 0000000..cb2eb96 --- /dev/null +++ b/newbinding/src/TargetSelect.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm + +llvm.includes.add('llvm/Support/TargetSelect.h') + +llvm.Function('InitializeNativeTarget') +#llvm.Function('InitializeAllTargets') + diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 45f9444..15b5e31 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -6,6 +6,7 @@ from raw_ostream import raw_ostream Type = llvm.Class() IntegerType = llvm.Class(Type) CompositeType = llvm.Class(Type) +StructType = llvm.Class(CompositeType) SequentialType = llvm.Class(CompositeType) PointerType = llvm.Class(SequentialType) @@ -113,3 +114,6 @@ class SequentialType: class PointerType: pass +@StructType +class StructType: + pass diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 5b907bd..7460c90 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -9,6 +9,7 @@ from StringRef import StringRef Value = llvm.Class() # forward declarations Argument = llvm.Class(Value) +MDNode = llvm.Class(Value) User = llvm.Class(Value) BasicBlock = llvm.Class(Value) Constant = llvm.Class(User) diff --git a/newbinding/test2.py b/newbinding/test2.py index a7a4ddd..9492bb6 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,7 +1,11 @@ import api import extra import _capsule +from StringIO import StringIO api.capsule.set_debug(True) + + +api.InitializeNativeTarget() context = api.getGlobalContext() @@ -71,3 +75,13 @@ builder.CreateRet(ret) print fn +errio = StringIO() +ee = api.ExecutionEngine.createJIT(m) +print ee, errio.getvalue() +print ee.getDataLayout().getStringRepresentation() + +datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64' + +assert datalayout_str == str(api.DataLayout.new(datalayout_str)) +assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) +