Completed binding for most of ExecutionEngine

This commit is contained in:
Siu Kwan Lam 2013-01-30 18:09:22 -06:00
commit 78f9c9a610
9 changed files with 391 additions and 9 deletions

View file

@ -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'

View file

@ -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

View file

@ -4,6 +4,7 @@
#include <llvm/Function.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>
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<GenericValue> 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<GenericValue*>(
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);
}

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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()

View file

@ -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))

View file

@ -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()