コード例 #1
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
コード例 #2
0
ファイル: reg2mem.py プロジェクト: YusufCakan/pykit
def split_critical_edges(func, cfg, phis):
    """
    Split critical edges to correctly handle cycles in phis. See 2) above.
    """
    b = Builder(func)
    for block in cfg.node:
        successors = cfg.neighbors(block)
        if len(successors) > 1:
            # More than one successor, we need to split
            # (Alternatively, we could move our copies into the successor block
            #  if we were the only predecessor, but this seems simpler)

            # Split successors with phis
            new_succs = {}  # old_successor -> new_successor
            for succ in successors:
                if phis[succ]:
                    label = func.temp("split_critical")
                    new_succ = func.new_block(label, after=block)
                    new_succs[succ] = new_succ
                    b.position_at_end(new_succ)
                    b.jump(succ)

            # Patch our basic-block terminator to point to new blocks
            if new_succs:
                terminator = block.terminator
                assert terminator.opcode == 'cbranch', terminator
                test, truebb, falsebb = terminator.args
                terminator.set_args([
                    test,
                    new_succs.get(truebb, truebb),
                    new_succs.get(falsebb, falsebb)
                ])
コード例 #3
0
def rewrite_obj_return(func, env):
    """
    Handle returning stack-allocated objects.
    """
    if should_skip(env):
        return

    context = env['flypy.typing.context']
    restype = env['flypy.typing.restype']
    envs = env['flypy.state.envs']

    builder = Builder(func)

    stack_alloc = representation.byref(restype)

    if stack_alloc:
        out = func.add_arg(func.temp("out"), opaque_t)
        context[out] = Pointer[restype]
        func.type = types.Function(types.Void, func.type.argtypes, False)

    for arg in func.args:
        arg.type = opaque_t
    func.type = types.Function(func.type.restype,
                               (opaque_t, ) * len(func.args), False)

    is_generator = env['flypy.state.generator']
    for op in func.ops:
        if (op.opcode == 'ret' and op.args[0] is not None and stack_alloc
                and not is_generator):
            # ret val =>
            #     store (load val) out ; ret void
            [val] = op.args
            builder.position_before(op)
            newval = builder.load(val)
            builder.store(newval, out)
            op.set_args([None])

            # Update context
            context[newval] = StackVar[context[val]]

        elif op.opcode == 'call' and op.type != types.Void:
            # result = call(f, ...) =>
            #     alloca result ; call(f, ..., &result)
            ty = context[op]
            if conversion.byref(ty):
                f, args = op.args
                if not is_flypy_cc(f) or should_skip(envs[f]):
                    continue

                builder.position_before(op)
                retval = builder.alloca(opaque_t)
                builder.position_after(op)
                op.replace_uses(retval)

                newargs = args + [retval]
                op.set_args([f, newargs])

                # Update context
                context[retval] = context[op]
                context[op] = void
コード例 #4
0
ファイル: translation.py プロジェクト: pombreda/flypy
    def initialize(self):
        """Initialize pykit untypes structures"""

        # Setup Function
        sig = types.Function(types.Opaque, [types.Opaque] * len(self.argnames),
                             False)
        self.dst = Function(func_name(self.func), self.argnames, sig)

        # Setup Builder
        self.builder = Builder(self.dst)

        # Setup Blocks
        for offset in self.bytecode.labels:
            name = blockname(self.func, offset)
            block = self.dst.new_block(name)
            self.blocks[offset] = block
            self.stacks[block] = []

        # Setup Variables
        self.builder.position_at_beginning(self.dst.startblock)
        for varname in self.varnames:
            stackvar = self.builder.alloca(types.Pointer(types.Opaque),
                                           result=self.dst.temp(varname))
            self.allocas[varname] = stackvar

            # Initialize function arguments
            if varname in self.argnames:
                self.builder.store(self.dst.get_arg(varname), stackvar)
コード例 #5
0
ファイル: calls.py プロジェクト: pombreda/flypy
def rewrite_setattr(func, env):
    """
    Resolve missing attributes through __setattr__
    """
    context = env['flypy.typing.context']

    b = Builder(func)

    for op in func.ops:
        if op.opcode == 'setfield':
            obj, attr, value = op.args
            obj_type = context[obj]
            attr_type = types.String[()]

            if attr not in obj_type.fields and attr not in obj_type.layout:
                assert SETATTR in obj_type.fields, attr

                b.position_after(op)

                # Construct attribute string
                attr_string = OConst(attr)

                # call(getfield(obj, '__setattr__'), ['attr', value])
                method_type = make_method(obj_type, SETATTR)
                method = b.getfield(ptypes.Opaque, obj, SETATTR)
                call = b.call(ptypes.Opaque, method, [attr_string, value])
                op.delete()

                # Update context
                del context[op]
                context[method] = method_type
                context[call] = types.Void[()]
                context[attr_string] = attr_type
コード例 #6
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)
コード例 #7
0
ファイル: ret.py プロジェクト: inaimathi/pykit
def run(func, env=None, return_block=None):
    """
    Rewrite 'ret' operations into jumps to a return block and assignments
    to a return variable.
    """
    b = Builder(func)
    return_block = return_block or func.new_block("pykit.return")

    # Allocate return variable
    if not func.type.restype.is_void:
        with b.at_front(func.startblock):
            return_var = b.alloca(types.Pointer(func.type.restype), [])
            b.store(Undef(func.type.restype), return_var)
    else:
        return_var = None

    # Repace 'ret' instructions with jumps and assignments
    for op in func.ops:
        if op.opcode == "ret":
            b.position_after(op)
            if return_var:
                b.store(op.args[0], return_var)
            b.jump(return_block)
            op.delete()

    with b.at_end(return_block):
        if return_var:
            result = b.load(return_var.type.base, [return_var])
        else:
            result = None

        b.ret(result)
コード例 #8
0
ファイル: cfa.py プロジェクト: YusufCakan/pykit
def move_allocas(func, allocas):
    """Move all allocas to the start block"""
    builder = Builder(func)
    builder.position_at_beginning(func.startblock)
    for alloca in allocas:
        if alloca.block != func.startblock:
            alloca.unlink()
            builder.emit(alloca)
コード例 #9
0
def move_generator(func, consumer, empty_body):
    gen = consumer.generator
    gen.unlink()

    b = Builder(func)
    b.position_at_end(empty_body)
    b.emit(gen)

    with b.at_end(empty_body):
        loop_exit = determine_loop_exit(consumer.loop)
        b.jump(loop_exit)
コード例 #10
0
ファイル: cfa.py プロジェクト: YusufCakan/pykit
def insert_phis(func, cfg, allocas):
    """Insert φs in the function given the set of promotable stack variables"""
    builder = Builder(func)
    phis = {}  # phi -> alloca
    for block in func.blocks:
        if len(cfg.predecessors(block)) > 1:
            with builder.at_front(block):
                for alloca in allocas:
                    phi = builder.phi(alloca.type.base, [], [])
                    phis[phi] = alloca

    return phis
コード例 #11
0
ファイル: frontend.py プロジェクト: pombreda/flypy
def simplify_exceptions(func, env=None):
    """
    Rewrite exceptions emitted by the front-end:

        exc_end -> split block
    """
    b = Builder(func)
    for op in func.ops:
        if op.opcode == 'exc_end':
            b.position_after(op)
            b.splitblock(terminate=True, preserve_exc=False)
            op.delete()
コード例 #12
0
ファイル: llconstants.py プロジェクト: pombreda/flypy
def rewrite_lowlevel_constants(func, env):
    """
    Rewrite constant pointers.
    """
    b = Builder(func)
    b.position_at_beginning(func.startblock)

    for op in func.ops:
        constants = collect_constants(op)
        new_constants = []
        for c in constants:
            new_constants.append(allocate_pointer_const(b, c))
        substitute_args(op, constants, new_constants)
コード例 #13
0
def preserve_exceptions(oldblock, newblock):
    """
    Preserve exc_setup instructions for block splits.
    """
    from pykit.ir import Builder

    func = oldblock.parent
    b = Builder(func)
    b.position_at_beginning(newblock)

    for op in oldblock.leaders:
        if op.opcode == 'exc_setup':
            b.exc_setup(op.args[0], **op.metadata)
コード例 #14
0
    def test_exc_rewrite(self):
        func = Function("foo", [], types.Function(types.Void, (), False))
        entry = func.new_block("entry")
        catch_block = func.new_block("catch")
        b = Builder(func)

        with b.at_front(entry):
            b.exc_setup([catch_block])
            b.exc_throw(Const(StopIteration, types.Exception))
        with b.at_front(catch_block):
            b.exc_catch([Const(Exception, types.Exception)])

        local_exceptions.run(func, {})
        self.assertNotIn('exc_throw', opcodes(func))
コード例 #15
0
    def visit_FuncDef(self, node):
        assert not node.param_decls
        self.enter_func()

        name = node.decl.name
        type = self.visit(node.decl.type)
        argnames = [p.name for p in node.decl.type.args.params]
        self.func = Function(name, argnames, type)
        self.func.add_block('entry')
        self.builder = Builder(self.func)
        self.builder.position_at_end(self.func.blocks[0])
        self.generic_visit(node.body)

        self.leave_func()
コード例 #16
0
ファイル: inline.py プロジェクト: YusufCakan/pykit
def inline(func, call):
    """
    Inline the call instruction into func.

    :return: { old_op : new_op }
    """
    callee = call.args[0]
    callblock = call.block
    # assert_inlinable(func, call, callee, uses)

    builder = Builder(func)
    builder.position_before(call)
    inline_header, inline_exit = builder.splitblock()
    new_callee, valuemap = copy_function(callee, temper=func.temp)
    result = rewrite_return(new_callee)

    # Fix up arguments
    for funcarg, arg in zip(new_callee.args, call.args[1]):
        funcarg.replace_uses(arg)

    # Copy blocks
    new_blocks = list(new_callee.blocks)
    after = inline_header
    for block in new_blocks:
        block.parent = None
        func.add_block(block, after=after)
        after = block

    # Fix up wiring
    builder.jump(new_callee.startblock)
    with builder.at_end(new_callee.exitblock):
        builder.jump(inline_exit)

    stretch_exception_block(builder, callblock, new_blocks)

    # Fix up final result of call
    if result is not None:
        # non-void return
        result.unlink()
        result.result = call.result
        call.replace(result)
    else:
        call.delete()

    func.reset_uses()
    #verify(func)

    return valuemap
コード例 #17
0
def detach_loop(func, consumer):
    loop, iter = consumer.loop, consumer.iter

    for block in loop.blocks:
        func.del_block(block)

    func.reset_uses()

    b = Builder(func)
    jump = iter.block.terminator
    assert jump.opcode == 'jump' and jump.args[0] == loop.head
    jump.delete()

    b.position_at_end(iter.block)
    _, newblock = b.splitblock(terminate=True)
    return newblock
コード例 #18
0
def from_expr(graph, expr_context, env):
    """
    Map a Blaze expression graph to blaze AIR

    Parameters
    ----------
    graph: blaze.expr.Op
        Expression graph

    expr_context: ExprContext
        Context of the expression

    ctx: ExecutionContext
    """
    inputs = expr_context.params

    # -------------------------------------------------
    # Types

    argtypes = [operand.dshape for operand in inputs]
    signature = types.Function(graph.dshape, argtypes, varargs=False)

    # -------------------------------------------------
    # Setup function

    name = "expr"
    argnames = ["e%d" % i for i in range(len(inputs))]
    f = Function(name, argnames, signature)
    builder = Builder(f)
    builder.position_at_beginning(f.new_block('entry'))

    # -------------------------------------------------
    # Generate function

    valuemap = dict(
        (expr, f.get_arg("e%d" % i)) for i, expr in enumerate(inputs))
    _from_expr(graph, f, builder, valuemap)

    retval = valuemap[graph]
    builder.ret(retval)

    # Update environment with runtime arguments
    runtime_args = [expr_context.terms[input] for input in inputs]
    env['runtime.args'] = dict(zip(f.args, runtime_args))

    return f
コード例 #19
0
def consume_yields(func, consumer, generator_func, valuemap):
    b = Builder(func)
    copier = lambda x: x

    loop = consumer.loop
    inlined_values = set(valuemap.values())

    for block in func.blocks:
        if block in inlined_values:
            for op in block.ops:
                if op.opcode == 'yield':
                    # -- Replace 'yield' by the loop body -- #
                    b.position_after(op)
                    _, resume = b.splitblock()

                    # Copy blocks
                    blocks = [copier(block) for block in loop.blocks]

                    # Insert blocks
                    prev = op.block
                    for block in blocks:
                        func.add_block(block, after=prev)
                        prev = block

                    # Fix wiring
                    b.jump(blocks[0])
                    b.position_at_end(blocks[-1])
                    b.jump(resume)

                    # We just introduced a bunch of copied blocks
                    func.reset_uses()

                    # Update phis with new predecessor
                    b.replace_predecessor(loop.tail, op.block, loop.head)
                    b.replace_predecessor(loop.tail, op.block, loop.head)

                    # Replace next() by value produced by yield
                    value = op.args[0]
                    consumer.next.replace_uses(value)
                    op.delete()

    # We don't need these anymore
    consumer.next.delete()
コード例 #20
0
def rewrite_raise_exc_type(func, env):
    """
    Rewrite 'raise Exception' to 'raise Exception()'
    """
    context = env['flypy.typing.context']
    b = Builder(func)

    for op in func.ops:
        if op.opcode == 'exc_throw':
            [exc_type] = op.args
            if isinstance(exc_type, Const):
                ty = context[exc_type]
                if ty.impl == Type:  # Type[Exception[]]
                    # Generate constructor application
                    b.position_before(op)
                    exc_obj = b.call(ptypes.Opaque, exc_type, [])
                    op.set_args([exc_obj])

                    type = ty.parameters[0]
                    context[exc_obj] = type
コード例 #21
0
def splitblock(block, trailing, name=None, terminate=False, preserve_exc=True):
    """Split the current block, returning (old_block, new_block)"""

    func = block.parent

    if block.is_terminated():
        successors = deduce_successors(block)
    else:
        successors = []

    # -------------------------------------------------
    # Sanity check

    # Allow splitting only after leaders and before terminator
    # TODO: error check

    # -------------------------------------------------
    # Split

    blockname = name or func.temp('Block')
    newblock = func.new_block(blockname, after=block)

    # -------------------------------------------------
    # Move ops after the split to new block

    for op in trailing:
        op.unlink()
    newblock.extend(trailing)

    if terminate and not block.is_terminated():
        # Terminate
        b = Builder(func)
        b.position_at_end(block)
        b.jump(newblock)

    # Update phis and preserve exception blocks
    patch_phis(block, newblock, successors)
    if preserve_exc:
        preserve_exceptions(block, newblock)

    return block, newblock
コード例 #22
0
    def visit_FuncDef(self, node):
        assert not node.param_decls
        self.enter_func()

        name = node.decl.name
        type = self.visit(node.decl.type)
        if node.decl.type.args:
            argnames = [p.name or "" for p in node.decl.type.args.params]
        else:
            argnames = []
        self.func = Function(name, argnames, type)
        self.func.new_block('entry')
        self.builder = Builder(self.func)
        self.builder.position_at_end(self.func.startblock)

        # Store arguments in stack variables
        for argname in argnames:
            self.assignvar(argname, self.func.get_arg(argname))

        self.generic_visit(node.body)
        self.leave_func()
コード例 #23
0
ファイル: reg2mem.py プロジェクト: YusufCakan/pykit
def generate_copies(func, phis):
    """
    Emit stores to stack variables in predecessor blocks.
    """
    builder = Builder(func)
    vars = {}
    loads = {}

    # Allocate a stack variable for each phi
    builder.position_at_beginning(func.startblock)
    for block in phis:
        for phi in phis[block]:
            vars[phi] = builder.alloca(types.Pointer(phi.type))

    # Generate loads in blocks containing the phis
    for block in phis:
        leaders = list(block.leaders)
        last_leader = leaders[-1] if leaders else block.head
        builder.position_after(last_leader)
        for phi in phis[block]:
            loads[phi] = builder.load(vars[phi])

    # Generate copies (store to stack variables)
    for block in phis:
        for phi in phis[block]:
            preds, args = phi.args
            var = vars[phi]
            phi_args = [loads.get(arg, arg) for arg in args]
            for pred, arg in zip(preds, phi_args):
                builder.position_before(pred.terminator)
                builder.store(arg, var)

    # Replace phis
    for block in phis:
        for phi in phis[block]:
            phi.replace_uses(loads[phi])
            phi.delete()

    return vars, loads
コード例 #24
0
ファイル: lower_fields.py プロジェクト: YusufCakan/pykit
def lower_fields(func, env):
    b = Builder(func)
    opbuilder = OpBuilder()

    for op in func.ops:
        if op.opcode not in ("getfield", "setfield"):
            continue

        if op.args[0].type.is_pointer:
            b.position_before(op)

            # Load the pointer and update the argument
            p = op.args[0]
            load = b.load(p)
            args = [load] + op.args[1:]
            op.set_args(args)

            if op.opcode == "setfield":
                # Write back result
                b.position_after(op)
                op.type = load.type
                b.store(op, p)

        if op.opcode == "getfield":
            struct, attr = op.args
            newop = opbuilder.extractfield(op.type,
                                           struct,
                                           attr,
                                           result=op.result)
        else:
            struct, attr, value = op.args
            newop = opbuilder.insertfield(op.type,
                                          struct,
                                          attr,
                                          value,
                                          result=op.result)

        op.replace(newop)
コード例 #25
0
ファイル: calls.py プロジェクト: pombreda/flypy
def rewrite_varargs(func, env):
    """
    Rewrite function application with arguments that go in the varargs:

        def f(x, *args):
            ...

        call(f, [x, y, z]) -> call(f, [x, (y, z)])
    """
    b = Builder(func)
    caller = Caller(b, env['flypy.typing.context'], env)
    caller = Caller(b, env['flypy.typing.context'], env)
    call_flags = env['flypy.state.call_flags']

    def f(context, py_func, f_env, op):
        f, args = op.args
        flags = call_flags.get(op, {})

        if flags.get('varargs'):
            return

        # Retrieve any remaining arguments meant for *args
        flattened = flatargs(py_func, args, {})
        if flattened.have_varargs:
            b.position_before(op)
            #print(py_func, flattened.varargs)

            # -- Build the tuple -- #
            result = caller.apply_constructor(EmptyTuple)
            for item in flattened.varargs:
                result = caller.apply_constructor(StaticTuple,
                                                  args=[item, result])

            # -- Patch callsite -- #
            args = list(flattened.positional) + [result]
            op.set_args([f, args])

    jitcallmap(f, func, env)
コード例 #26
0
ファイル: calls.py プロジェクト: pombreda/flypy
def rewrite_getattr(func, env):
    """
    Resolve missing attributes through __getattr__
    """
    context = env['flypy.typing.context']

    b = OpBuilder()
    builder = Builder(func)

    for op in func.ops:
        if op.opcode == 'getfield':
            value, attr = op.args
            obj_type = context[value]
            attr_type = types.String[()]

            if attr not in obj_type.fields and attr not in obj_type.layout:
                assert '__getattr__' in obj_type.fields

                op.set_args([value, '__getattr__'])

                # Construct attribute string
                attr_string = OConst(attr)

                # Retrieve __getattr__ function and type
                getattr_func, func_type, restype = infer_getattr(
                    obj_type, op, env)

                # call(getfield(obj, '__getattr__'), ['attr'])
                call = b.call(op.type, op, [attr_string])
                op.replace_uses(call)
                builder.position_after(op)
                builder.emit(call)

                # Update context
                context[op] = func_type
                context[attr_string] = attr_type
                context[call] = restype
コード例 #27
0
 def __init__(self, func):
     self.mod = func.module
     self.builder = Builder(func)
     self.func = func
コード例 #28
0
ファイル: test_ir.py プロジェクト: nouiz/pykit
 def setUp(self):
     self.f = from_assembly(testfunc)
     self.b = Builder(self.f)
コード例 #29
0
ファイル: test_builder.py プロジェクト: nouiz/pykit
 def setUp(self):
     self.f = Function("testfunc", ['a'],
                       types.Function(types.Float32, [types.Int32]))
     self.b = Builder(self.f)
     self.b.position_at_end(self.f.add_block('entry'))
     self.a = self.f.get_arg('a')
コード例 #30
0
ファイル: test_ir.py プロジェクト: inaimathi/pykit
 def setUp(self):
     self.m = from_c(source)
     self.f = self.m.get_function('testfunc')
     self.b = Builder(self.f)