from ctypes import c_bool, c_int, c_size_t, Structure, byref from collections import namedtuple from enum import IntFlag from llvmlite.binding import ffi _prunestats = namedtuple('PruneStats', ('basicblock diamond fanout fanout_raise')) class PruneStats(_prunestats): """ Holds statistics from reference count pruning. """ def __add__(self, other): if not isinstance(other, PruneStats): msg = 'PruneStats can only be added to another PruneStats, got {}.' raise TypeError(msg.format(type(other))) return PruneStats(self.basicblock + other.basicblock, self.diamond + other.diamond, self.fanout + other.fanout, self.fanout_raise + other.fanout_raise) def __sub__(self, other): if not isinstance(other, PruneStats): msg = ('PruneStats can only be subtracted from another PruneStats, ' 'got {}.') raise TypeError(msg.format(type(other))) return PruneStats(self.basicblock - other.basicblock, self.diamond - other.diamond, self.fanout - other.fanout, self.fanout_raise - other.fanout_raise) class _c_PruneStats(Structure): _fields_ = [ ('basicblock', c_size_t), ('diamond', c_size_t), ('fanout', c_size_t), ('fanout_raise', c_size_t)] def dump_refprune_stats(printout=False): """ Returns a namedtuple containing the current values for the refop pruning statistics. If kwarg `printout` is True the stats are printed to stderr, default is False. """ stats = _c_PruneStats(0, 0, 0, 0) do_print = c_bool(printout) ffi.lib.LLVMPY_DumpRefPruneStats(byref(stats), do_print) return PruneStats(stats.basicblock, stats.diamond, stats.fanout, stats.fanout_raise) def set_time_passes(enable): """Enable or disable the pass timers. Parameters ---------- enable : bool Set to True to enable the pass timers. Set to False to disable the pass timers. """ ffi.lib.LLVMPY_SetTimePasses(c_bool(enable)) def report_and_reset_timings(): """Returns the pass timings report and resets the LLVM internal timers. Pass timers are enabled by ``set_time_passes()``. If the timers are not enabled, this function will return an empty string. Returns ------- res : str LLVM generated timing report. """ with ffi.OutputString() as buf: ffi.lib.LLVMPY_ReportAndResetTimings(buf) return str(buf) def create_module_pass_manager(): return ModulePassManager() def create_function_pass_manager(module): return FunctionPassManager(module) class RefPruneSubpasses(IntFlag): PER_BB = 0b0001 # noqa: E221 DIAMOND = 0b0010 # noqa: E221 FANOUT = 0b0100 # noqa: E221 FANOUT_RAISE = 0b1000 ALL = PER_BB | DIAMOND | FANOUT | FANOUT_RAISE class PassManager(ffi.ObjectRef): """PassManager """ def _dispose(self): self._capi.LLVMPY_DisposePassManager(self) def add_constant_merge_pass(self): """See http://llvm.org/docs/Passes.html#constmerge-merge-duplicate-global-constants.""" # noqa E501 ffi.lib.LLVMPY_AddConstantMergePass(self) def add_dead_arg_elimination_pass(self): """See http://llvm.org/docs/Passes.html#deadargelim-dead-argument-elimination.""" # noqa E501 ffi.lib.LLVMPY_AddDeadArgEliminationPass(self) def add_function_attrs_pass(self): """See http://llvm.org/docs/Passes.html#functionattrs-deduce-function-attributes.""" # noqa E501 ffi.lib.LLVMPY_AddFunctionAttrsPass(self) def add_function_inlining_pass(self, threshold): """See http://llvm.org/docs/Passes.html#inline-function-integration-inlining.""" # noqa E501 ffi.lib.LLVMPY_AddFunctionInliningPass(self, threshold) def add_global_dce_pass(self): """See http://llvm.org/docs/Passes.html#globaldce-dead-global-elimination.""" # noqa E501 ffi.lib.LLVMPY_AddGlobalDCEPass(self) def add_global_optimizer_pass(self): """See http://llvm.org/docs/Passes.html#globalopt-global-variable-optimizer.""" # noqa E501 ffi.lib.LLVMPY_AddGlobalOptimizerPass(self) def add_ipsccp_pass(self): """See http://llvm.org/docs/Passes.html#ipsccp-interprocedural-sparse-conditional-constant-propagation.""" # noqa E501 ffi.lib.LLVMPY_AddIPSCCPPass(self) def add_dead_code_elimination_pass(self): """See http://llvm.org/docs/Passes.html#dce-dead-code-elimination.""" ffi.lib.LLVMPY_AddDeadCodeEliminationPass(self) def add_cfg_simplification_pass(self): """See http://llvm.org/docs/Passes.html#simplifycfg-simplify-the-cfg.""" ffi.lib.LLVMPY_AddCFGSimplificationPass(self) def add_gvn_pass(self): """See http://llvm.org/docs/Passes.html#gvn-global-value-numbering.""" ffi.lib.LLVMPY_AddGVNPass(self) def add_instruction_combining_pass(self): """See http://llvm.org/docs/Passes.html#passes-instcombine.""" ffi.lib.LLVMPY_AddInstructionCombiningPass(self) def add_licm_pass(self): """See http://llvm.org/docs/Passes.html#licm-loop-invariant-code-motion.""" # noqa E501 ffi.lib.LLVMPY_AddLICMPass(self) def add_sccp_pass(self): """See http://llvm.org/docs/Passes.html#sccp-sparse-conditional-constant-propagation.""" # noqa E501 ffi.lib.LLVMPY_AddSCCPPass(self) def add_sroa_pass(self): """See http://llvm.org/docs/Passes.html#scalarrepl-scalar-replacement-of-aggregates-dt. Note that this pass corresponds to the ``opt -sroa`` command-line option, despite the link above.""" # noqa E501 ffi.lib.LLVMPY_AddSROAPass(self) def add_type_based_alias_analysis_pass(self): ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass(self) def add_basic_alias_analysis_pass(self): """See http://llvm.org/docs/AliasAnalysis.html#the-basicaa-pass.""" ffi.lib.LLVMPY_AddBasicAliasAnalysisPass(self) def add_loop_rotate_pass(self): """http://llvm.org/docs/Passes.html#loop-rotate-rotate-loops.""" ffi.lib.LLVMPY_LLVMAddLoopRotatePass(self) # Non-standard LLVM passes def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL, subgraph_limit=1000): """Add Numba specific Reference count pruning pass. Parameters ---------- subpasses_flags : RefPruneSubpasses A bitmask to control the subpasses to be enabled. subgraph_limit : int Limit the fanout pruners to working on a subgraph no bigger than this number of basic-blocks to avoid spending too much time in very large graphs. Default is 1000. Subject to change in future versions. """ iflags = RefPruneSubpasses(subpasses_flags) ffi.lib.LLVMPY_AddRefPrunePass(self, iflags, subgraph_limit) class ModulePassManager(PassManager): def __init__(self, ptr=None): if ptr is None: ptr = ffi.lib.LLVMPY_CreatePassManager() PassManager.__init__(self, ptr) def run(self, module): """ Run optimization passes on the given module. """ return ffi.lib.LLVMPY_RunPassManager(self, module) class FunctionPassManager(PassManager): def __init__(self, module): ptr = ffi.lib.LLVMPY_CreateFunctionPassManager(module) self._module = module module._owned = True PassManager.__init__(self, ptr) def initialize(self): """ Initialize the FunctionPassManager. Returns True if it produced any changes (?). """ return ffi.lib.LLVMPY_InitializeFunctionPassManager(self) def finalize(self): """ Finalize the FunctionPassManager. Returns True if it produced any changes (?). """ return ffi.lib.LLVMPY_FinalizeFunctionPassManager(self) def run(self, function): """ Run optimization passes on the given function. """ return ffi.lib.LLVMPY_RunFunctionPassManager(self, function) # ============================================================================ # FFI ffi.lib.LLVMPY_CreatePassManager.restype = ffi.LLVMPassManagerRef ffi.lib.LLVMPY_CreateFunctionPassManager.argtypes = [ffi.LLVMModuleRef] ffi.lib.LLVMPY_CreateFunctionPassManager.restype = ffi.LLVMPassManagerRef ffi.lib.LLVMPY_DisposePassManager.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_RunPassManager.argtypes = [ffi.LLVMPassManagerRef, ffi.LLVMModuleRef] ffi.lib.LLVMPY_RunPassManager.restype = c_bool ffi.lib.LLVMPY_InitializeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_InitializeFunctionPassManager.restype = c_bool ffi.lib.LLVMPY_FinalizeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_FinalizeFunctionPassManager.restype = c_bool ffi.lib.LLVMPY_RunFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef, ffi.LLVMValueRef] ffi.lib.LLVMPY_RunFunctionPassManager.restype = c_bool ffi.lib.LLVMPY_AddConstantMergePass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddDeadArgEliminationPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddFunctionAttrsPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddFunctionInliningPass.argtypes = [ ffi.LLVMPassManagerRef, c_int] ffi.lib.LLVMPY_AddGlobalDCEPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddGlobalOptimizerPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddIPSCCPPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddDeadCodeEliminationPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddCFGSimplificationPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddGVNPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddInstructionCombiningPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddLICMPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddSCCPPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddSROAPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddBasicAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddRefPrunePass.argtypes = [ffi.LLVMPassManagerRef, c_int, c_size_t]