def _build_ufunc_loop_body(load, store, context, func, builder, arrays, out, offsets, store_offset, signature): elems = load() # Compute status, retval = context.call_conv.call_function(builder, func, signature.return_type, signature.args, elems) # Ignoring error status and store result # Store if out.byref: retval = builder.load(retval) if not cgutils.is_struct(retval.type): retval = context.get_value_as_argument(builder, signature.return_type, retval) store(retval) # increment indices for off, ary in zip(offsets, arrays): builder.store(builder.add(builder.load(off), ary.step), off) builder.store(builder.add(builder.load(store_offset), out.step), store_offset) return status.code
def _build_ufunc_loop_body(load, store, context, func, builder, arrays, out, offsets, store_offset, signature): elems = load() # Compute status, retval = context.call_function(builder, func, signature.return_type, signature.args, elems) # Ignoring error status and store result # Store if out.byref: retval = builder.load(retval) if not cgutils.is_struct(retval.type): retval = context.get_value_as_argument(builder, signature.return_type, retval) store(retval) # increment indices for off, ary in zip(offsets, arrays): builder.store(builder.add(builder.load(off), ary.step), off) builder.store(builder.add(builder.load(store_offset), out.step), store_offset) return status.code
def is_struct_type(self, ty): return cgutils.is_struct(self.get_data_type(ty))
def lower_expr(self, resty, expr): if expr.op == 'binop': return self.lower_binop(resty, expr) elif expr.op == 'inplace_binop': lty = self.typeof(expr.lhs.name) if not lty.mutable: # inplace operators on non-mutable types reuse the same # definition as the corresponding copying operators. return self.lower_binop(resty, expr) elif expr.op == 'unary': val = self.loadvar(expr.value.name) typ = self.typeof(expr.value.name) # Get function signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.fn, signature) # Convert argument to match val = self.context.cast(self.builder, val, typ, signature.args[0]) res = impl(self.builder, [val]) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'call': signature = self.fndesc.calltypes[expr] if isinstance(expr.func, ir.Intrinsic): fnty = expr.func.name castvals = expr.func.args else: fnty = self.typeof(expr.func.name) if expr.kws: # Fold keyword arguments try: pysig = fnty.pysig except AttributeError: raise NotImplementedError("unsupported keyword arguments " "when calling %s" % (fnty,)) ba = pysig.bind(*expr.args, **dict(expr.kws)) assert not ba.kwargs args = ba.args else: args = expr.args argvals = [self.loadvar(a.name) for a in args] argtyps = [self.typeof(a.name) for a in args] castvals = [self.context.cast(self.builder, av, at, ft) for av, at, ft in zip(argvals, argtyps, signature.args)] if isinstance(fnty, types.ExternalFunction): # Handle a named external function fndesc = ExternalFunctionDescriptor( fnty.symbol, fnty.sig.return_type, fnty.sig.args) func = self.context.declare_external_function( cgutils.get_module(self.builder), fndesc) res = self.context.call_external_function( self.builder, func, fndesc.argtypes, castvals) elif isinstance(fnty, types.Method): # Method of objects are handled differently fnobj = self.loadvar(expr.func.name) res = self.context.call_class_method(self.builder, fnobj, signature, castvals) elif isinstance(fnty, types.FunctionPointer): # Handle a C function pointer pointer = fnty.funcptr res = self.context.call_function_pointer(self.builder, pointer, signature, castvals, fnty.cconv) else: if isinstance(signature.return_type, types.Phantom): return self.context.get_dummy_value() # Normal function resolution (for Numba-compiled functions) impl = self.context.get_function(fnty, signature) if signature.recvr: # The "self" object is passed as the function object # for bounded function the_self = self.loadvar(expr.func.name) # Prepend the self reference castvals = [the_self] + castvals res = impl(self.builder, castvals) libs = getattr(impl, "libs", ()) for lib in libs: self.library.add_linking_library(lib) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'pair_first': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) item = self.context.pair_first(self.builder, val, ty) return self.context.get_argument_value(self.builder, ty.first_type, item) elif expr.op == 'pair_second': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) item = self.context.pair_second(self.builder, val, ty) return self.context.get_argument_value(self.builder, ty.second_type, item) elif expr.op in ('getiter', 'iternext'): val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.op, signature) [fty] = signature.args castval = self.context.cast(self.builder, val, ty, fty) res = impl(self.builder, (castval,)) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'exhaust_iter': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) # If we have a heterogenous tuple, we needn't do anything, # and we can't iterate over it anyway. if isinstance(ty, types.Tuple): return val itemty = ty.iterator_type.yield_type tup = self.context.get_constant_undef(resty) pairty = types.Pair(itemty, types.boolean) getiter_sig = typing.signature(ty.iterator_type, ty) getiter_impl = self.context.get_function('getiter', getiter_sig) iternext_sig = typing.signature(pairty, ty.iterator_type) iternext_impl = self.context.get_function('iternext', iternext_sig) iterobj = getiter_impl(self.builder, (val,)) # We call iternext() as many times as desired (`expr.count`). for i in range(expr.count): pair = iternext_impl(self.builder, (iterobj,)) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, self.builder.not_(is_valid)): self.return_exception(ValueError) item = self.context.pair_first(self.builder, pair, pairty) tup = self.builder.insert_value(tup, item, i) # Call iternext() once more to check that the iterator # is exhausted. pair = iternext_impl(self.builder, (iterobj,)) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, is_valid): self.return_exception(ValueError) return tup elif expr.op == "getattr": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) if isinstance(resty, types.BoundFunction): # if we are getting out a method, assume we have typed this # properly and just build a bound function object res = self.context.get_bound_function(self.builder, val, ty) else: impl = self.context.get_attribute(val, ty, expr.attr) if impl is None: # ignore the attribute res = self.context.get_dummy_value() else: res = impl(self.context, self.builder, ty, val, expr.attr) return res elif expr.op == "static_getitem": baseval = self.loadvar(expr.value.name) indexval = self.context.get_constant(types.intp, expr.index) if cgutils.is_struct(baseval.type): # Statically extract the given element from the structure # (structures aren't dynamically indexable). return self.builder.extract_value(baseval, expr.index) else: # Fall back on the generic getitem() implementation # for this type. signature = typing.signature(resty, self.typeof(expr.value.name), types.intp) impl = self.context.get_function("getitem", signature) argvals = (baseval, indexval) res = impl(self.builder, argvals) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == "getitem": baseval = self.loadvar(expr.value.name) indexval = self.loadvar(expr.index.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function("getitem", signature) argvals = (baseval, indexval) argtyps = (self.typeof(expr.value.name), self.typeof(expr.index.name)) castvals = [self.context.cast(self.builder, av, at, ft) for av, at, ft in zip(argvals, argtyps, signature.args)] res = impl(self.builder, castvals) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == "build_tuple": itemvals = [self.loadvar(i.name) for i in expr.items] itemtys = [self.typeof(i.name) for i in expr.items] castvals = [self.context.cast(self.builder, val, fromty, toty) for val, toty, fromty in zip(itemvals, resty, itemtys)] tup = self.context.get_constant_undef(resty) for i in range(len(castvals)): tup = self.builder.insert_value(tup, castvals[i], i) return tup elif expr.op == "cast": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) castval = self.context.cast(self.builder, val, ty, resty) return castval raise NotImplementedError(expr)
def lower_expr(self, resty, expr): if expr.op == 'binop': return self.lower_binop(resty, expr) elif expr.op == 'inplace_binop': lty = self.typeof(expr.lhs.name) if not lty.mutable: # inplace operators on non-mutable types reuse the same # definition as the corresponding copying operators. return self.lower_binop(resty, expr) elif expr.op == 'unary': val = self.loadvar(expr.value.name) typ = self.typeof(expr.value.name) # Get function signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.fn, signature) # Convert argument to match val = self.context.cast(self.builder, val, typ, signature.args[0]) res = impl(self.builder, [val]) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'call': argvals = [self.loadvar(a.name) for a in expr.args] argtyps = [self.typeof(a.name) for a in expr.args] signature = self.fndesc.calltypes[expr] if isinstance(expr.func, ir.Intrinsic): fnty = expr.func.name castvals = expr.func.args else: assert not expr.kws, expr.kws fnty = self.typeof(expr.func.name) castvals = [self.context.cast(self.builder, av, at, ft) for av, at, ft in zip(argvals, argtyps, signature.args)] if isinstance(fnty, types.Method): # Method of objects are handled differently fnobj = self.loadvar(expr.func.name) res = self.context.call_class_method(self.builder, fnobj, signature, castvals) elif isinstance(fnty, types.FunctionPointer): # Handle function pointer pointer = fnty.funcptr res = self.context.call_function_pointer(self.builder, pointer, signature, castvals) elif isinstance(fnty, cffi_support.ExternCFunction): # XXX unused? fndesc = ExternalFunctionDescriptor( fnty.symbol, fnty.restype, fnty.argtypes) func = self.context.declare_external_function( cgutils.get_module(self.builder), fndesc) res = self.context.call_external_function(self.builder, func, fndesc.argtypes, castvals) else: # Normal function resolution impl = self.context.get_function(fnty, signature) if signature.recvr: # The "self" object is passed as the function object # for bounded function the_self = self.loadvar(expr.func.name) # Prepend the self reference castvals = [the_self] + castvals res = impl(self.builder, castvals) libs = getattr(impl, "libs", ()) if libs: self.context.add_libs(libs) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'pair_first': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) item = self.context.pair_first(self.builder, val, ty) return self.context.get_argument_value(self.builder, ty.first_type, item) elif expr.op == 'pair_second': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) item = self.context.pair_second(self.builder, val, ty) return self.context.get_argument_value(self.builder, ty.second_type, item) elif expr.op in ('getiter', 'iternext'): val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.op, signature) [fty] = signature.args castval = self.context.cast(self.builder, val, ty, fty) res = impl(self.builder, (castval,)) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'exhaust_iter': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) # If we have a heterogenous tuple, we needn't do anything, # and we can't iterate over it anyway. if isinstance(ty, types.Tuple): return val itemty = ty.iterator_type.yield_type tup = self.context.get_constant_undef(resty) pairty = types.Pair(itemty, types.boolean) getiter_sig = typing.signature(ty.iterator_type, ty) getiter_impl = self.context.get_function('getiter', getiter_sig) iternext_sig = typing.signature(pairty, ty.iterator_type) iternext_impl = self.context.get_function('iternext', iternext_sig) iterobj = getiter_impl(self.builder, (val,)) excid = self.context.add_exception(ValueError) # We call iternext() as many times as desired (`expr.count`). for i in range(expr.count): pair = iternext_impl(self.builder, (iterobj,)) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, self.builder.not_(is_valid)): self.context.return_user_exc(self.builder, excid) item = self.context.pair_first(self.builder, pair, pairty) tup = self.builder.insert_value(tup, item, i) # Call iternext() once more to check that the iterator # is exhausted. pair = iternext_impl(self.builder, (iterobj,)) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, is_valid): self.context.return_user_exc(self.builder, excid) return tup elif expr.op == "getattr": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) if isinstance(resty, types.BoundFunction): # if we are getting out a method, assume we have typed this # properly and just build a bound function object res = self.context.get_bound_function(self.builder, val, ty) else: impl = self.context.get_attribute(val, ty, expr.attr) if impl is None: # ignore the attribute res = self.context.get_dummy_value() else: res = impl(self.context, self.builder, ty, val, expr.attr) return res elif expr.op == "static_getitem": baseval = self.loadvar(expr.value.name) indexval = self.context.get_constant(types.intp, expr.index) if cgutils.is_struct(baseval.type): # Statically extract the given element from the structure # (structures aren't dynamically indexable). return self.builder.extract_value(baseval, expr.index) else: # Fall back on the generic getitem() implementation # for this type. signature = typing.signature(resty, self.typeof(expr.value.name), types.intp) impl = self.context.get_function("getitem", signature) argvals = (baseval, indexval) res = impl(self.builder, argvals) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == "getitem": baseval = self.loadvar(expr.value.name) indexval = self.loadvar(expr.index.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function("getitem", signature) argvals = (baseval, indexval) argtyps = (self.typeof(expr.value.name), self.typeof(expr.index.name)) castvals = [self.context.cast(self.builder, av, at, ft) for av, at, ft in zip(argvals, argtyps, signature.args)] res = impl(self.builder, castvals) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == "build_tuple": itemvals = [self.loadvar(i.name) for i in expr.items] itemtys = [self.typeof(i.name) for i in expr.items] castvals = [self.context.cast(self.builder, val, fromty, toty) for val, toty, fromty in zip(itemvals, resty, itemtys)] tup = self.context.get_constant_undef(resty) for i in range(len(castvals)): tup = self.builder.insert_value(tup, castvals[i], i) return tup elif expr.op == "cast": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) castval = self.context.cast(self.builder, val, ty, resty) return castval raise NotImplementedError(expr)