def __init__(self, context, library, fndesc, interp): self.context = context self.library = library self.fndesc = fndesc self.blocks = utils.SortedMap(utils.iteritems(interp.blocks)) self.interp = interp self.call_conv = context.call_conv # Initialize LLVM self.module = self.library.create_ir_module(self.fndesc.unique_name) # Python execution environment (will be available to the compiled # function). self.env = _dynfunc.Environment( globals=self.fndesc.lookup_module().__dict__) # Setup function self.function = context.declare_function(self.module, fndesc) self.entry_block = self.function.append_basic_block('entry') self.builder = Builder.new(self.entry_block) self.call_helper = self.call_conv.init_call_helper(self.builder) # Internal states self.blkmap = {} self.varmap = {} self.firstblk = min(self.blocks.keys()) self.loc = -1 # Subclass initialization self.init()
def __init__(self, func): func = get_function_object(func) code = get_code_object(func) if not code: raise ByteCodeSupportError("%s does not provide its bytecode" % func) if code.co_cellvars: raise ByteCodeSupportError("does not support cellvars") table = utils.SortedMap(ByteCodeIter(code)) labels = set(dis.findlabels(code.co_code)) labels.add(0) try: func_qualname = func.__qualname__ except AttributeError: func_qualname = func.__name__ self._mark_lineno(table, code) super(ByteCode, self).__init__(func=func, func_qualname=func_qualname, argspec=inspect.getargspec(func), filename=code.co_filename, co_names=code.co_names, co_varnames=code.co_varnames, co_consts=code.co_consts, co_freevars=code.co_freevars, table=table, labels=list(sorted(labels)))
def _compute_used_globals(cls, func, table, co_consts, co_names): """ Compute the globals used by the function with the given bytecode table. """ d = {} globs = func.__globals__ builtins = globs['__builtins__'] if isinstance(builtins, ModuleType): builtins = builtins.__dict__ # Look for LOAD_GLOBALs in the bytecode for inst in table.values(): if inst.opname == 'LOAD_GLOBAL': name = co_names[inst.arg] if name not in d: try: value = globs[name] except KeyError: value = builtins[name] d[name] = value # Add globals used by any nested code object for co in co_consts: if isinstance(co, CodeType): subtable = utils.SortedMap(ByteCodeIter(co)) d.update( cls._compute_used_globals(func, subtable, co.co_consts, co.co_names)) return d
def __init__(self, func): func = get_function_object(func) code = get_code_object(func) pysig = utils.pysignature(func) if not code: raise errors.ByteCodeSupportError( "%s does not provide its bytecode" % func) if code.co_cellvars: raise NotImplementedError("cell vars are not supported") table = utils.SortedMap(ByteCodeIter(code)) labels = set(dis.findlabels(code.co_code)) labels.add(0) try: func_qualname = func.__qualname__ except AttributeError: func_qualname = func.__name__ self._mark_lineno(table, code) super(ByteCode, self).__init__(func=func, func_qualname=func_qualname, is_generator=inspect.isgeneratorfunction(func), pysig=pysig, filename=code.co_filename, co_names=code.co_names, co_varnames=code.co_varnames, co_consts=code.co_consts, co_freevars=code.co_freevars, table=table, labels=list(sorted(labels)))
def describe_function(interp, typemap, restype, calltypes): fname, pymod, doc, args, kws = _describe(interp) native = True sortedblocks = utils.SortedMap(utils.dict_iteritems(interp.blocks)) fd = FunctionDescriptor(native, pymod, fname, doc, sortedblocks, typemap, restype, calltypes, args, kws) return fd
def make_loop_bytecode(bytecode, loop, args, returns): # Add return None co_consts = tuple(bytecode.co_consts) if None not in co_consts: co_consts += (None, ) if returns: for out in returns: # Load output loadfast = ByteCodeInst.get(loop[-1].next, "LOAD_FAST", bytecode.co_varnames.index(out)) loadfast.lineno = loop[-1].lineno loop.append(loadfast) # Build tuple buildtuple = ByteCodeInst.get(loop[-1].next, "BUILD_TUPLE", len(returns)) buildtuple.lineno = loop[-1].lineno loop.append(buildtuple) else: # Load None load_none = ByteCodeInst.get(loop[-1].next, "LOAD_CONST", co_consts.index(None)) load_none.lineno = loop[-1].lineno loop.append(load_none) # Return TOS return_value = ByteCodeInst.get(loop[-1].next, "RETURN_VALUE", 0) return_value.lineno = loop[-1].lineno loop.append(return_value) # Function name loop_qualname = bytecode.func_qualname + ".__numba__loop%d__" % loop[ 0].offset # Argspec argspectype = type(bytecode.argspec) argspec = argspectype(args=args, varargs=(), keywords=(), defaults=()) # Code table codetable = utils.SortedMap((i.offset, i) for i in loop) # Custom bytecode object lbc = CustomByteCode( func=bytecode.func, func_qualname=loop_qualname, # Enforced in separate_loops() is_generator=False, argspec=argspec, filename=bytecode.filename, co_names=bytecode.co_names, co_varnames=bytecode.co_varnames, co_consts=co_consts, co_freevars=bytecode.co_freevars, table=codetable, labels=bytecode.labels) return lbc
def describe_pyfunction(interp): fname, pymod, doc, args, kws = _describe(interp) defdict = lambda: defaultdict(lambda: types.pyobject) typemap = defdict() restype = types.pyobject calltypes = defdict() native = False sortedblocks = utils.SortedMap(utils.dict_iteritems(interp.blocks)) fd = FunctionDescriptor(native, pymod, fname, doc, sortedblocks, typemap, restype, calltypes, args, kws) return fd
def lift_loop(bytecode, dispatcher_factory): """Lift the top-level loops. Returns (outer, loops) ------------------------ * outer: ByteCode of a copy of the loop-less function. * loops: a list of ByteCode of the loops. """ outer = [] loops = [] separate_loops(bytecode, outer, loops) # Discover variables references outer_rds, outer_wrs = find_varnames_uses(bytecode, outer) outer_wrs |= set(bytecode.argspec.args) dispatchers = [] outerlabels = set(bytecode.labels) outernames = list(bytecode.co_names) for loop in loops: args, rets = discover_args_and_returns(bytecode, loop, outer_rds, outer_wrs) if rets: # Cannot deal with loop that write to variables used in outer body # Put the loop back into the outer function outer = stitch_instructions(outer, loop) # Recompute read-write variable set wrs, rds = find_varnames_uses(bytecode, loop) outer_wrs |= wrs outer_rds |= rds else: disp = insert_loop_call(bytecode, loop, args, outer, outerlabels, outernames, dispatcher_factory) dispatchers.append(disp) # Build outer bytecode codetable = utils.SortedMap((i.offset, i) for i in outer) outerbc = CustomByteCode(func=bytecode.func, func_qualname=bytecode.func_qualname, argspec=bytecode.argspec, filename=bytecode.filename, co_names=outernames, co_varnames=bytecode.co_varnames, co_consts=bytecode.co_consts, co_freevars=bytecode.co_freevars, table=codetable, labels=outerlabels & set(codetable.keys())) return outerbc, dispatchers
def lift_loop(bytecode, dispatcher_factory): """Lift the top-level loops. Returns (outer, loops) ------------------------ * outer: ByteCode of a copy of the loop-less function. * loops: a list of ByteCode of the loops. """ outer = [] loops = [] # Discover variables references outer_rds, outer_wrs = find_varnames_uses(bytecode, iter(bytecode)) # Separate loops and outer separate_loops(bytecode, outer, loops) # Prepend arguments as negative bytecode offset for a in bytecode.pysig.parameters: outer_wrs[a] = [-1] + outer_wrs[a] dispatchers = [] outerlabels = set(bytecode.labels) outernames = list(bytecode.co_names) for loop in loops: args, rets = discover_args_and_returns(bytecode, loop, outer_rds, outer_wrs) disp = insert_loop_call(bytecode, loop, args, outer, outerlabels, rets, dispatcher_factory) dispatchers.append(disp) # Build outer bytecode codetable = utils.SortedMap((i.offset, i) for i in outer) outerbc = CustomByteCode(func=bytecode.func, func_qualname=bytecode.func_qualname, is_generator=bytecode.is_generator, pysig=bytecode.pysig, filename=bytecode.filename, co_names=outernames, co_varnames=bytecode.co_varnames, co_consts=bytecode.co_consts, co_freevars=bytecode.co_freevars, table=codetable, labels=outerlabels & set(codetable.keys())) return outerbc, dispatchers
def make_loop_bytecode(bytecode, loop, args): # Add return None co_consts = tuple(bytecode.co_consts) if None not in co_consts: co_consts += (None, ) # Load None load_none = ByteCodeInst.get(loop[-1].next, "LOAD_CONST", co_consts.index(None)) load_none.lineno = loop[-1].lineno loop.append(load_none) # Return None return_value = ByteCodeInst.get(loop[-1].next, "RETURN_VALUE", 0) return_value.lineno = loop[-1].lineno loop.append(return_value) # Function name loop_qualname = bytecode.func_qualname + ".__numba__loop%d__" % loop[ 0].offset # Argspec argspectype = type(bytecode.argspec) argspec = argspectype(args=args, varargs=(), keywords=(), defaults=()) # Code table codetable = utils.SortedMap((i.offset, i) for i in loop) # Custom bytecode object lbc = CustomByteCode(func=bytecode.func, func_qualname=loop_qualname, argspec=argspec, filename=bytecode.filename, co_names=bytecode.co_names, co_varnames=bytecode.co_varnames, co_consts=co_consts, co_freevars=bytecode.co_freevars, table=codetable, labels=bytecode.labels) return lbc
def _from_python_function(cls, interp, typemap, restype, calltypes, native, mangler=None): (qualname, unique_name, modname, doc, args, kws, func_globals) = cls._get_function_info(interp) sortedblocks = utils.SortedMap(utils.dict_iteritems(interp.blocks)) self = cls(native, modname, qualname, unique_name, doc, sortedblocks, typemap, restype, calltypes, args, kws, mangler=mangler, globals=func_globals) return self