示例#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
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
示例#3
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
示例#4
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
示例#5
0
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)
示例#6
0
def lower_fields(func, env=None):
    b = Builder(func)

    for op in func.ops:
        if op.opcode in ("getfield", "setfield") and op.args[0].type.is_pointer:
            b.position_before(op)
            p = op.args[0]
            load = b.load(p.type.base, [p])
            args = [load] + op.args[1:]
            op.set_args(args)

            if op.opcode == "setfield":
                b.position_after(op)
                b.store(op, p)
示例#7
0
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
示例#8
0
文件: inline.py 项目: B-Rich/pykit
def inline(func, call, uses=None):
    """
    Inline the call instruction into func.

    :param uses: defuse information
    """
    callee = call.args[0]
    # assert_inlinable(func, call, callee, uses)

    builder = Builder(func)
    builder.position_before(call)
    inline_header, inline_exit = builder.splitblock()
    new_callee = 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
    after = inline_header
    for block in new_callee.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)

    # 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)
示例#9
0
def rewrite_raise_exc_type(func, env):
    """
    Rewrite 'raise Exception' to 'raise Exception()'
    """
    context = env['numba.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
示例#10
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
示例#11
0
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
示例#12
0
文件: reg2mem.py 项目: flypy/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
示例#13
0
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)
示例#14
0
def convert_retval(func, env):
    """
    Rewrite 'return x' to 'return (restype) x'
    """
    if env['numba.state.opaque']:
        return

    restype = func.type.restype
    context = env['numba.typing.context']

    b = Builder(func)
    for op in func.ops:
        if op.opcode != 'ret' or op.args[0] is None:
            continue

        [retval] = op.args
        if retval.type != restype:
            b.position_before(op)
            converted = b.convert(restype, retval)
            op.set_args([converted])

            # Update type context
            context[converted] = context[retval]