From 9fe9e8eb3949166582cc4a441cbcd38f3fbafaa9 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Fri, 12 Jul 2013 19:38:50 -0500 Subject: [PATCH] Incremental extensions to llpython to better support using the Python C-API. --- llpython/byte_translator.py | 67 ++++++++++++++++++++++++++++++------- llpython/bytetype.py | 24 +++++++++++-- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index bcb2748..a4dc980 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -10,6 +10,7 @@ import opcode import types import logging +from llvm import LLVMException import llvm.core as lc from . import opcode_util @@ -40,6 +41,13 @@ _compare_mapping_sint = {'>':lc.ICMP_SGT, '<=':lc.ICMP_SLE, '!=':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: class LLVMCaster (object): @@ -120,6 +128,37 @@ class LLVMCaster (object): raise NotImplementedError(lkind1, lkind2) 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 @@ -377,11 +416,12 @@ class LLVMTranslator (BytecodeFlowVisitor): raise NotImplementedError("LLVMTranslator.op_BUILD_SLICE") def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): - return args + return [args] def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): fn = args[0] args = args[1:] + argcount = len(args) fn_name = getattr(fn, '__name__', None) if isinstance(fn, (types.FunctionType, types.MethodType)): ret_val = [fn(self.builder, *args)] @@ -421,6 +461,9 @@ class LLVMTranslator (BytecodeFlowVisitor): elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): ret_val = [self.builder.fcmp(_compare_mapping_float[cmp_kind], arg1, arg2)] + elif isinstance(arg1.type, lc.PointerType): + ret_val = [self.builder.icmp(_compare_mapping_ptr[cmp_kind], + arg1, arg2)] else: raise NotImplementedError('Comparison of type %r' % (arg1.type,)) return ret_val @@ -480,17 +523,7 @@ class LLVMTranslator (BytecodeFlowVisitor): raise NotImplementedError("LLVMTranslator.op_LOAD_ATTR") def op_LOAD_CONST (self, i, op, arg, *args, **kws): - py_val = 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 + return [_convert_const(self.code_obj.co_consts[arg])] def op_LOAD_DEREF (self, i, op, arg, *args, **kws): name = self.code_obj.co_freevars[arg] @@ -546,7 +579,15 @@ class LLVMTranslator (BytecodeFlowVisitor): return [self.builder.store(store_val, dest_addr)] 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): raise NotImplementedError("LLVMTranslator.op_UNARY_INVERT") diff --git a/llpython/bytetype.py b/llpython/bytetype.py index 211f3f8..6549133 100644 --- a/llpython/bytetype.py +++ b/llpython/bytetype.py @@ -1,4 +1,5 @@ #! /usr/bin/env python +# -*- coding: utf-8 -*- # ______________________________________________________________________ import ctypes @@ -23,9 +24,10 @@ li8_ptr = lc.Type.pointer(li8) lc_int = lc.Type.int(ctypes.sizeof(ctypes.c_int) * 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_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)) 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,)) 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) +PyBool_FromLong = lc.Type.function(l_pyobj_p, [lc_long]) 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