diff --git a/llpython/af_to_api.py b/llpython/af_to_api.py new file mode 100644 index 0000000..8569a46 --- /dev/null +++ b/llpython/af_to_api.py @@ -0,0 +1,239 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# ______________________________________________________________________ +# Module imports + +from __future__ import print_function, division, absolute_import + +import inspect + +import llvm.core as lc + +from . import byte_control +from . import addr_flow +from . import opcode_util +from . import bytetype +from .bytecode_visitor import GenericFlowVisitor + +# ______________________________________________________________________ +# Class definitions + +class AddressFlowToLLVMPyAPICalls(GenericFlowVisitor): + + def __init__(self, _prefix=None, _postfix=None): + if _prefix is not None: + if inspect.isfunction(_prefix): + __prefix = _prefix + else: + def __prefix(self, opname, *opargs): + return _prefix + self.prefix = __prefix + if _postfix is not None: + if inspect.isfunction(_postfix): + __postfix = _postfix + else: + def __postfix(self, opname, *opargs): + return _postfix + self.postfix = __postfix + + def prefix(self, opname, *opargs): + return '' + + def postfix(self, opname, *opargs): + return '' + + def translate_cfg(self, code_obj, cfg, llvm_module=None, **kws): + assert inspect.iscode(code_obj) + self.code_obj = code_obj + self.cfg = cfg + self.target_function_name = kws.get( + 'target_function_name', 'co_%s_%x' % (code_obj.co_name, + id(code_obj))) + if llvm_module is None: + llvm_module = lc.Module.new('lmod_' + self.target_function_name) + self.llvm_module = llvm_module + self.visit(cfg.blocks) + del self.llvm_module + del self.cfg + del self.code_obj + return llvm_module + + def enter_flow_object(self, flow): + super(AddressFlowToLLVMPyAPICalls, self).enter_flow_object(flow) + self.nargs = opcode_util.get_nargs(self.code_obj) + lltype = lc.Type.function(bytetype.l_pyobj_p, + tuple(bytetype.l_pyobj_p + for _ in range(self.nargs))) + self.llvm_function = self.llvm_module.add_function( + lltype, self.target_function_name) + self.llvm_blocks = {} + for block in self.block_list: + if 0 in self.cfg.blocks_reaching[block]: + bb = self.llvm_function.append_basic_block( + 'BLOCK_%d' % (block,)) + self.llvm_blocks[block] = bb + + def exit_flow_object(self, flow): + super(AddressFlowToLLVMPyAPICalls, self).exit_flow_object(flow) + del self.llvm_blocks + del self.llvm_function + + def enter_block(self, block): + ret_val = False + if block in self.llvm_blocks: + self.llvm_block = self.llvm_blocks[block] + self.builder = lc.Builder.new(self.llvm_block) + ret_val = True + return ret_val + + def exit_block(self, block): + # XXX Isn't this really a bug in GenericFlowVisitor.visit()? + if block in self.llvm_blocks: + del self.builder + del self.llvm_block + + def _op(self, i, op, arg, *args, **kws): + return[] + raise NotImplementedError() + + op_BINARY_ADD = _op + op_BINARY_AND = _op + op_BINARY_DIVIDE = _op + op_BINARY_FLOOR_DIVIDE = _op + op_BINARY_LSHIFT = _op + op_BINARY_MODULO = _op + op_BINARY_MULTIPLY = _op + op_BINARY_OR = _op + op_BINARY_POWER = _op + op_BINARY_RSHIFT = _op + op_BINARY_SUBSCR = _op + op_BINARY_SUBTRACT = _op + op_BINARY_TRUE_DIVIDE = _op + op_BINARY_XOR = _op + op_BREAK_LOOP = _op + op_BUILD_CLASS = _op + op_BUILD_LIST = _op + op_BUILD_MAP = _op + op_BUILD_SET = _op + op_BUILD_SLICE = _op + op_BUILD_TUPLE = _op + op_CALL_FUNCTION = _op + op_CALL_FUNCTION_KW = _op + op_CALL_FUNCTION_VAR = _op + op_CALL_FUNCTION_VAR_KW = _op + op_COMPARE_OP = _op + op_CONTINUE_LOOP = _op + op_DELETE_ATTR = _op + op_DELETE_DEREF = _op + op_DELETE_FAST = _op + op_DELETE_GLOBAL = _op + op_DELETE_NAME = _op + op_DELETE_SLICE = _op + op_DELETE_SUBSCR = _op + op_DUP_TOP = _op + op_DUP_TOPX = _op + op_DUP_TOP_TWO = _op + op_END_FINALLY = _op + op_EXEC_STMT = _op + op_EXTENDED_ARG = _op + op_FOR_ITER = _op + op_GET_ITER = _op + op_IMPORT_FROM = _op + op_IMPORT_NAME = _op + op_IMPORT_STAR = _op + op_INPLACE_ADD = _op + op_INPLACE_AND = _op + op_INPLACE_DIVIDE = _op + op_INPLACE_FLOOR_DIVIDE = _op + op_INPLACE_LSHIFT = _op + op_INPLACE_MODULO = _op + op_INPLACE_MULTIPLY = _op + op_INPLACE_OR = _op + op_INPLACE_POWER = _op + op_INPLACE_RSHIFT = _op + op_INPLACE_SUBTRACT = _op + op_INPLACE_TRUE_DIVIDE = _op + op_INPLACE_XOR = _op + op_JUMP_ABSOLUTE = _op + op_JUMP_FORWARD = _op + op_JUMP_IF_FALSE = _op + op_JUMP_IF_FALSE_OR_POP = _op + op_JUMP_IF_TRUE = _op + op_JUMP_IF_TRUE_OR_POP = _op + op_LIST_APPEND = _op + op_LOAD_ATTR = _op + op_LOAD_BUILD_CLASS = _op + op_LOAD_CLOSURE = _op + op_LOAD_CONST = _op + op_LOAD_DEREF = _op + op_LOAD_FAST = _op + op_LOAD_GLOBAL = _op + op_LOAD_LOCALS = _op + op_LOAD_NAME = _op + op_MAKE_CLOSURE = _op + op_MAKE_FUNCTION = _op + op_MAP_ADD = _op + op_NOP = _op + op_POP_BLOCK = _op + op_POP_EXCEPT = _op + op_POP_JUMP_IF_FALSE = _op + op_POP_JUMP_IF_TRUE = _op + op_POP_TOP = _op + op_PRINT_EXPR = _op + op_PRINT_ITEM = _op + op_PRINT_ITEM_TO = _op + op_PRINT_NEWLINE = _op + op_PRINT_NEWLINE_TO = _op + op_RAISE_VARARGS = _op + op_RETURN_VALUE = _op + op_ROT_FOUR = _op + op_ROT_THREE = _op + op_ROT_TWO = _op + op_SETUP_EXCEPT = _op + op_SETUP_FINALLY = _op + op_SETUP_LOOP = _op + op_SETUP_WITH = _op + op_SET_ADD = _op + op_SLICE = _op + op_STOP_CODE = _op + op_STORE_ATTR = _op + op_STORE_DEREF = _op + op_STORE_FAST = _op + op_STORE_GLOBAL = _op + op_STORE_LOCALS = _op + op_STORE_MAP = _op + op_STORE_NAME = _op + op_STORE_SLICE = _op + op_STORE_SUBSCR = _op + op_UNARY_CONVERT = _op + op_UNARY_INVERT = _op + op_UNARY_NEGATIVE = _op + op_UNARY_NOT = _op + op_UNARY_POSITIVE = _op + op_UNPACK_EX = _op + op_UNPACK_SEQUENCE = _op + op_WITH_CLEANUP = _op + op_YIELD_VALUE = _op + +# ______________________________________________________________________ +# Function definition(s) + +def demo_translator(*args, **kws): + def _visit(obj): + if inspect.isfunction(obj): + obj = opcode_util.get_code_object(obj) + print('\n; %s\n; %r' % ('_' * 70, obj)) + cfg = byte_control.ControlFlowBuilder.build_cfg_from_co(obj) + cfg.blocks = addr_flow.AddressFlowBuilder().visit_cfg(cfg) + print(AddressFlowToLLVMPyAPICalls(**kws).translate_cfg(obj, cfg)) + return opcode_util.visit_code_args(_visit, *args) + +# ______________________________________________________________________ +# Main (self-test) routine + +if __name__ == '__main__': + import sys + demo_translator(*sys.argv[1:], _prefix = '_') + +# ______________________________________________________________________ +# End of af_to_api.py diff --git a/llpython/opcode_util.py b/llpython/opcode_util.py index 727e4ce..ce92043 100644 --- a/llpython/opcode_util.py +++ b/llpython/opcode_util.py @@ -280,5 +280,12 @@ def build_basic_blocks (co_obj): labels + [len(co_code)])) return blocks +# ______________________________________________________________________ + +def get_nargs(co_obj): + flags = co_obj.co_flags + return (1 + co_obj.co_argcount + (1 if flags & 4 else 0) + + (1 if flags & 8 else 0)) + # ______________________________________________________________________ # End of opcode_util.py