From 6f532f164a1fab9f7a49cc38b60e89ea40315ca7 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 9 May 2013 16:03:31 -0500 Subject: [PATCH] Working on full opcode coverage and support for exception control flow. --- llpython/byte_control.py | 25 +++++++++++++++---- llpython/byte_flow.py | 49 +++++++++++++++++++++++++++---------- llpython/byte_translator.py | 2 +- llpython/opcode_util.py | 8 +++--- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/llpython/byte_control.py b/llpython/byte_control.py index acd5a41..5aec6be 100644 --- a/llpython/byte_control.py +++ b/llpython/byte_control.py @@ -33,7 +33,7 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BasicBlockVisitor): self.block_list = list(blocks.keys()) self.block_list.sort() self.cfg = ControlFlowGraph() - self.loop_stack = [] + self.control_stack = [] for block in self.block_list: self.cfg.add_block(block, blocks[block]) @@ -43,7 +43,7 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BasicBlockVisitor): self.cfg.compute_dataflow() self.cfg.update_for_ssa() ret_val = self.cfg - del self.loop_stack + del self.control_stack del self.cfg del self.block_list del self.blocks @@ -70,7 +70,7 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BasicBlockVisitor): elif op in opcode.hasjrel: self.cfg.add_edge(block, i + arg + 3) elif opname == 'BREAK_LOOP': - loop_i, _, loop_arg = self.loop_stack[-1] + loop_i, _, loop_arg = self.control_stack[-1] self.cfg.add_edge(block, loop_i + loop_arg + 3) elif opname != 'RETURN_VALUE': self.cfg.add_edge(block, self._get_next_block(block)) @@ -87,13 +87,28 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BasicBlockVisitor): return super(ControlFlowBuilder, self).op_STORE_FAST(i, op, arg, *args, **kws) + def op_SETUP_EXCEPT (self, i, op, arg, *args, **kws): + self.control_stack.append((i, op, arg)) + return super(ControlFlowBuilder, self).op_SETUP_EXCEPT(i, op, arg, + *args, **kws) + + def op_SETUP_FINALLY (self, i, op, arg, *args, **kws): + self.control_stack.append((i, op, arg)) + return super(ControlFlowBuilder, self).op_SETUP_FINALLY(i, op, arg, + *args, **kws) + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): - self.loop_stack.append((i, op, arg)) + self.control_stack.append((i, op, arg)) return super(ControlFlowBuilder, self).op_SETUP_LOOP(i, op, arg, *args, **kws) + def op_SETUP_WITH (self, i, op, arg, *args, **kws): + self.control_stack.append((i, op, arg)) + return super(ControlFlowBuilder, self).op_SETUP_WITH(i, op, arg, *args, + **kws) + def op_POP_BLOCK (self, i, op, arg, *args, **kws): - self.loop_stack.pop() + self.control_stack.pop() return super(ControlFlowBuilder, self).op_POP_BLOCK(i, op, arg, *args, **kws) diff --git a/llpython/byte_flow.py b/llpython/byte_flow.py index c86c6d1..a5abd9f 100644 --- a/llpython/byte_flow.py +++ b/llpython/byte_flow.py @@ -128,7 +128,7 @@ class BytecodeFlowBuilder (BasicBlockVisitor): op_CALL_FUNCTION_VAR = _op op_CALL_FUNCTION_VAR_KW = _op op_COMPARE_OP = _op - #op_CONTINUE_LOOP = _op + #op_CONTINUE_LOOP = _not_implemented op_DELETE_ATTR = _op op_DELETE_FAST = _op op_DELETE_GLOBAL = _op @@ -142,9 +142,14 @@ class BytecodeFlowBuilder (BasicBlockVisitor): def op_DUP_TOPX (self, i, op, arg): self.stack += self.stack[-arg:] - #op_END_FINALLY = _op + #op_DUP_TOP_TWO = _not_implemented + #op_END_FINALLY = _not_implemented op_EXEC_STMT = _op - #op_EXTENDED_ARG = _op + + def op_EXTENDED_ARG (self, i, op, arg): + raise ValueError("Unexpected EXTENDED_ARG opcode at index %d (should " + "be removed by itercode)." % i) + op_FOR_ITER = _op op_GET_ITER = _op @@ -175,15 +180,26 @@ class BytecodeFlowBuilder (BasicBlockVisitor): op_JUMP_FORWARD = _op def op_JUMP_IF_FALSE (self, i, op, arg): - opname, _, _, _ = self.opmap[op] - ret_val = (i, op, opname, arg, [self.stack[-1]]) + ret_val = i, op, self.opnames[op], arg, [self.stack[-1]] self.block.append(ret_val) return ret_val + #op_JUMP_IF_FALSE_OR_POP = _not_implemented op_JUMP_IF_TRUE = op_JUMP_IF_FALSE - op_LIST_APPEND = _op + #op_JUMP_IF_TRUE_OR_POP = op_JUMP_IF_FALSE_OR_POP + + def op_LIST_APPEND (self, i, op, arg): + '''This method is used for both LIST_APPEND, and SET_ADD + opcodes.''' + elem = self.stack.pop() + container = self.stack[-arg] + ret_val = i, op, self.opnames[op], arg, [container, elem] + self.block.append(ret_val) + return ret_val + op_LOAD_ATTR = _op - op_LOAD_CLOSURE = _op + #op_LOAD_BUILD_CLASS = _not_implemented + #op_LOAD_CLOSURE = _not_implemented op_LOAD_CONST = _op op_LOAD_DEREF = _op op_LOAD_FAST = _op @@ -219,19 +235,24 @@ class BytecodeFlowBuilder (BasicBlockVisitor): def op_ROT_TWO (self, i, op, arg): self.stack[-2:] = (self.stack[-1], self.stack[-2]) - #op_SETUP_EXCEPT = _op - #op_SETUP_FINALLY = _op + #op_SETUP_EXCEPT = _not_implemented + #op_SETUP_FINALLY = _not_implemented def op_SETUP_LOOP (self, i, op, arg): self.loop_stack.append((i, op, arg)) - self.block.append((i, op, self.opnames[op], arg, [])) + ret_val = i, op, self.opnames[op], arg, [] + self.block.append(ret_val) + return ret_val + #op_SETUP_WITH = _not_implemented + op_SET_ADD = op_LIST_APPEND op_SLICE = _op - #op_STOP_CODE = _op + #op_STOP_CODE = _not_implemented op_STORE_ATTR = _op op_STORE_DEREF = _op op_STORE_FAST = _op op_STORE_GLOBAL = _op + #op_STORE_LOCALS = _not_implemented op_STORE_MAP = _op op_STORE_NAME = _op op_STORE_SLICE = _op @@ -241,8 +262,9 @@ class BytecodeFlowBuilder (BasicBlockVisitor): op_UNARY_NEGATIVE = _op op_UNARY_NOT = _op op_UNARY_POSITIVE = _op - op_UNPACK_SEQUENCE = _op - #op_WITH_CLEANUP = _op + #op_UNPACK_EX = _not_implemented + #op_UNPACK_SEQUENCE = _not_implemented + #op_WITH_CLEANUP = _not_implemented op_YIELD_VALUE = _op # ______________________________________________________________________ @@ -254,6 +276,7 @@ def build_flow (func): cfg = byte_control.build_cfg(func) return BytecodeFlowBuilder().visit_cfg(cfg) + # ______________________________________________________________________ # Main (self-test) routine diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index 9b6d2de..5473f20 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -591,7 +591,7 @@ def llpython_into (llvm_function, **kws): # Main (self-test) routine def main (*args): - from tests import llfuncs, llfunctys + from .tests import llfuncs, llfunctys if not args: args = ('doslice',) elif 'all' in args: diff --git a/llpython/opcode_util.py b/llpython/opcode_util.py index 1de6507..aecdff7 100644 --- a/llpython/opcode_util.py +++ b/llpython/opcode_util.py @@ -34,8 +34,8 @@ OPCODE_MAP = { 'BUILD_CLASS': (3, 1, None), 'BUILD_LIST': (-1, 1, None), 'BUILD_MAP': (-1, 1, None), - 'BUILD_SET': (None, None, None), - 'BUILD_SLICE': (None, None, None), + 'BUILD_SET': (-1, 1, None), + 'BUILD_SLICE': (-1, 1, None), # oparg should only be 2 or 3 'BUILD_TUPLE': (-1, 1, None), 'CALL_FUNCTION': (-2, 1, None), 'CALL_FUNCTION_KW': (-3, 1, None), @@ -57,7 +57,7 @@ OPCODE_MAP = { 'DUP_TOPX': (None, None, None), 'DUP_TOP_TWO': (None, None, None), 'END_FINALLY': (None, None, None), - 'EXEC_STMT': (None, None, None), + 'EXEC_STMT': (3, 0, 1), 'EXTENDED_ARG': (None, None, None), 'FOR_ITER': (1, 1, 1), 'GET_ITER': (1, 1, None), @@ -83,7 +83,7 @@ OPCODE_MAP = { 'JUMP_IF_FALSE_OR_POP': (None, None, None), 'JUMP_IF_TRUE': (1, 1, 1), 'JUMP_IF_TRUE_OR_POP': (None, None, None), - 'LIST_APPEND': (2, 0, 1), + 'LIST_APPEND': (None, None, None), 'LOAD_ATTR': (1, 1, None), 'LOAD_BUILD_CLASS': (None, None, None), 'LOAD_CLOSURE': (None, None, None),