Пример #1
0
 def make_dispatcher(self, shape, index, argtypes, resulttype):
     inputargs = [varoftype(t) for t in [Char] + argtypes]
     startblock = Block(inputargs)
     startblock.exitswitch = inputargs[0]
     graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
     row_of_graphs = self.callfamily.calltables[shape][index]
     links = []
     descs = list(self.s_pbc.descriptions)
     if self.s_pbc.can_be_None:
         descs.insert(0, None)
     for desc in descs:
         if desc is None:
             continue
         args_v = [varoftype(t) for t in argtypes]
         b = Block(args_v)
         llfn = self.rtyper.getcallable(row_of_graphs[desc])
         v_fn = inputconst(typeOf(llfn), llfn)
         v_result = varoftype(resulttype)
         b.operations.append(
             SpaceOperation("direct_call", [v_fn] + args_v, v_result))
         b.closeblock(Link([v_result], graph.returnblock))
         i = self.descriptions.index(desc)
         links.append(Link(inputargs[1:], b, chr(i)))
         links[-1].llexitcase = chr(i)
     startblock.closeblock(*links)
     return graph
Пример #2
0
def test_SSA_to_SSI():
    c = Variable('c')
    x = Variable('x')
    y = Variable('y')
    b1 = Block([c])
    b2 = Block([x])
    b3 = Block([])

    graph = FunctionGraph('x', b1)
    b2.operations.append(SpaceOperation('add', [x, c], y))
    b2.exitswitch = y

    b1.closeblock(Link([Constant(0)], b2))
    b2.closeblock(Link([y], b2), Link([], b3))
    b3.closeblock(Link([y, c], graph.exceptblock))
    SSA_to_SSI(graph)

    assert len(b1.inputargs) == 1
    assert len(b2.inputargs) == 2
    assert len(b3.inputargs) == 2

    assert b2.inputargs == b2.operations[0].args
    assert len(b1.exits[0].args) == 2
    assert b1.exits[0].args[1] is c
    assert len(b2.exits[0].args) == 2
    assert b2.exits[0].args == [y, b2.inputargs[1]]
    assert len(b2.exits[1].args) == 2
    assert len(b3.exits[0].args) == 2

    index = b3.inputargs.index(b3.exits[0].args[0])
    assert b2.exits[1].args[index] is b2.operations[0].result

    index = b3.inputargs.index(b3.exits[0].args[1])
    assert b2.exits[1].args[index] is b2.inputargs[1]
Пример #3
0
def test_funny_links():
    from rpython.flowspace.model import Block, FunctionGraph, \
         Variable, Constant, Link
    from rpython.flowspace.operation import op
    for i in range(2):
        v_i = Variable("i")
        block = Block([v_i])
        g = FunctionGraph("is_one", block)
        op1 = op.eq(v_i, Constant(1))
        block.operations.append(op1)
        block.exitswitch = op1.result
        tlink = Link([Constant(1)], g.returnblock, True)
        flink = Link([Constant(0)], g.returnblock, False)
        links = [tlink, flink]
        if i:
            links.reverse()
        block.closeblock(*links)
        t = TranslationContext()
        a = t.buildannotator()
        a.build_graph_types(g, [annmodel.SomeInteger()])
        rtyper = t.buildrtyper()
        rtyper.specialize()
        interp = LLInterpreter(rtyper)
        assert interp.eval_graph(g, [1]) == 1
        assert interp.eval_graph(g, [0]) == 0
Пример #4
0
 def make_dispatcher(self, shape, index, argtypes, resulttype):
     inputargs = [varoftype(t) for t in [Char] + argtypes]
     startblock = Block(inputargs)
     startblock.exitswitch = inputargs[0]
     graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
     row_of_graphs = self.callfamily.calltables[shape][index]
     links = []
     descs = list(self.s_pbc.descriptions)
     if self.s_pbc.can_be_None:
         descs.insert(0, None)
     for desc in descs:
         if desc is None:
             continue
         args_v = [varoftype(t) for t in argtypes]
         b = Block(args_v)
         llfn = self.rtyper.getcallable(row_of_graphs[desc])
         v_fn = inputconst(typeOf(llfn), llfn)
         v_result = varoftype(resulttype)
         b.operations.append(
             SpaceOperation("direct_call", [v_fn] + args_v, v_result))
         b.closeblock(Link([v_result], graph.returnblock))
         i = self.descriptions.index(desc)
         links.append(Link(inputargs[1:], b, chr(i)))
         links[-1].llexitcase = chr(i)
     startblock.closeblock(*links)
     return graph
Пример #5
0
def test_funny_links():
    from rpython.flowspace.model import Block, FunctionGraph, \
         Variable, Constant, Link
    from rpython.flowspace.operation import op
    for i in range(2):
        v_i = Variable("i")
        block = Block([v_i])
        g = FunctionGraph("is_one", block)
        op1 = op.eq(v_i, Constant(1))
        block.operations.append(op1)
        block.exitswitch = op1.result
        tlink = Link([Constant(1)], g.returnblock, True)
        flink = Link([Constant(0)], g.returnblock, False)
        links = [tlink, flink]
        if i:
            links.reverse()
        block.closeblock(*links)
        t = TranslationContext()
        a = t.buildannotator()
        a.build_graph_types(g, [annmodel.SomeInteger()])
        rtyper = t.buildrtyper()
        rtyper.specialize()
        interp = LLInterpreter(rtyper)
        assert interp.eval_graph(g, [1]) == 1
        assert interp.eval_graph(g, [0]) == 0
Пример #6
0
 def dispatcher(self, shape, index, argtypes, resulttype):
     key = shape, index, tuple(argtypes), resulttype
     if key in self._dispatch_cache:
         return self._dispatch_cache[key]
     from rpython.translator.unsimplify import varoftype
     from rpython.flowspace.model import FunctionGraph, Link, Block, SpaceOperation
     inputargs = [varoftype(t) for t in [Char] + argtypes]
     startblock = Block(inputargs)
     startblock.exitswitch = inputargs[0]
     graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
     row_of_graphs = self.callfamily.calltables[shape][index]
     links = []
     descs = list(self.s_pbc.descriptions)
     if self.s_pbc.can_be_None:
         descs.insert(0, None)
     for desc in descs:
         if desc is None:
             continue
         args_v = [varoftype(t) for t in argtypes]
         b = Block(args_v)
         llfn = self.rtyper.getcallable(row_of_graphs[desc])
         v_fn = inputconst(typeOf(llfn), llfn)
         v_result = varoftype(resulttype)
         b.operations.append(
             SpaceOperation("direct_call", [v_fn] + args_v, v_result))
         b.closeblock(Link([v_result], graph.returnblock))
         i = self.descriptions.index(desc)
         links.append(Link(inputargs[1:], b, chr(i)))
         links[-1].llexitcase = chr(i)
     startblock.closeblock(*links)
     self.rtyper.annotator.translator.graphs.append(graph)
     ll_ret = getfunctionptr(graph)
     #FTYPE = FuncType
     c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
     return c_ret
Пример #7
0
def test_optimize_goto_if_not__incoming():
    v1 = Variable()
    v1.concretetype = lltype.Bool
    block = Block([v1])
    block.exitswitch = v1
    block.exits = [FakeLink(False), FakeLink(True)]
    assert not Transformer().optimize_goto_if_not(block)
Пример #8
0
 def test_regalloc_exitswitch_2(self):
     v1 = Variable(); v1.concretetype = rclass.CLASSTYPE
     v2 = Variable(); v2.concretetype = rclass.CLASSTYPE
     v3 = Variable(); v3.concretetype = rclass.CLASSTYPE
     v4 = Variable(); v4.concretetype = rclass.CLASSTYPE
     block = Block([])
     block.operations = [
         SpaceOperation('res_call', [], v1),
         SpaceOperation('-live-', [], None),
         ]
     graph = FunctionGraph('f', block, v4)
     exclink = Link([v2], graph.returnblock)
     exclink.llexitcase = 123     # normally an exception class
     exclink.last_exception = v2
     exclink.last_exc_value = "unused"
     block.exitswitch = c_last_exception
     block.closeblock(Link([v1], graph.returnblock),
                      exclink)
     #
     self.check_assembler(graph, """
         res_call -> %i0
         -live-
         catch_exception L1
         int_return %i0
         ---
         L1:
         goto_if_exception_mismatch $123, L2
         last_exception -> %i0
         int_return %i0
         ---
         L2:
         reraise
     """)
Пример #9
0
def test_SSA_to_SSI():
    c = Variable('c')
    x = Variable('x')
    y = Variable('y')
    b1 = Block([c])
    b2 = Block([x])
    b3 = Block([])

    graph = FunctionGraph('x', b1)
    b2.operations.append(SpaceOperation('add', [x, c], y))
    b2.exitswitch = y

    b1.closeblock(Link([Constant(0)], b2))
    b2.closeblock(Link([y], b2), Link([], b3))
    b3.closeblock(Link([y, c], graph.exceptblock))
    SSA_to_SSI(graph)

    assert len(b1.inputargs) == 1
    assert len(b2.inputargs) == 2
    assert len(b3.inputargs) == 2

    assert b2.inputargs == b2.operations[0].args
    assert len(b1.exits[0].args) == 2
    assert b1.exits[0].args[1] is c
    assert len(b2.exits[0].args) == 2
    assert b2.exits[0].args == [y, b2.inputargs[1]]
    assert len(b2.exits[1].args) == 2
    assert len(b3.exits[0].args) == 2

    index = b3.inputargs.index(b3.exits[0].args[0])
    assert b2.exits[1].args[index] is b2.operations[0].result

    index = b3.inputargs.index(b3.exits[0].args[1])
    assert b2.exits[1].args[index] is b2.inputargs[1]
Пример #10
0
def test_optimize_goto_if_not__unknownop():
    v3 = Variable()
    v3.concretetype = lltype.Bool
    block = Block([])
    block.operations = [SpaceOperation("foobar", [], v3)]
    block.exitswitch = v3
    block.exits = [FakeLink(False), FakeLink(True)]
    assert not Transformer().optimize_goto_if_not(block)
Пример #11
0
 def copy_block(self, block):
     if block in self._copied_blocks:
         return self._copied_blocks[block]
     args = ([self.get_new_name(var) for var in block.inputargs] +
             self.passon_vars(block))
     newblock = Block(args)
     self._copied_blocks[block] = newblock
     newblock.operations = [self.copy_operation(op) for op in block.operations]
     newblock.closeblock(*[self.copy_link(link, block) for link in block.exits])
     newblock.exitswitch = self.get_new_name(block.exitswitch)
     self.search_for_calls(newblock)
     return newblock
Пример #12
0
 def copy_block(self, block):
     if block in self._copied_blocks:
         return self._copied_blocks[block]
     args = ([self.get_new_name(var) for var in block.inputargs] +
             self.passon_vars(block))
     newblock = Block(args)
     self._copied_blocks[block] = newblock
     newblock.operations = [self.copy_operation(op) for op in block.operations]
     newblock.closeblock(*[self.copy_link(link, block) for link in block.exits])
     newblock.exitswitch = self.get_new_name(block.exitswitch)
     self.search_for_calls(newblock)
     return newblock
Пример #13
0
def test_optimize_goto_if_not__ptr_iszero():
    for opname in ["ptr_iszero", "ptr_nonzero"]:
        v1 = Variable()
        v3 = Variable()
        v3.concretetype = lltype.Bool
        block = Block([v1])
        block.operations = [SpaceOperation(opname, [v1], v3)]
        block.exitswitch = v3
        block.exits = exits = [FakeLink(False), FakeLink(True)]
        res = Transformer().optimize_goto_if_not(block)
        assert res == True
        assert block.operations == []
        assert block.exitswitch == (opname, v1, "-live-before")
        assert block.exits == exits
Пример #14
0
def test_optimize_goto_if_not():
    v1 = Variable()
    v2 = Variable()
    v3 = Variable()
    v3.concretetype = lltype.Bool
    sp1 = SpaceOperation("foobar", [], None)
    sp2 = SpaceOperation("foobaz", [], None)
    block = Block([v1, v2])
    block.operations = [sp1, SpaceOperation("int_gt", [v1, v2], v3), sp2]
    block.exitswitch = v3
    block.exits = exits = [FakeLink(False), FakeLink(True)]
    res = Transformer().optimize_goto_if_not(block)
    assert res == True
    assert block.operations == [sp1, sp2]
    assert block.exitswitch == ("int_gt", v1, v2)
    assert block.exits == exits
Пример #15
0
def test_optimize_goto_if_not__exit():
    # this case occurs in practice, e.g. with RPython code like:
    #     return bool(p) and p.somefield > 0
    v1 = Variable()
    v2 = Variable()
    v3 = Variable()
    v3.concretetype = lltype.Bool
    block = Block([v1, v2])
    block.operations = [SpaceOperation("int_gt", [v1, v2], v3)]
    block.exitswitch = v3
    block.exits = exits = [FakeLink(False), FakeLink(True)]
    block.exits[1].args = [v3]
    res = Transformer().optimize_goto_if_not(block)
    assert res == True
    assert block.operations == []
    assert block.exitswitch == ("int_gt", v1, v2)
    assert block.exits == exits
    assert exits[1].args == [const(True)]
Пример #16
0
    def generic_exception_matching(self, afterblock, copiedexceptblock):
        #XXXXX don't look: insert blocks that do exception matching
        #for the cases where direct matching did not work
        exc_match = Constant(
            self.translator.rtyper.exceptiondata.fn_exception_match)
        exc_match.concretetype = typeOf(exc_match.value)
        blocks = []
        for i, link in enumerate(afterblock.exits[1:]):
            etype = copyvar(None, copiedexceptblock.inputargs[0])
            evalue = copyvar(None, copiedexceptblock.inputargs[1])
            passon_vars = self.passon_vars(i)
            block = Block([etype, evalue] + passon_vars)
            res = Variable()
            res.concretetype = Bool
            cexitcase = Constant(link.llexitcase)
            cexitcase.concretetype = typeOf(cexitcase.value)
            args = [exc_match, etype, cexitcase]
            block.operations.append(SpaceOperation("direct_call", args, res))
            block.exitswitch = res
            linkargs = self.find_args_in_exceptional_case(link, link.target,
                                                          etype, evalue, afterblock,
                                                          passon_vars)
            l = Link(linkargs, link.target)
            l.prevblock = block
            l.exitcase = True
            l.llexitcase = True
            block.closeblock(l)
            if i > 0:
                l = Link(blocks[-1].inputargs, block)
                l.exitcase = False
                l.llexitcase = False
                blocks[-1].recloseblock(l, *blocks[-1].exits)
            blocks.append(block)

        blocks[-1].recloseblock(*blocks[-1].exits[:1])
        blocks[-1].operations = []
        blocks[-1].exitswitch = None
        blocks[-1].exits[0].exitcase = None
        del blocks[-1].exits[0].llexitcase
        linkargs = copiedexceptblock.inputargs
        copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
Пример #17
0
    def generic_exception_matching(self, afterblock, copiedexceptblock):
        #XXXXX don't look: insert blocks that do exception matching
        #for the cases where direct matching did not work
        exc_match = Constant(
            self.translator.rtyper.exceptiondata.fn_exception_match)
        exc_match.concretetype = typeOf(exc_match.value)
        blocks = []
        for i, link in enumerate(afterblock.exits[1:]):
            etype = copiedexceptblock.inputargs[0].copy()
            evalue = copiedexceptblock.inputargs[1].copy()
            passon_vars = self.passon_vars(i)
            block = Block([etype, evalue] + passon_vars)
            res = Variable()
            res.concretetype = Bool
            cexitcase = Constant(link.llexitcase)
            cexitcase.concretetype = typeOf(cexitcase.value)
            args = [exc_match, etype, cexitcase]
            block.operations.append(SpaceOperation("direct_call", args, res))
            block.exitswitch = res
            linkargs = self.find_args_in_exceptional_case(link, link.target,
                                                          etype, evalue, afterblock,
                                                          passon_vars)
            l = Link(linkargs, link.target)
            l.prevblock = block
            l.exitcase = True
            l.llexitcase = True
            block.closeblock(l)
            if i > 0:
                l = Link(blocks[-1].inputargs, block)
                l.exitcase = False
                l.llexitcase = False
                blocks[-1].recloseblock(l, *blocks[-1].exits)
            blocks.append(block)

        blocks[-1].recloseblock(*blocks[-1].exits[:1])
        blocks[-1].operations = []
        blocks[-1].exitswitch = None
        blocks[-1].exits[0].exitcase = None
        del blocks[-1].exits[0].llexitcase
        linkargs = copiedexceptblock.inputargs
        copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
Пример #18
0
def test_SSA_to_SSI():
    c = Variable('c')
    x = Variable('x')
    y = Variable('y')
    b1 = Block([c])
    b2 = Block([x])
    b3 = Block([])

    b2.operations.append(SpaceOperation('add', [x, c], y))
    b2.exitswitch = y

    b1.closeblock(Link([Constant(0)], b2))
    b2.closeblock(Link([y], b2), Link([], b3))
    b3.closeblock(Link([y, c], None))

    SSA_to_SSI({b1: True,     # reachable from outside
                b2: False,
                b3: False})

    assert len(b1.inputargs) == 1
    assert len(b2.inputargs) == 2
    assert len(b3.inputargs) == 2

    assert b2.inputargs == b2.operations[0].args
    assert len(b1.exits[0].args) == 2
    assert b1.exits[0].args[1] is c
    assert len(b2.exits[0].args) == 2
    assert b2.exits[0].args == [y, b2.inputargs[1]]
    assert len(b2.exits[1].args) == 2
    assert len(b3.exits[0].args) == 2

    index = b3.inputargs.index(b3.exits[0].args[0])
    assert b2.exits[1].args[index] is b2.operations[0].result

    index = b3.inputargs.index(b3.exits[0].args[1])
    assert b2.exits[1].args[index] is b2.inputargs[1]
Пример #19
0
def split_block(block, index, _forcelink=None):
    """return a link where prevblock is the block leading up but excluding the
    index'th operation and target is a new block with the neccessary variables
    passed on.
    """
    assert 0 <= index <= len(block.operations)
    if block.exitswitch == c_last_exception:
        assert index < len(block.operations)
    #varmap is the map between names in the new and the old block
    #but only for variables that are produced in the old block and needed in
    #the new one
    varmap = {}
    vars_produced_in_new_block = set()

    def get_new_name(var):
        if var is None:
            return None
        if isinstance(var, Constant):
            return var
        if var in vars_produced_in_new_block:
            return var
        if var not in varmap:
            varmap[var] = var.copy()
        return varmap[var]

    moved_operations = block.operations[index:]
    new_moved_ops = []
    for op in moved_operations:
        repl = dict((arg, get_new_name(arg)) for arg in op.args)
        newop = op.replace(repl)
        new_moved_ops.append(newop)
        vars_produced_in_new_block.add(op.result)
    moved_operations = new_moved_ops
    links = block.exits
    block.exits = None
    for link in links:
        for i, arg in enumerate(link.args):
            #last_exception and last_exc_value are considered to be created
            #when the link is entered
            if link.args[i] not in [link.last_exception, link.last_exc_value]:
                link.args[i] = get_new_name(link.args[i])
    exitswitch = get_new_name(block.exitswitch)
    #the new block gets all the attributes relevant to outgoing links
    #from block the old block
    if _forcelink is not None:
        assert index == 0
        linkargs = list(_forcelink)
        for v in varmap:
            if v not in linkargs:
                # 'v' was not specified by _forcelink, but we found out that
                # we need it!  Hack: if it is 'concretetype is lltype.Void'
                # then it's ok to recreate its value in the target block.
                # If not, then we have a problem :-)
                from rpython.rtyper.lltypesystem import lltype
                if v.concretetype is not lltype.Void:
                    raise Exception(
                        "The variable %r of type %r was not explicitly listed"
                        " in _forcelink.  This issue can be caused by a"
                        " jitdriver.jit_merge_point() where some variable"
                        " containing an int or str or instance is actually"
                        " known to be constant, e.g. always 42." %
                        (v, v.concretetype))
                c = Constant(None, lltype.Void)
                w = varmap[v]
                newop = SpaceOperation('same_as', [c], w)
                i = 0
                while i < len(moved_operations):
                    if w in moved_operations[i].args:
                        break
                    i += 1
                moved_operations.insert(i, newop)
    else:
        linkargs = varmap.keys()
    newblock = Block([get_new_name(v) for v in linkargs])
    newblock.operations = moved_operations
    newblock.recloseblock(*links)
    newblock.exitswitch = exitswitch
    link = Link(linkargs, newblock)
    block.operations = block.operations[:index]
    block.recloseblock(link)
    block.exitswitch = None
    return link
Пример #20
0
def split_block(annotator, block, index, _forcelink=None):
    """return a link where prevblock is the block leading up but excluding the
    index'th operation and target is a new block with the neccessary variables
    passed on.
    """
    assert 0 <= index <= len(block.operations)
    if block.exitswitch == c_last_exception:
        assert index < len(block.operations)
    #varmap is the map between names in the new and the old block
    #but only for variables that are produced in the old block and needed in
    #the new one
    varmap = {}
    vars_produced_in_new_block = {}
    def get_new_name(var):
        if var is None:
            return None
        if isinstance(var, Constant):
            return var
        if var in vars_produced_in_new_block:
            return var
        if var not in varmap:
            varmap[var] = copyvar(annotator, var)
        return varmap[var]
    moved_operations = block.operations[index:]
    new_moved_ops = []
    for op in moved_operations:
        newop = SpaceOperation(op.opname,
                               [get_new_name(arg) for arg in op.args],
                               op.result)
        new_moved_ops.append(newop)
        vars_produced_in_new_block[op.result] = True
    moved_operations = new_moved_ops
    links = block.exits
    block.exits = None
    for link in links:
        for i, arg in enumerate(link.args):
            #last_exception and last_exc_value are considered to be created
            #when the link is entered
            if link.args[i] not in [link.last_exception, link.last_exc_value]:
                link.args[i] = get_new_name(link.args[i])
    exitswitch = get_new_name(block.exitswitch)
    #the new block gets all the attributes relevant to outgoing links
    #from block the old block
    if _forcelink is not None:
        assert index == 0
        linkargs = list(_forcelink)
        for v in varmap:
            if v not in linkargs:
                # 'v' was not specified by _forcelink, but we found out that
                # we need it!  Hack: if it is 'concretetype is lltype.Void'
                # then it's ok to recreate its value in the target block.
                # If not, then we have a problem :-)
                from rpython.rtyper.lltypesystem import lltype
                if v.concretetype is not lltype.Void:
                    raise Exception(
                        "The variable %r of type %r was not explicitly listed"
                        " in _forcelink.  This issue can be caused by a"
                        " jitdriver.jit_merge_point() where some variable"
                        " containing an int or str or instance is actually"
                        " known to be constant, e.g. always 42." % (
                        v, v.concretetype))
                c = Constant(None, lltype.Void)
                w = varmap[v]
                newop = SpaceOperation('same_as', [c], w)
                i = 0
                while i < len(moved_operations):
                    if w in moved_operations[i].args:
                        break
                    i += 1
                moved_operations.insert(i, newop)
    else:
        linkargs = varmap.keys()
    newblock = Block([get_new_name(v) for v in linkargs])
    newblock.operations = moved_operations
    newblock.recloseblock(*links)
    newblock.exitswitch = exitswitch
    link = Link(linkargs, newblock)
    block.operations = block.operations[:index]
    block.recloseblock(link)
    block.exitswitch = None
    return link