diff --git a/newbinding/binding.py b/newbinding/binding.py index f7d5ac4..9ddedf3 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -59,9 +59,17 @@ class BuiltinTypes(_Type): Void = BuiltinTypes('void') Unsigned = BuiltinTypes('unsigned') +UnsignedLongLong = BuiltinTypes('unsigned long long') # used in llvm-3.2 +LongLong = BuiltinTypes('long long') +Float = BuiltinTypes('float') +Double = BuiltinTypes('double') Uint64 = BuiltinTypes('uint64_t') +Size_t = BuiltinTypes('size_t') +VoidPtr = BuiltinTypes('void*') Bool = BuiltinTypes('bool') +StdString = BuiltinTypes('std::string') ConstStdString = BuiltinTypes('const std::string') +ConstCharPtr = BuiltinTypes('const char*') PyObjectPtr = BuiltinTypes('PyObject*') PyObjectPtr.format='O' diff --git a/newbinding/include/llvm_binding/conversion.h b/newbinding/include/llvm_binding/conversion.h index 0e30c60..a1fc87c 100644 --- a/newbinding/include/llvm_binding/conversion.h +++ b/newbinding/include/llvm_binding/conversion.h @@ -25,6 +25,45 @@ int py_str_to(PyObject *strobj, llvm::StringRef &strref){ return 1; } +static +int py_str_to(PyObject *strobj, std::string &strref){ + // type check + if (!PyString_Check(strobj)) { + // raises TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a str"); + return 0; + } + // get len and buffer + const char * buf = PyString_AsString(strobj); + if (!buf) { + // raises TypeError + return 0; + } + // set output + strref = std::string(buf); + // success + return 1; +} + + +static +int py_str_to(PyObject *strobj, const char* &strref){ + // type check + if (!PyString_Check(strobj)) { + // raises TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a str"); + return 0; + } + // get buffer + strref = PyString_AsString(strobj); + if (!strref) { + // raises TypeError + return 0; + } + // success + return 1; +} + static int py_int_to(PyObject *intobj, unsigned & val){ if (!PyInt_Check(intobj)) { @@ -37,6 +76,70 @@ int py_int_to(PyObject *intobj, unsigned & val){ return 1; } +static +int py_int_to(PyObject *intobj, unsigned long long & val){ + if (!PyInt_Check(intobj)) { + // raise TypeError + puts(PyString_AsString(PyObject_Str(PyObject_Type(intobj)))); + PyErr_SetString(PyExc_TypeError, "Expecting an int 2"); + return 0; + } + val = PyInt_AsUnsignedLongLongMask(intobj); + // success + return 1; + +} + +static +int py_int_to(PyObject *intobj, size_t & val){ + unsigned long long ull; + if (py_int_to(intobj, ull)) { + val = (size_t)ull; + return 1; + } else { + return 0; + } +} + + +static +int py_int_to(PyObject *intobj, void* & val){ + if (!PyLong_Check(intobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting an int"); + return 0; + } + val = PyLong_FromVoidPtr(intobj); + // success + return 1; +} + +static +int py_float_to(PyObject *floatobj, double & val){ + if (!PyFloat_Check(floatobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a float"); + return 0; + } + val = PyFloat_AsDouble(floatobj); + if (PyErr_Occurred()){ + return 0; + } + // success + return 1; +} + + +static +int py_float_to(PyObject *floatobj, float & val){ + double db; + int status = py_float_to(floatobj, db); + if (status) + val = db; + return status; +} + + static int py_bool_to(PyObject *boolobj, bool & val){ if (!PyBool_Check(boolobj)) { @@ -78,8 +181,18 @@ PyObject* py_bool_from(bool val){ } static -PyObject* py_int_from(int val){ - return PyInt_FromLong(val); +PyObject* py_int_from(const long long & val){ + return PyLong_FromLongLong(val); +} + +static +PyObject* py_int_from(void * addr){ + return PyLong_FromVoidPtr(addr); +} + +static +PyObject* py_float_from(const double& val) { + return PyFloat_FromDouble(val); } // casting diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index b5edd2c..7aacfde 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace extra{ using namespace llvm; @@ -234,3 +235,108 @@ llvm::ExecutionEngine* ExecutionEngine_createJIT( PyFile_WriteString(ErrorStr.c_str(), errout); return ee; } + +static +llvm::GenericValue* GenericValue_CreateInt(llvm::Type* Ty, unsigned long long N, + bool IsSigned) +{ + // Shamelessly copied from LLVM + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->IntVal = llvm::APInt(Ty->getIntegerBitWidth(), N, IsSigned); + return GenVal; +} + +static +llvm::GenericValue* GenericValue_CreateFloat(float Val) +{ + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->FloatVal = Val; + return GenVal; +} + +static +llvm::GenericValue* GenericValue_CreateDouble(double Val) +{ + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->DoubleVal = Val; + return GenVal; +} + +static +llvm::GenericValue* GenericValue_CreatePointer(void * Ptr) +{ + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->PointerVal = Ptr; + return GenVal; +} + +static +unsigned GenericValue_ValueIntWidth(llvm::GenericValue *GenValRef) +{ + return GenValRef->IntVal.getBitWidth(); +} + +static +unsigned long long GenericValue_ToUnsignedInt(llvm::GenericValue* GenVal) +{ + return GenVal->IntVal.getZExtValue(); +} + + +static +long long GenericValue_ToSignedInt(llvm::GenericValue* GenVal) +{ + return GenVal->IntVal.getSExtValue(); +} + +static +void* GenericValue_ToPointer(llvm::GenericValue* GenVal) +{ + return GenVal->PointerVal; +} + +static +double GenericValue_ToFloat(llvm::GenericValue* GenVal, llvm::Type* Ty) +{ + switch (Ty->getTypeID()) { + case llvm::Type::FloatTyID: + return GenVal->FloatVal; + default: + // Behavior undefined if type is not a float or a double + return GenVal->DoubleVal; + } +} + +static +PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE, + llvm::Function* Fn, PyObject* Args) +{ + using namespace llvm; + const char * GVN = "llvm::GenericValue"; + if (!PyTuple_Check(Args)) { + PyErr_SetString(PyExc_TypeError, "Expect a tuple of args."); + return NULL; + } + std::vector vec_args; + Py_ssize_t nargs = PyTuple_Size(Args); + vec_args.reserve(nargs); + for (Py_ssize_t i = 0; i < nargs; ++i) { + PyObject* obj = PyTuple_GetItem(Args, i); + if (!obj) { + PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?"); + return NULL; + } + + GenericValue* gv = static_cast( + PyCapsule_GetPointer(obj, GVN)); + + if (!gv) { + return NULL; + } + vec_args.push_back(*gv); + } + + GenericValue ret = EE->runFunction(Fn, vec_args); + return pycapsule_new(new GenericValue(ret), GVN); +} + diff --git a/newbinding/src/ExecutionEngine.py b/newbinding/src/ExecutionEngine.py index 0fbe387..5a95a16 100644 --- a/newbinding/src/ExecutionEngine.py +++ b/newbinding/src/ExecutionEngine.py @@ -4,6 +4,11 @@ from Module import Module from JITMemoryManager import JITMemoryManager from CodeGen import CodeGenOpt, Reloc, CodeModel from DataLayout import DataLayout +from Value import Function, GlobalValue, BasicBlock, Constant +from GlobalVariable import GlobalVariable +from MachineCodeInfo import MachineCodeInfo +from GenericValue import GenericValue +from Type import Type ExecutionEngine = llvm.Class() @@ -32,3 +37,58 @@ class ExecutionEngine: addModule = Method(Void, ptr(Module)) getDataLayout = Method(const(ownedptr(DataLayout))) removeModule = Method(cast(Bool, bool), ptr(Module)) + + FindFunctionNamed = Method(ptr(Function), cast(str, ConstCharPtr)) + getPointerToNamedFunction = Method(cast(VoidPtr, int), + cast(str, StdString), + cast(bool, Bool)).require_only(1) + + runStaticConstructorsDestructors = Method(Void, cast(Bool, bool)) + runStaticConstructorsDestructors |= Method(Void, ptr(Module), + cast(Bool, bool)) + + addGlobalMapping = Method(Void, ptr(GlobalValue), cast(int, VoidPtr)) + clearAllGlobalMappings = Method() + clearGlobalMappingsFromModule = Method(Void, ptr(Module)) + updateGlobalMapping = Method(cast(VoidPtr, int), + ptr(GlobalValue), cast(int, VoidPtr)) + + getPointerToGlobalIfAvailable = Method(cast(VoidPtr, int), ptr(GlobalValue)) + getPointerToGlobal = Method(cast(VoidPtr, int), ptr(GlobalValue)) + getPointerToFunction = Method(cast(VoidPtr, int), ptr(Function)) + getPointerToBasicBlock = Method(cast(VoidPtr, int), ptr(BasicBlock)) + getPointerToFunctionOrStub = Method(cast(VoidPtr, int), ptr(Function)) + + runJITOnFunction = Method(Void, ptr(Function), ptr(MachineCodeInfo)) + runJITOnFunction.require_only(1) + + getGlobalValueAtAddress = Method(const(ptr(GlobalValue)), cast(int, VoidPtr)) + + StoreValueToMemory = Method(Void, ref(GenericValue), ptr(GenericValue), + ptr(Type)) + + InitializeMemory = Method(Void, ptr(Constant), cast(int, VoidPtr)) + + recompileAndRelinkFunction = Method(cast(int, VoidPtr), ptr(Function)) + + freeMachineCodeForFunction = Method(Void, ptr(Function)) + getOrEmitGlobalVariable = Method(cast(int, VoidPtr), ptr(GlobalVariable)) + + DisableLazyCompilation = Method(Void, cast(bool, Bool)) + isCompilingLazily = Method(cast(Bool, bool)) + isLazyCompilationDisabled = Method(cast(Bool, bool)) + DisableGVCompilation = Method(Void, cast(bool, Bool)) + isSymbolSearchingDisabled = Method(cast(Bool, bool)) + RegisterTable = Method(Void, ptr(Function), cast(int, VoidPtr)) + DeregisterTable = Method(Void, ptr(Function)) + DeregisterAllTables = Method() + + _runFunction = CustomMethod('ExecutionEngine_RunFunction', + PyObjectPtr, ptr(Function), PyObjectPtr) + + @CustomPythonMethod + def runFunction(self, fn, args): + import capsule + unwrapped = map(capsule.unwrap, args) + return self._runFunction(fn, tuple(unwrapped)) + diff --git a/newbinding/src/GenericValue.py b/newbinding/src/GenericValue.py new file mode 100644 index 0000000..74587ba --- /dev/null +++ b/newbinding/src/GenericValue.py @@ -0,0 +1,34 @@ +from binding import * +from namespace import llvm +from Type import Type + +GenericValue = llvm.Class() + +@GenericValue +class GenericValue: + delete = Destructor() + + def _factory(name, *argtys): + return CustomStaticMethod('GenericValue_' + name, + ptr(GenericValue), *argtys) + + CreateFloat = _factory('CreateFloat', cast(float, Float)) + + CreateDouble = _factory('CreateDouble', cast(float, Float)) + + CreateInt = _factory('CreateInt', ptr(Type), + cast(int, UnsignedLongLong), cast(bool, Bool)) + + CreatePointer = _factory('CreatePointer', cast(int, VoidPtr)) + + def _accessor(name, *argtys): + return CustomMethod('GenericValue_' + name, *argtys) + + valueIntWidth = _accessor('ValueIntWidth', cast(Unsigned, int)) + + toSignedInt = _accessor('ToSignedInt', cast(UnsignedLongLong, int)) + toUnsignedInt = _accessor('ToUnsignedInt', cast(LongLong, int)) + + toFloat = _accessor('ToFloat', cast(Double, float), ptr(Type)) + + toPointer = _accessor('ToPointer', cast(VoidPtr, int)) \ No newline at end of file diff --git a/newbinding/src/MachineCodeInfo.py b/newbinding/src/MachineCodeInfo.py new file mode 100644 index 0000000..5d91e3a --- /dev/null +++ b/newbinding/src/MachineCodeInfo.py @@ -0,0 +1,13 @@ +from binding import * +from namespace import llvm + +MachineCodeInfo = llvm.Class() + +@MachineCodeInfo +class MachineCodeInfo: + _include_ = 'llvm/CodeGen/MachineCodeInfo.h' + setSize = Method(Void, cast(int, Size_t)) + setAddress = Method(Void, cast(int, VoidPtr)) + size = Method(cast(Size_t, int)) + address = Method(cast(VoidPtr, int)) + diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 6cd6e2e..9b392ca 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -44,4 +44,11 @@ class Module: print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) print_.realname = 'print' + @CustomPythonMethod + def __str__(self): + import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os, None) + return os.str() + dropAllReferences = Method() diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 15b5e31..bf51b9d 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -2,6 +2,7 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from raw_ostream import raw_ostream +from StringRef import StringRef Type = llvm.Class() IntegerType = llvm.Class(Type) @@ -52,6 +53,19 @@ class Type: isIntegerTy = Method(cast(Bool, bool)) isIntegerTy |= Method(cast(Bool, bool), cast(int, Unsigned)) + getIntegerBitWidth = Method(cast(Unsigned, int)) + getFunctionParamType = Method(ptr(Type), cast(int, Unsigned)) + getFunctionNumParams = Method(cast(int, Unsigned)) + + isFunctionVarArg = type_checker() + + getStructName = Method(cast(StringRef, str)) + getStructNumElements = Method(cast(Unsigned, int)) + getStructElementType = Method(ptr(Type), cast(int, Unsigned)) + getSequentialElementType = Method(ptr(Type)) + + # Factories + def type_factory(): return StaticMethod(ptr(Type), ref(LLVMContext)) diff --git a/newbinding/test2.py b/newbinding/test2.py index 9492bb6..7902df4 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -28,25 +28,25 @@ print os.str() int1ty = api.Type.getInt1Ty(context) int1ty.dump() -print int1ty.isIntegerTy(1) +assert int1ty.isIntegerTy(1) fnty = api.FunctionType.get(int1ty, False) fnty.dump() -types = [int1ty, api.Type.getIntNTy(context, 21)] -fnty = api.FunctionType.get(int1ty, types, False) +types = [api.Type.getIntNTy(context, 8), api.Type.getIntNTy(context, 32)] +fnty = api.FunctionType.get(api.Type.getIntNTy(context, 8), types, False) print fnty const = m.getOrInsertFunction("foo", fnty) -fn = extra.downcast(const, api.Function) +fn = const._downcast(api.Function) print fn assert fn.hasName() assert 'foo' == fn.getName() fn.setName('bar') assert 'bar' == fn.getName() -assert fn.getReturnType() is int1ty +assert fn.getReturnType().isIntegerTy(8) assert fnty is fn.getFunctionType() @@ -70,13 +70,19 @@ assert bb.getTerminator() is None arg0, arg1 = fn.getArgumentList() print arg0, arg1 -ret = builder.CreateCall(fn, [arg0, arg1], '') +extended = builder.CreateZExt(arg0, arg1.getType()) +result = builder.CreateAdd(extended, arg1) +ret = builder.CreateTrunc(result, fn.getReturnType()) builder.CreateRet(ret) +print arg0.list_use() + print fn errio = StringIO() -ee = api.ExecutionEngine.createJIT(m) +print m + +ee = api.ExecutionEngine.createJIT(m, errio) print ee, errio.getvalue() print ee.getDataLayout().getStringRepresentation() @@ -85,3 +91,24 @@ datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64- assert datalayout_str == str(api.DataLayout.new(datalayout_str)) assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) +fn2 = ee.FindFunctionNamed(fn.getName()) +assert fn2 is fn + +assert ee.getPointerToFunction(fn) +assert ee.getPointerToNamedFunction('printf') + +gv0 = api.GenericValue.CreateInt(arg0.getType(), 12, False) +gv1 = api.GenericValue.CreateInt(arg1.getType(), -32, True) + +assert gv0.valueIntWidth() == arg0.getType().getIntegerBitWidth() +assert gv1.valueIntWidth() == arg1.getType().getIntegerBitWidth() + +assert gv0.toUnsignedInt() == 12 +assert gv1.toSignedInt() == -32 + +gv1 = api.GenericValue.CreateInt(arg1.getType(), 32, False) + +gvR = ee.runFunction(fn, (gv0, gv1)) + +assert 44 == gvR.toUnsignedInt() +