Incremental extensions to llpython to better support using the Python C-API.
This commit is contained in:
parent
e4f4d56fe6
commit
9fe9e8eb39
2 changed files with 75 additions and 16 deletions
|
|
@ -10,6 +10,7 @@ import opcode
|
||||||
import types
|
import types
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from llvm import LLVMException
|
||||||
import llvm.core as lc
|
import llvm.core as lc
|
||||||
|
|
||||||
from . import opcode_util
|
from . import opcode_util
|
||||||
|
|
@ -40,6 +41,13 @@ _compare_mapping_sint = {'>':lc.ICMP_SGT,
|
||||||
'<=':lc.ICMP_SLE,
|
'<=':lc.ICMP_SLE,
|
||||||
'!=':lc.ICMP_NE}
|
'!=':lc.ICMP_NE}
|
||||||
|
|
||||||
|
_compare_mapping_ptr = {'>':lc.ICMP_UGT,
|
||||||
|
'<':lc.ICMP_ULT,
|
||||||
|
'==':lc.ICMP_EQ,
|
||||||
|
'>=':lc.ICMP_UGE,
|
||||||
|
'<=':lc.ICMP_ULE,
|
||||||
|
'!=':lc.ICMP_NE}
|
||||||
|
|
||||||
# XXX Stolen from numba.llvm_types:
|
# XXX Stolen from numba.llvm_types:
|
||||||
|
|
||||||
class LLVMCaster (object):
|
class LLVMCaster (object):
|
||||||
|
|
@ -120,6 +128,37 @@ class LLVMCaster (object):
|
||||||
raise NotImplementedError(lkind1, lkind2)
|
raise NotImplementedError(lkind1, lkind2)
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
|
# ______________________________________________________________________
|
||||||
|
|
||||||
|
def _convert_const(py_val):
|
||||||
|
'''Convert a constant Python value into a comparable LLVM
|
||||||
|
constant. Preserves Python values and data structures such as
|
||||||
|
lists, tuples, and None.
|
||||||
|
'''
|
||||||
|
if isinstance(py_val, list):
|
||||||
|
ret_val = [_convert_const(child) for child in py_val]
|
||||||
|
elif isinstance(py_val, tuple):
|
||||||
|
ret_val = tuple(_convert_const(child) for child in py_val)
|
||||||
|
elif isinstance(py_val, int):
|
||||||
|
ret_val = lc.Constant.int(bytetype.lc_int, py_val)
|
||||||
|
elif isinstance(py_val, float):
|
||||||
|
ret_val = lc.Constant.double(py_val)
|
||||||
|
elif py_val == None:
|
||||||
|
ret_val = py_val
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('Constant conversion for %r' % (py_val,))
|
||||||
|
return ret_val
|
||||||
|
|
||||||
|
# ______________________________________________________________________
|
||||||
|
|
||||||
|
def get_or_insert_global_variable(llvm_module, variable_ty, variable_name):
|
||||||
|
try:
|
||||||
|
ret_val = llvm_module.get_global_variable_named(variable_name)
|
||||||
|
# XXX Check LLVM value is of correct type?!
|
||||||
|
except LLVMException:
|
||||||
|
ret_val = llvm_module.add_global_variable(variable_ty, variable_name)
|
||||||
|
return ret_val
|
||||||
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
# Class definitions
|
# Class definitions
|
||||||
|
|
||||||
|
|
@ -377,11 +416,12 @@ class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
raise NotImplementedError("LLVMTranslator.op_BUILD_SLICE")
|
raise NotImplementedError("LLVMTranslator.op_BUILD_SLICE")
|
||||||
|
|
||||||
def op_BUILD_TUPLE (self, i, op, arg, *args, **kws):
|
def op_BUILD_TUPLE (self, i, op, arg, *args, **kws):
|
||||||
return args
|
return [args]
|
||||||
|
|
||||||
def op_CALL_FUNCTION (self, i, op, arg, *args, **kws):
|
def op_CALL_FUNCTION (self, i, op, arg, *args, **kws):
|
||||||
fn = args[0]
|
fn = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
|
argcount = len(args)
|
||||||
fn_name = getattr(fn, '__name__', None)
|
fn_name = getattr(fn, '__name__', None)
|
||||||
if isinstance(fn, (types.FunctionType, types.MethodType)):
|
if isinstance(fn, (types.FunctionType, types.MethodType)):
|
||||||
ret_val = [fn(self.builder, *args)]
|
ret_val = [fn(self.builder, *args)]
|
||||||
|
|
@ -421,6 +461,9 @@ class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE):
|
elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE):
|
||||||
ret_val = [self.builder.fcmp(_compare_mapping_float[cmp_kind],
|
ret_val = [self.builder.fcmp(_compare_mapping_float[cmp_kind],
|
||||||
arg1, arg2)]
|
arg1, arg2)]
|
||||||
|
elif isinstance(arg1.type, lc.PointerType):
|
||||||
|
ret_val = [self.builder.icmp(_compare_mapping_ptr[cmp_kind],
|
||||||
|
arg1, arg2)]
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError('Comparison of type %r' % (arg1.type,))
|
raise NotImplementedError('Comparison of type %r' % (arg1.type,))
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
@ -480,17 +523,7 @@ class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
raise NotImplementedError("LLVMTranslator.op_LOAD_ATTR")
|
raise NotImplementedError("LLVMTranslator.op_LOAD_ATTR")
|
||||||
|
|
||||||
def op_LOAD_CONST (self, i, op, arg, *args, **kws):
|
def op_LOAD_CONST (self, i, op, arg, *args, **kws):
|
||||||
py_val = self.code_obj.co_consts[arg]
|
return [_convert_const(self.code_obj.co_consts[arg])]
|
||||||
if isinstance(py_val, int):
|
|
||||||
ret_val = [lc.Constant.int(bytetype.lc_int, py_val)]
|
|
||||||
elif isinstance(py_val, float):
|
|
||||||
ret_val = [lc.Constant.double(py_val)]
|
|
||||||
elif py_val == None:
|
|
||||||
ret_val = [None]
|
|
||||||
else:
|
|
||||||
raise NotImplementedError('Constant converstion for %r' %
|
|
||||||
(py_val,))
|
|
||||||
return ret_val
|
|
||||||
|
|
||||||
def op_LOAD_DEREF (self, i, op, arg, *args, **kws):
|
def op_LOAD_DEREF (self, i, op, arg, *args, **kws):
|
||||||
name = self.code_obj.co_freevars[arg]
|
name = self.code_obj.co_freevars[arg]
|
||||||
|
|
@ -546,7 +579,15 @@ class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
return [self.builder.store(store_val, dest_addr)]
|
return [self.builder.store(store_val, dest_addr)]
|
||||||
|
|
||||||
def op_UNARY_CONVERT (self, i, op, arg, *args, **kws):
|
def op_UNARY_CONVERT (self, i, op, arg, *args, **kws):
|
||||||
raise NotImplementedError("LLVMTranslator.op_UNARY_CONVERT")
|
var_ty = args[0]
|
||||||
|
if isinstance(var_ty, lc.Type):
|
||||||
|
var_name = var_ty.__name__
|
||||||
|
ret_val = [get_or_insert_global_variable(self.llvm_module, var_ty,
|
||||||
|
var_name)]
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("LLVMTranslator.op_UNARY_CONVERT: %r" %
|
||||||
|
(var_ty,))
|
||||||
|
return ret_val
|
||||||
|
|
||||||
def op_UNARY_INVERT (self, i, op, arg, *args, **kws):
|
def op_UNARY_INVERT (self, i, op, arg, *args, **kws):
|
||||||
raise NotImplementedError("LLVMTranslator.op_UNARY_INVERT")
|
raise NotImplementedError("LLVMTranslator.op_UNARY_INVERT")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#! /usr/bin/env python
|
#! /usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
@ -23,9 +24,10 @@ li8_ptr = lc.Type.pointer(li8)
|
||||||
lc_int = lc.Type.int(ctypes.sizeof(ctypes.c_int) * 8)
|
lc_int = lc.Type.int(ctypes.sizeof(ctypes.c_int) * 8)
|
||||||
lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8)
|
lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8)
|
||||||
|
|
||||||
l_pyobject_head = [lc_size_t, lc.Type.pointer(li32)]
|
l_pyobject_head = [lc_size_t, li8_ptr]
|
||||||
l_pyobject_head_struct = lc.Type.struct(l_pyobject_head)
|
l_pyobject_head_struct = lc.Type.struct(l_pyobject_head)
|
||||||
l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct)
|
l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct)
|
||||||
|
l_pyobj_pp = lc.Type.pointer(l_pyobj_p)
|
||||||
l_pyfunc = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
l_pyfunc = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
|
||||||
strlen = lc.Type.function(lc_size_t, (li8_ptr,))
|
strlen = lc.Type.function(lc_size_t, (li8_ptr,))
|
||||||
|
|
@ -34,10 +36,26 @@ strndup = lc.Type.function(li8_ptr, (li8_ptr, lc_size_t))
|
||||||
malloc = lc.Type.function(li8_ptr, (lc_size_t,))
|
malloc = lc.Type.function(li8_ptr, (lc_size_t,))
|
||||||
free = lc.Type.function(lvoid, (li8_ptr,))
|
free = lc.Type.function(lvoid, (li8_ptr,))
|
||||||
|
|
||||||
Py_BuildValue = lc.Type.function(l_pyobj_p, [li8_ptr], True)
|
|
||||||
PyArg_ParseTuple = lc.Type.function(lc_int, [l_pyobj_p, li8_ptr], True)
|
PyArg_ParseTuple = lc.Type.function(lc_int, [l_pyobj_p, li8_ptr], True)
|
||||||
|
PyBool_FromLong = lc.Type.function(l_pyobj_p, [lc_long])
|
||||||
PyEval_SaveThread = lc.Type.function(li8_ptr, [])
|
PyEval_SaveThread = lc.Type.function(li8_ptr, [])
|
||||||
PyEval_RestoreThread = lc.Type.function(lc.Type.void(), [li8_ptr])
|
PyEval_RestoreThread = lc.Type.function(lvoid, [li8_ptr])
|
||||||
|
PyInt_AsLong = lc.Type.function(lc_long, [l_pyobj_p])
|
||||||
|
PyInt_FromLong = lc.Type.function(l_pyobj_p, [lc_long])
|
||||||
|
PyNumber_Add = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
PyNumber_Divide = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
PyNumber_Multiply = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
PyNumber_Remainder = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
PyNumber_Subtract = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
PyNumber_TrueDivide = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
PyString_Check = lc.Type.function(lc_int, [l_pyobj_p])
|
||||||
|
PyString_CheckExact = lc.Type.function(lc_int, [l_pyobj_p])
|
||||||
|
PyString_Format = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p))
|
||||||
|
Py_BuildValue = lc.Type.function(l_pyobj_p, [li8_ptr], True)
|
||||||
|
Py_DecRef = lc.Type.function(lvoid, [l_pyobj_p])
|
||||||
|
Py_IncRef = lc.Type.function(lvoid, [l_pyobj_p])
|
||||||
|
|
||||||
|
PyInt_Type = li8
|
||||||
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
# End of bytetype.py
|
# End of bytetype.py
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue