Exemplo n.º 1
0
    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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
def insert_allocations(func, env):
    b = Builder(func)

    # IR positions and list of ops
    positions = dict((op, idx) for idx, op in enumerate(func.ops))
    oplist = list(func.ops)

    for op in func.ops:
        if op.opcode == 'ckernel':
            ckernel, args = op.args
            alloc = Op('alloc', op.type, args=[])

            # TODO: Insert alloc in args list of ckernel

            # Replace uses of ckernel with temporary allocation
            op.replace_uses(alloc)
            op.set_args([ckernel, [alloc] + args])

            # Emit allocation before first use
            b.position_before(op)
            b.emit(alloc)

            # Emit deallocation after last use, unless we are returning
            # the result
            idx = max(positions[u] for u in func.uses[alloc])
            last_op = oplist[idx]
            if not last_op.opcode == 'ret':
                b.position_after(last_op)
                dealloc = Op('dealloc', types.Void, [alloc])
                b.emit(dealloc)

    return func, env
Exemplo n.º 7
0
    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
Exemplo n.º 8
0
 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
Exemplo n.º 9
0
 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
Exemplo n.º 10
0
 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
Exemplo n.º 11
0
    def visit_FuncCall(self, node):
        type = self.type
        opcode = node.name.name
        args = self.visits(node.args.exprs) if node.args else []

        if opcode == "list":
            return args
        elif not type and not ops.is_void(opcode):
            error(
                node, "Expected a type for sub-expression "
                "(add a cast or assignment)")
        elif not hasattr(self.builder, opcode):
            if opcode in self.mod.functions:
                func = self.mod.get_function(opcode)
                return self.builder.call(type, func, args)

            # error(node, "No opcode %s" % (opcode,))
            op = Op(opcode, type or types.Opaque, args)
            self.builder.emit(op)
            return op

        buildop = getattr(self.builder, opcode)
        if ops.is_void(opcode):
            return buildop(*args)
        else:
            return buildop(type or types.Opaque, *args)
Exemplo n.º 12
0
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:
            new_op = Op(op.opcode, op.type, nestedmap(lookup, op.args),
                        result=temper(op.result), parent=new_block)
            # assert new_op.result != op.result

            valuemap[op] = new_op
            new_block.append(new_op)

    return f
Exemplo n.º 13
0
def explicit_coercions(func, env=None):
    """
    Turn implicit coercions into explicit conversion operations.
    """
    conversions = {}
    b = Builder(func)

    for op in func.ops:
        if op.opcode != 'kernel':
            continue

        overload = op.metadata['overload']
        signature = overload.resolved_sig
        parameters = signature.parameters[:-1]
        assert len(op.args) - 1 == len(parameters)

        # -------------------------------------------------
        # Identify conversion points

        replacements = {} # { arg : replacement_conversion }
        for arg, param_type in zip(op.args[1:], parameters):
            if arg.type != param_type:
                conversion = conversions.get((arg, param_type))
                if not conversion:
                    conversion = Op('convert', param_type, [arg])
                    b.position_after(arg)
                    b.emit(conversion)
                    conversions[arg, param_type] = conversion

                replacements[arg] = conversion

        # -------------------------------------------------

        op.replace_args(replacements)
Exemplo n.º 14
0
 def ret(self, obj0, **kwds):
     returnType = types.Void
     register = kwds.pop('result', None)
     op = Op('ret', returnType, [obj0], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 15
0
 def alloca(self, returnType, obj0, **kwds):
     assert returnType is not None
     register = kwds.pop('result', None)
     op = Op('alloca', returnType, [obj0], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 16
0
 def bitcast(self, returnType, value0, **kwds):
     assert isinstance(value0, Value)
     assert returnType is not None
     register = kwds.pop('result', None)
     op = Op('bitcast', returnType, [value0], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 17
0
 def exc_catch(self, lst0, **kwds):
     assert isinstance(lst0, list)
     returnType = types.Void
     register = kwds.pop('result', None)
     op = Op('exc_catch', returnType, [lst0], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 18
0
 def print(self, value0, **kwds):
     assert isinstance(value0, Value)
     returnType = types.Void
     register = kwds.pop('result', None)
     op = Op('print', returnType, [value0], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 19
0
 def call_math(self, returnType, obj0, lst0, **kwds):
     assert isinstance(lst0, list)
     assert returnType is not None
     register = kwds.pop('result', None)
     op = Op('call_math', returnType, [obj0, lst0], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 20
0
    def test_combinator(self):
        visitor = SampleVisitor()
        def op_blah(op):
            visitor.recorded.append(op.opcode)

        comb = combine(visitor, {'op_blah': op_blah})
        with self.b.at_front(self.entry):
            self.b.emit(Op('blah', None, []))
        visit(comb, self.f)
        self.eq(visitor.recorded, ['blah', 'mul'])
Exemplo n.º 21
0
 def phi(self, returnType, lst0, lst1, **kwds):
     assert isinstance(lst0, list)
     assert isinstance(lst1, list)
     assert returnType is not None
     register = kwds.pop('result', None)
     op = Op('phi', returnType, [lst0, lst1], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 22
0
 def setfield(self, value0, obj0, value1, **kwds):
     assert isinstance(value0, Value)
     assert isinstance(value1, Value)
     returnType = types.Void
     register = kwds.pop('result', None)
     op = Op('setfield', returnType, [value0, obj0, value1], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 23
0
    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
Exemplo n.º 24
0
 def shufflevector(self, returnType, value0, value1, value2, **kwds):
     assert isinstance(value0, Value)
     assert isinstance(value1, Value)
     assert isinstance(value2, Value)
     assert returnType is not None
     register = kwds.pop('result', None)
     op = Op('shufflevector', returnType, [value0, value1, value2], register, metadata=kwds)
     if config.op_verify:
         verify_op_syntax(op)
     self._insert_op(op)
     return op
Exemplo n.º 25
0
def _build_op(type, args):
    if len(args) == 9:
        argnames = []
        _, dest, _, _, type, _, opname, _, _ = args
    else:
        _, dest, _, _, type, _, opname, _, argnames, _ = args

    if not isinstance(argnames, list):
        argnames = [argnames]

    return Op(opname, type, argnames, dest)
Exemplo n.º 26
0
def run(func, env):
    from flypy.runtime.special import debugprint

    for op in func.ops:
        if op.opcode == 'call':
            f, args = op.args
            if isinstance(f, Const) and f.const == debugprint:
                env["flypy.state.have_debugprint"] = True
                op.replace(
                    Op("debugprint", ptypes.Void, args, result=op.result))

                [expr] = args
                debugprint_expr(expr, "frontend")
Exemplo n.º 27
0
def run(func, env):
    storage = env['storage']

    for op in func.ops:
        if op.opcode == 'ckernel':
            # Build an executable chunked or in-memory pykernel
            if storage is None:
                pykernel = op_ckernel(op)
            else:
                pykernel = op_ckernel_chunked(op)

            newop = Op('pykernel', op.type, [pykernel, op.args[1]], op.result)
            op.replace(newop)
Exemplo n.º 28
0
    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 = 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
Exemplo n.º 29
0
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
Exemplo n.º 30
0
def assemble_kernels(func, env, pykernels, strategy):
    """
    Transforms kernel ops to pykernel ops, for execution by a simple
    interpreter.

    Arguments
    =========
    pykernels: { Op: py_func }
        python applyable kernels that accept blaze arrays

    strategy: str
        the strategy for which we are applying the transform
    """
    strategies = env['strategies']

    for op in func.ops:
        if op.opcode == 'kernel' and strategies[op] == strategy:
            pykernel = pykernels[op]
            op.replace(
                Op('pykernel', op.type, [pykernel, op.args[1:]], op.result))
Exemplo n.º 31
0
def apply_result(func, cfg, deadblocks, cells):
    """
    Apply the result of the SCCP analysis:

        - replace ops with constants
        - remove unreachable code blocks
    """
    for op in func.ops:
        if isconst(cells[op]):
            op.replace_uses(cells[op])
            op.delete()
        if op.opcode == 'cbranch' and isconst(cells[op.args[0]]):
            test = cells[op.args[0]].const
            blocks = {True: op.args[1], False: op.args[2] }
            target = blocks[test]
            other  = blocks[not test]
            cfg.remove_edge(op.block, other)
            op.replace(Op("jump", types.Void, [target], op.result))

    cfa.delete_blocks(func, cfg, deadblocks)
Exemplo n.º 32
0
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 = f.new_block(block.name)
        valuemap[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, valuemap
Exemplo n.º 33
0
def newop(opcode, args):
    return Op(opcode, types.Opaque, args)
Exemplo n.º 34
0
 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
Exemplo n.º 35
0
def rewrite_sql(func, env):
    """
    Generate SQL queries for each SQL op and assemble them into one big query
    which we rewrite to python kernels.
    """
    strategies = env['strategies']  # op -> strategy (e.g. 'sql')
    impls = env['kernel.overloads']  # (op, strategy) -> Overload
    roots = env['roots']  # Backend boundaries: { Op }
    args = env['runtime.args']  # FuncArg -> blaze.Array
    conns = env['sql.conns']  # Op -> SQL Connection

    rewrite = set()  # ops to rewrite to sql kernels
    delete = set()  # ops to delete
    queries = {}  # op -> query (str)

    leafs = {}  # op -> set of SQL leafs

    # Extract table names and insert in queries
    for arg in func.args:
        if strategies[arg] == 'sql':
            arr = args[arg]
            sql_ddesc = arr._data

            if isinstance(sql_ddesc, DyNDDataDescriptor):
                # Extract scalar value from blaze array
                assert not sql_ddesc.dshape.shape
                # Do something better here
                query = str(sql_ddesc.dynd_arr())
            else:
                table = Table(sql_ddesc.col.table)
                query = Column(table, sql_ddesc.col.colname)

            queries[arg] = query
            leafs[arg] = [arg]

    # print(func)
    # print(strategies)

    # Generate SQL queries for each op
    for op in func.ops:
        if op.opcode == "kernel" and strategies[op] == 'sql':
            query_gen, signature = impls[op, 'sql']

            args = op.args[1:]
            inputs = [queries[arg] for arg in args]
            query = query_gen(*inputs)
            queries[op] = query
            if args[0] in conns:
                conns[op] = conns[args[0]]
            leafs[op] = [leaf for arg in args for leaf in leafs[arg]]

        elif op.opcode == 'convert':
            uses = func.uses[op]
            if all(strategies[use] == 'sql' for use in uses):
                arg = op.args[0]
                query = queries[arg]
                queries[op] = query

                if arg in conns:
                    conns[op] = conns[arg]
                leafs[op] = list(leafs[arg])
            else:
                continue

        else:
            continue

        if op in roots:
            rewrite.add(op)
        else:
            delete.add(op)

    # Rewrite sql kernels to python kernels
    for op in rewrite:
        query = queries[op]
        pykernel = sql_to_pykernel(query, op, env)
        newop = Op('pykernel', op.type, [pykernel, leafs[op]], op.result)
        op.replace(newop)

    # Delete remaining unnecessary ops
    func.delete_all(delete)
Exemplo n.º 36
0
 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
Exemplo n.º 37
0
 def _process(self, ty, args, result=None):
     assert ty is not None
     # args = nestedmap(make_arg, args)
     result = Op(op, ty, args, result)
     self._insert_op(result)
     return result