Adding docstrings for some of llnumba.
This commit is contained in:
parent
99c9a1f204
commit
fe1ba06698
4 changed files with 68 additions and 0 deletions
|
|
@ -11,7 +11,17 @@ from control_flow import ControlFlowGraph
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor):
|
class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor):
|
||||||
|
'''Visitor responsible for traversing a bytecode flow object and
|
||||||
|
building a control flow graph (CFG).
|
||||||
|
|
||||||
|
The primary purpose of this transformation is to create a CFG,
|
||||||
|
which is used by later transformers for dataflow analysis.
|
||||||
|
'''
|
||||||
def visit (self, flow, nargs = 0, *args, **kws):
|
def visit (self, flow, nargs = 0, *args, **kws):
|
||||||
|
'''Given a bytecode flow, and an optional number of arguments,
|
||||||
|
return a :py:class:`numba.llnumba.control_flow.ControlFlowGraph`
|
||||||
|
instance describing the full control flow of the bytecode
|
||||||
|
flow.'''
|
||||||
self.nargs = nargs
|
self.nargs = nargs
|
||||||
ret_val = super(ControlFlowBuilder, self).visit(flow, *args, **kws)
|
ret_val = super(ControlFlowBuilder, self).visit(flow, *args, **kws)
|
||||||
del self.nargs
|
del self.nargs
|
||||||
|
|
@ -73,6 +83,8 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor):
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
def build_cfg (func):
|
def build_cfg (func):
|
||||||
|
'''Given a Python function, create a bytecode flow, visit the flow
|
||||||
|
object, and return a control flow graph.'''
|
||||||
import byte_flow
|
import byte_flow
|
||||||
return ControlFlowBuilder().visit(
|
return ControlFlowBuilder().visit(
|
||||||
byte_flow.build_flow(func),
|
byte_flow.build_flow(func),
|
||||||
|
|
|
||||||
15
byte_flow.py
15
byte_flow.py
|
|
@ -10,6 +10,19 @@ import opcode_util
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
class BytecodeFlowBuilder (BytecodeIterVisitor):
|
class BytecodeFlowBuilder (BytecodeIterVisitor):
|
||||||
|
'''Transforms a bytecode vector into a bytecode "flow tree".
|
||||||
|
|
||||||
|
The flow tree is a Python dictionary, described loosely by the
|
||||||
|
following set of productions:
|
||||||
|
|
||||||
|
* `flow_tree` ``:=`` ``{`` `blocks` ``*`` ``}``
|
||||||
|
* `blocks` ``:=`` `block_index` ``:`` ``[`` `bytecode_tree` ``*`` ``]``
|
||||||
|
* `bytecode_tree` ``:=`` ``(`` `opcode_index` ``,`` `opcode` ``,``
|
||||||
|
`opname` ``,`` `arg` ``,`` ``[`` `bytecode_tree` ``*`` ``]`` ``)``
|
||||||
|
|
||||||
|
The primary purpose of this transformation is to simulate the
|
||||||
|
value stack, removing it and any stack-specific opcodes.'''
|
||||||
|
|
||||||
def __init__ (self, *args, **kws):
|
def __init__ (self, *args, **kws):
|
||||||
super(BytecodeFlowBuilder, self).__init__(*args, **kws)
|
super(BytecodeFlowBuilder, self).__init__(*args, **kws)
|
||||||
om_items = opcode_util.OPCODE_MAP.items()
|
om_items = opcode_util.OPCODE_MAP.items()
|
||||||
|
|
@ -195,6 +208,8 @@ class BytecodeFlowBuilder (BytecodeIterVisitor):
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
def build_flow (func):
|
def build_flow (func):
|
||||||
|
'''Given a Python function, return a bytecode flow tree for that
|
||||||
|
function.'''
|
||||||
return BytecodeFlowBuilder().visit(opcode_util.get_code_object(func))
|
return BytecodeFlowBuilder().visit(opcode_util.get_code_object(func))
|
||||||
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
#! /usr/bin/env python
|
#! /usr/bin/env python
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
'''Defines a bytecode based LLVM translator for llnumba code.
|
||||||
|
'''
|
||||||
|
# ______________________________________________________________________
|
||||||
# Module imports
|
# Module imports
|
||||||
|
|
||||||
import opcode
|
import opcode
|
||||||
|
|
@ -113,7 +116,17 @@ class LLVMCaster (object):
|
||||||
# Class definitions
|
# Class definitions
|
||||||
|
|
||||||
class LLVMTranslator (BytecodeFlowVisitor):
|
class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
|
'''Transformer responsible for visiting a set of bytecode flow
|
||||||
|
trees, emitting LLVM code.
|
||||||
|
|
||||||
|
Unlike other translators in :py:mod:`numba.llnumba`, this
|
||||||
|
incorporates the full transformation chain, starting with
|
||||||
|
:py:class:`numba.llnumba.byte_flow.BytecodeFlowBuilder`, then
|
||||||
|
:py:class:`numba.llnumba.byte_control.ControlFlowBuilder`, and
|
||||||
|
then :py:class:`numba.llnumba.phi_injector.PhiInjector`.'''
|
||||||
|
|
||||||
def __init__ (self, llvm_module = None, *args, **kws):
|
def __init__ (self, llvm_module = None, *args, **kws):
|
||||||
|
'''Constructor for LLVMTranslator.'''
|
||||||
super(LLVMTranslator, self).__init__(*args, **kws)
|
super(LLVMTranslator, self).__init__(*args, **kws)
|
||||||
if llvm_module is None:
|
if llvm_module is None:
|
||||||
llvm_module = lc.Module.new('Translated_Module_%d' % (id(self),))
|
llvm_module = lc.Module.new('Translated_Module_%d' % (id(self),))
|
||||||
|
|
@ -123,6 +136,13 @@ class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
self.phi_injector = PhiInjector()
|
self.phi_injector = PhiInjector()
|
||||||
|
|
||||||
def translate (self, function, llvm_type = None, env = None):
|
def translate (self, function, llvm_type = None, env = None):
|
||||||
|
'''Translate a function to the given LLVM function type.
|
||||||
|
|
||||||
|
If no type is given, then assume the function is of LLVM type
|
||||||
|
"void ()".
|
||||||
|
|
||||||
|
The optional env parameter allows extension of the global
|
||||||
|
environment.'''
|
||||||
if llvm_type is None:
|
if llvm_type is None:
|
||||||
llvm_type = lc.Type.function(lvoid, ())
|
llvm_type = lc.Type.function(lvoid, ())
|
||||||
if env is None:
|
if env is None:
|
||||||
|
|
@ -495,6 +515,8 @@ class LLVMTranslator (BytecodeFlowVisitor):
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
def translate_function (func, lltype, llvm_module = None, **kws):
|
def translate_function (func, lltype, llvm_module = None, **kws):
|
||||||
|
'''Given a function and an LLVM function type, emit LLVM code for
|
||||||
|
that function using a new LLVMTranslator instance.'''
|
||||||
translator = LLVMTranslator(llvm_module)
|
translator = LLVMTranslator(llvm_module)
|
||||||
translator.translate(func, lltype, kws)
|
translator.translate(func, lltype, kws)
|
||||||
return translator
|
return translator
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,23 @@ REF_DEF = def_synth_op('REF_DEF')
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor):
|
class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor):
|
||||||
|
'''Transformer responsible for modifying a bytecode flow, removing
|
||||||
|
LOAD_FAST and STORE_FAST opcodes, and replacing them with a static
|
||||||
|
single assignment (SSA) representation.
|
||||||
|
|
||||||
|
In order to support SSA, PhiInjector adds the following synthetic
|
||||||
|
opcodes to transformed flows:
|
||||||
|
|
||||||
|
* REF_ARG: Specifically reference an incomming argument value.
|
||||||
|
|
||||||
|
* BUILD_PHI: Build a phi node to disambiguate between several
|
||||||
|
possible definitions at a control flow join.
|
||||||
|
|
||||||
|
* DEFINITION: Unique value definition indexed by the "arg" field
|
||||||
|
in the tuple.
|
||||||
|
|
||||||
|
* REF_DEF: Reference a specific value definition.'''
|
||||||
|
|
||||||
def visit_cfg (self, cfg, nargs = 0, *args, **kws):
|
def visit_cfg (self, cfg, nargs = 0, *args, **kws):
|
||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
ret_val = self.visit(cfg.blocks, nargs)
|
ret_val = self.visit(cfg.blocks, nargs)
|
||||||
|
|
@ -105,6 +122,8 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor):
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
def inject_phis (func):
|
def inject_phis (func):
|
||||||
|
'''Given a Python function, return a bytecode flow object that has
|
||||||
|
been transformed by a fresh PhiInjector instance.'''
|
||||||
import byte_control
|
import byte_control
|
||||||
argcount = byte_control.opcode_util.get_code_object(func).co_argcount
|
argcount = byte_control.opcode_util.get_code_object(func).co_argcount
|
||||||
cfg = byte_control.build_cfg(func)
|
cfg = byte_control.build_cfg(func)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue