llvmpy/llpython/addr_flow.py

88 lines
3.1 KiB
Python

#! /usr/bin/env python
# ______________________________________________________________________
# Module imports
from __future__ import absolute_import
from .byte_flow import Instr, BytecodeFlowBuilder, demo_flow_builder
from .opcode_util import build_basic_blocks, itercodeobjs
# ______________________________________________________________________
# Class definition(s)
class AddressFlowBuilder(BytecodeFlowBuilder):
'''
Builds on top of the BytecodeFlowBuilder with two important differences:
* Child nodes are represented by bytecode indices.
* All operations (other than purely stack manipulation operations)
are retained in the block list (as opposed to being nested).
The resulting data structure describes a directed acyclic graph
(DAG) in a similar fashion to BytecodeFlowBuilder:
* `flow_dag` ``:=`` ``{`` `blocks` ``*`` ``}``
* `blocks` ``:=`` `block_index` ``:`` ``[`` `bytecode_tuple` ``*`` ``]``
* `bytecode_tuple` ``:=`` ``(`` `opcode_index` ``,`` `opcode` ``,``
`opname` ``,`` `arg` ``,`` ``[`` `opcode_index` ``*`` ``]`` ``)``
'''
def _visit_op(self, i, op, arg, opname, pops, pushes, appends):
assert pops is not None, ('%s not well defined in opcode_util.'
'OPCODE_MAP' % opname)
if pops:
if pops < 0:
pops = arg - pops - 1
assert pops <= len(self.stack), ("Stack underflow at instruction "
"%d (%s)!" % (i, opname))
stk_args = [stk_arg[0] for stk_arg in self.stack[-pops:]]
del self.stack[-pops:]
else:
stk_args = []
ret_val = Instr(i, op, opname, arg, stk_args)
if pushes:
self.stack.append(ret_val)
self.block.append(ret_val)
return ret_val
def op_IMPORT_FROM (self, i, op, arg):
# References top of stack without popping, so we can't use the
# generic machinery.
opname = self.opmap[op][0]
ret_val = Instr(i, op, opname, arg, [self.stack[-1][0]])
self.stack.append(ret_val)
self.block.append(ret_val)
return ret_val
def op_JUMP_IF_FALSE (self, i, op, arg):
ret_val = Instr(i, op, self.opnames[op], arg, [self.stack[-1][0]])
self.block.append(ret_val)
return ret_val
op_JUMP_IF_TRUE = op_JUMP_IF_FALSE
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 = Instr(i, op, self.opnames[op], arg, [container[0], elem[0]])
self.block.append(ret_val)
return ret_val
op_SET_ADD = op_LIST_APPEND
# ______________________________________________________________________
# Main (self-test) routine
def main(*args):
return demo_flow_builder(AddressFlowBuilder, *args)
# ______________________________________________________________________
if __name__ == "__main__":
import sys
main(*sys.argv[1:])
# ______________________________________________________________________
# End of addr_flow.py