def op_kernel(self, op): if op not in self.jitted: return op uses = self.func.uses[op] if all(u in self.trees for u in uses): # All our consumers know about us and have us as an argument # in their tree! Delete this op, only the root will perform a # rewrite. self.delete_later.append(op) elif any(u in self.trees for u in uses): # Some consumers have us as a node, but others don't. This # forms a ckernel boundary, so we need to detach ourselves! raise NotImplementedError else: # No consumer has us as an internal node in the kernel tree, we # are a kerneltree root tree = self.trees[op] # out_rank = len(op.type.shape) # tree = tree.adapt(out_rank, llvm_array.C_CONTIGUOUS) ckernel_deferred = tree.make_ckernel_deferred(op.type) # Flatten the tree of args, removing duplicates just # as the kernel tree does. args = [] for arg in op.args[1:]: # Skip op.args[0], the kernel string name for ir_arg, kt_arg in self.arguments[arg]: if ir_arg not in args: args.append(ir_arg) new_op = Op('ckernel', op.type, [ckernel_deferred, args], op.result) new_op.add_metadata({'rank': 0, 'parallel': True}) return new_op
def _from_expr(expr, f, builder, values): if expr.opcode == 'array': result = values[expr] else: # ------------------------------------------------- # Construct args # This is purely for IR readability name = qualified_name(expr.metadata['overload'].func) args = [_from_expr(arg, f, builder, values) for arg in expr.args] args = [Const(name)] + args # ------------------------------------------------- # Construct Op result = Op("kernel", expr.dshape, args) # Copy metadata verbatim assert 'kernel' in expr.metadata assert 'overload' in expr.metadata result.add_metadata(expr.metadata) # ------------------------------------------------- # Emit Op in code stream builder.emit(result) values[expr] = result return result
def op_kernel(self, op): if op not in self.trees: return op uses = self.func.uses[op] if all(u in self.trees for u in uses): # All our consumers know about us and have us as an argument # in their tree! Delete this op, only the root will perform a # rewrite. self.delete_later.append(op) elif any(u in self.trees for u in uses): # Some consumers have us as a node, but others don't. This # forms a ckernel boundary, so we need to detach ourselves! raise NotImplementedError else: # No consumer has us as an internal node in the kernel tree, we # are a kerneltree root tree = self.trees[op] # out_rank = len(op.type.shape) # tree = tree.adapt(out_rank, llvm_array.C_CONTIGUOUS) unbound_ckernel = tree.make_unbound_ckernel(strided=False) # Skip kernel string name, first arg to 'kernel' Operations args = [ir_arg for arg in op.args[1:] for ir_arg, kt_arg in self.arguments[arg]] new_op = Op('ckernel', op.type, [unbound_ckernel, args], op.result) new_op.add_metadata({'rank': 0, 'parallel': True}) return new_op
def op_kernel(self, op): if self.strategies[op] != 'ckernel': return function = op.metadata['kernel'] overload = op.metadata['overload'] func = overload.func polysig = overload.sig monosig = overload.resolved_sig argtypes = datashape.coretypes.Tuple(monosig.argtypes) try: overload = function.best_match('ckernel', argtypes) except datashape.CoercionError: return op impl = overload.func assert monosig == overload.resolved_sig, (monosig, overload.resolved_sig) new_op = Op('ckernel', op.type, [impl, op.args[1:]], op.result) new_op.add_metadata({'rank': 0, 'parallel': True}) return new_op
def _process(self, ty, args=None, result=None, **metadata): if args is None: args = [] assert ty is not None assert isinstance(args, list), args assert not any(arg is None for arg in flatten(args)), args result = Op(op, ty, args, result) if metadata: result.add_metadata(metadata) self._insert_op(result) return result
def op_kernel(self, op): function = op.metadata['kernel'] overload = op.metadata['overload'] func = overload.func polysig = overload.sig monosig = overload.resolved_sig impls = function.find_impls(func, polysig, 'ckernel') if impls: [impl] = impls new_op = Op('ckernel', op.type, [impl, op.args[1:]], op.result) new_op.add_metadata({'rank': 0, 'parallel': True}) return new_op return op
def op_kernel(self, op): function = op.metadata['kernel'] overload = op.metadata['overload'] func = overload.func polysig = overload.sig monosig = overload.resolved_sig argtypes = monosig.argtypes if function.matches('ckernel', argtypes): overload = function.best_match('ckernel', argtypes) impl = overload.func assert monosig == overload.resolved_sig, (monosig, overload.resolved_sig) new_op = Op('ckernel', op.type, [impl, op.args[1:]], op.result) new_op.add_metadata({'rank': 0, 'parallel': True}) return new_op return op
def copy_function(func, temper=None, module=None): """Copy a Function. `temper` may be given to""" temper = temper or make_temper() f = Function(func.name, list(func.argnames), func.type, temper=temper) valuemap = {} lookup = partial(_lookup, module or func.module, f, valuemap) ### Construct new Blocks for block in func.blocks: new_block = Block(temper(block.name), f) valuemap[block] = new_block f.add_block(new_block) ### Construct new Operations for block in func.blocks: new_block = valuemap[block] for op in block.ops: if op.opcode == 'phi': # Phi nodes may be circular, or may simply precede some of # their arguments args = [] else: args = nestedmap(lookup, op.args) new_op = Op(op.opcode, op.type, args, result=temper(op.result), parent=new_block) new_op.add_metadata(op.metadata) # assert new_op.result != op.result valuemap[op] = new_op new_block.append(new_op) for old_op in func.ops: if old_op.opcode == 'phi': new_op = valuemap[old_op] new_op.set_args(nestedmap(lookup, old_op.args)) return f
def insert(self, opcode, *args): type = types.Void if ops.is_void(opcode) else types.Opaque op = Op(opcode, type, list(args)) op.add_metadata({'lineno': self.lineno}) self.builder.emit(op) return op