Example #1
0
def test_fold_exitswitch_along_one_path():
    def g(n):
        if n == 42:
            return 5
        else:
            return n+1
    def fn(n):
        if g(n) == 5:
            return 100
        else:
            return 0

    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt import removenoops, inline
    inline.auto_inline_graphs(t, t.graphs, threshold=999)
    constant_fold_graph(graph)
    removenoops.remove_same_as(graph)
    if option.view:
        t.view()
    # check that the graph starts with a condition (which should be 'n==42')
    # and that if this condition is true, it goes directly to 'return 100'.
    assert len(graph.startblock.exits) == 2
    assert graph.startblock.exits[1].exitcase == True
    assert graph.startblock.exits[1].target is graph.returnblock
    check_graph(graph, [10], 0, t)
    check_graph(graph, [42], 100, t)
Example #2
0
def test_switch_on_symbolic():
    symb1 = CDefinedIntSymbolic("1", 1)
    symb2 = CDefinedIntSymbolic("2", 2)
    symb3 = CDefinedIntSymbolic("3", 3)

    def fn(x):
        res = 0
        if x == symb1:
            res += x + 1
        elif x == symb2:
            res += x + 2
        elif x == symb3:
            res += x + 3
        res += 1
        return res

    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = t.graphs[0]
    remove_same_as(graph)
    res = merge_if_blocks_once(graph)
    assert not res
    checkgraph(graph)
Example #3
0
 def split_graph_and_record_jitdriver(self, graph, block, pos):
     op = block.operations[pos]
     jd = JitDriverStaticData()
     jd._jit_merge_point_in = graph
     args = op.args[2:]
     s_binding = self.translator.annotator.binding
     jd._portal_args_s = [s_binding(v) for v in args]
     graph = copygraph(graph)
     [jmpp] = find_jit_merge_points([graph])
     graph.startblock = support.split_before_jit_merge_point(*jmpp)
     # XXX this is incredibly obscure, but this is sometiems necessary
     #     so we don't explode in checkgraph. for reasons unknown this
     #     is not contanied within simplify_graph
     removenoops.remove_same_as(graph)
     # a crash in the following checkgraph() means that you forgot
     # to list some variable in greens=[] or reds=[] in JitDriver,
     # or that a jit_merge_point() takes a constant as an argument.
     checkgraph(graph)
     for v in graph.getargs():
         assert isinstance(v, Variable)
     assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs())
     self.translator.graphs.append(graph)
     jd.portal_graph = graph
     # it's a bit unbelievable to have a portal without func
     assert hasattr(graph, "func")
     graph.func._dont_inline_ = True
     graph.func._jit_unroll_safe_ = True
     jd.jitdriver = block.operations[pos].args[1].value
     jd.portal_runner_ptr = "<not set so far>"
     jd.result_type = history.getkind(jd.portal_graph.getreturnvar()
                                      .concretetype)[0]
     self.jitdrivers_sd.append(jd)
Example #4
0
def storesink_graph(graph):

    def clear_cache_for(cache, concretetype, fieldname):
        for k in cache.keys():
            if k[0].concretetype == concretetype and k[1] == fieldname:
                del cache[k]

    added_some_same_as = False

    for block in graph.iterblocks():
        newops = []
        cache = {}
        for op in block.operations:
            if op.opname == 'getfield':
                tup = (op.args[0], op.args[1].value)
                res = cache.get(tup, None)
                if res is not None:
                    op.opname = 'same_as'
                    op.args = [res]
                    added_some_same_as = True
                else:
                    cache[tup] = op.result
            elif op.opname in ['setarrayitem', 'setinteriorfield']:
                pass
            elif op.opname == 'setfield':
                clear_cache_for(cache, op.args[0].concretetype,
                                op.args[1].value)
            elif has_side_effects(op):
                cache = {}
            newops.append(op)
        if block.operations:
            block.operations = newops

    if added_some_same_as:
        removenoops.remove_same_as(graph)
Example #5
0
def test_remove_same_as():
    def nothing(x):
        return x

    def f():
        nothing(False)
        if nothing(True):
            return 42
        else:
            return 666

    t = TranslationContext()
    t.buildannotator().build_types(f, [])
    t.buildrtyper().specialize()
    # now we make the 'if True' appear
    f_graph = graphof(t, f)
    simple_inline_function(t, nothing, f_graph)
    # here, the graph looks like  v21=same_as(True);  exitswitch: v21
    remove_same_as(f_graph)
    t.checkgraphs()
    # only one path should be left
    for block in f_graph.iterblocks():
        assert len(block.exits) <= 1

    interp = LLInterpreter(t.rtyper)
    result = interp.eval_graph(f_graph, [])
    assert result == 42
Example #6
0
 def split_graph_and_record_jitdriver(self, graph, block, pos):
     op = block.operations[pos]
     jd = JitDriverStaticData()
     jd._jit_merge_point_in = graph
     args = op.args[2:]
     s_binding = self.translator.annotator.binding
     jd._portal_args_s = [s_binding(v) for v in args]
     graph = copygraph(graph)
     [jmpp] = find_jit_merge_points([graph])
     graph.startblock = support.split_before_jit_merge_point(*jmpp)
     # XXX this is incredibly obscure, but this is sometiems necessary
     #     so we don't explode in checkgraph. for reasons unknown this
     #     is not contanied within simplify_graph
     removenoops.remove_same_as(graph)
     # a crash in the following checkgraph() means that you forgot
     # to list some variable in greens=[] or reds=[] in JitDriver,
     # or that a jit_merge_point() takes a constant as an argument.
     checkgraph(graph)
     for v in graph.getargs():
         assert isinstance(v, Variable)
     assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs())
     self.translator.graphs.append(graph)
     jd.portal_graph = graph
     # it's a bit unbelievable to have a portal without func
     assert hasattr(graph, "func")
     graph.func._dont_inline_ = True
     graph.func._jit_unroll_safe_ = True
     jd.jitdriver = block.operations[pos].args[1].value
     jd.portal_runner_ptr = "<not set so far>"
     jd.result_type = history.getkind(
         jd.portal_graph.getreturnvar().concretetype)[0]
     self.jitdrivers_sd.append(jd)
Example #7
0
def test_replace_exitswitch_by_constant_bug():
    class X:
        pass
    def constant9():
        x = X()
        x.n = 3
        x.n = 9
        return x.n
    def fn():
        n = constant9()
        if n == 1: return 5
        elif n == 2: return 6
        elif n == 3: return 8
        elif n == 4: return -123
        elif n == 5: return 12973
        else: return n
    
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = t.graphs[0]
    remove_same_as(graph)
    merge_if_blocks_once(graph)
    from rpython.translator.backendopt import malloc, inline
    inline.auto_inlining(t, 20)
    malloc.remove_mallocs(t, t.graphs)
    from rpython.translator import simplify
    simplify.join_blocks(graph)
Example #8
0
def test_remove_same_as_nonconst():
    from rpython.rlib.nonconst import NonConstant
    from rpython.rtyper.lltypesystem.lloperation import llop
    from rpython.rtyper.lltypesystem import lltype

    def f():
        if NonConstant(False):
            x = llop.same_as(lltype.Signed, 666)
        return 42

    t = TranslationContext()
    t.buildannotator().build_types(f, [])
    t.buildrtyper().specialize()
    f_graph = graphof(t, f)
    #simple_inline_function(t, nothing, f_graph)
    # here, the graph looks like  v21=same_as(True);  exitswitch: v21
    remove_same_as(f_graph)
    t.checkgraphs()
    # only one path should be left
    for block in f_graph.iterblocks():
        assert len(block.exits) <= 1

    for block in t.annotator.annotated:
        assert None not in block.operations

    interp = LLInterpreter(t.rtyper)
    result = interp.eval_graph(f_graph, [])
    assert result == 42
Example #9
0
def test_coalesce_exitswitchs():
    def g(n):
        return n > 5 and n < 20
    def fn(n):
        if g(n):
            return 100
        else:
            return 0

    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt import removenoops, inline
    inline.auto_inline_graphs(t, t.graphs, threshold=999)
    removenoops.remove_same_as(graph)
    constant_fold_graph(graph)
    if option.view:
        t.view()
    # check that the graph starts with a condition (which should be 'n > 5')
    # and that if this condition is false, it goes directly to 'return 0'.
    assert summary(graph) == {'int_gt': 1, 'int_lt': 1}
    assert len(graph.startblock.exits) == 2
    assert graph.startblock.exits[0].exitcase == False
    assert graph.startblock.exits[0].target is graph.returnblock
    check_graph(graph, [2], 0, t)
    check_graph(graph, [10], 100, t)
    check_graph(graph, [42], 0, t)
Example #10
0
def storesink_graph(graph):
    """ remove superfluous getfields. use a super-local method: all non-join
    blocks inherit the heap information from their (single) predecessor
    """
    added_some_same_as = False
    entrymap = mkentrymap(graph)

    # all merge blocks are starting points
    todo = [(block, None, None) for (block, prev_blocks) in entrymap.iteritems()
                if len(prev_blocks) > 1 or block is graph.startblock]

    visited = 0

    while todo:
        block, cache, inputlink = todo.pop()
        visited += 1
        if cache is None:
            cache = {}

        if block.operations:
            changed_block = _storesink_block(block, cache, inputlink)
            added_some_same_as = changed_block or added_some_same_as
        for link in block.exits:
            if len(entrymap[link.target]) == 1:
                new_cache = _translate_cache(cache, link)
                todo.append((link.target, new_cache, link))

    assert visited == len(entrymap)
    if added_some_same_as:
        removenoops.remove_same_as(graph)
        simplify.transform_dead_op_vars(graph)
Example #11
0
def storesink_graph(graph):
    """ remove superfluous getfields. use a super-local method: all non-join
    blocks inherit the heap information from their (single) predecessor
    """
    added_some_same_as = False
    entrymap = mkentrymap(graph)

    # all merge blocks are starting points
    todo = [(block, None, None)
            for (block, prev_blocks) in entrymap.iteritems()
            if len(prev_blocks) > 1 or block is graph.startblock]

    visited = 0

    while todo:
        block, cache, inputlink = todo.pop()
        visited += 1
        if cache is None:
            cache = {}

        if block.operations:
            changed_block = _storesink_block(block, cache, inputlink)
            added_some_same_as = changed_block or added_some_same_as
        for link in block.exits:
            if len(entrymap[link.target]) == 1:
                new_cache = _translate_cache(cache, link)
                todo.append((link.target, new_cache, link))

    assert visited == len(entrymap)
    if added_some_same_as:
        removenoops.remove_same_as(graph)
        simplify.transform_dead_op_vars(graph)
Example #12
0
def test_merge_several():
    def merge(n, m):
        r = -1
        if n == 0:
            if m == 0:
                r = 0
            elif m == 1:
                r = 1
            else:
                r = 2
        elif n == 1:
            r = 4
        else:
            r = 6
        return r
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(merge, [int, int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, merge)
    remove_same_as(graph)
    merge_if_blocks(graph)
    assert len(graph.startblock.exits) == 3
    assert len(list(graph.iterblocks())) == 3
    interp = LLInterpreter(rtyper)
    for m in range(3):
        res = interp.eval_graph(graph, [0, m])
        assert res == m
    res = interp.eval_graph(graph, [1, 0])
    assert res == 4
    res = interp.eval_graph(graph, [2, 0])
    assert res == 6
Example #13
0
def test_fold_exitswitch_along_one_path():
    def g(n):
        if n == 42:
            return 5
        else:
            return n+1
    def fn(n):
        if g(n) == 5:
            return 100
        else:
            return 0

    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt import removenoops, inline
    inline.auto_inline_graphs(t, t.graphs, threshold=999)
    constant_fold_graph(graph)
    removenoops.remove_same_as(graph)
    if option.view:
        t.view()
    # check that the graph starts with a condition (which should be 'n==42')
    # and that if this condition is true, it goes directly to 'return 100'.
    assert len(graph.startblock.exits) == 2
    assert graph.startblock.exits[1].exitcase == True
    assert graph.startblock.exits[1].target is graph.returnblock
    check_graph(graph, [10], 0, t)
    check_graph(graph, [42], 100, t)
Example #14
0
def test_replace_exitswitch_by_constant_bug():
    class X:
        pass

    def constant9():
        x = X()
        x.n = 3
        x.n = 9
        return x.n

    def fn():
        n = constant9()
        if n == 1: return 5
        elif n == 2: return 6
        elif n == 3: return 8
        elif n == 4: return -123
        elif n == 5: return 12973
        else: return n

    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = t.graphs[0]
    remove_same_as(graph)
    merge_if_blocks_once(graph)
    from rpython.translator.backendopt import malloc, inline
    inline.auto_inlining(t, 20)
    malloc.remove_mallocs(t, t.graphs)
    from rpython.translator import simplify
    simplify.join_blocks(graph)
Example #15
0
def test_coalesce_exitswitchs():
    def g(n):
        return n > 5 and n < 20
    def fn(n):
        if g(n):
            return 100
        else:
            return 0

    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt import removenoops, inline
    inline.auto_inline_graphs(t, t.graphs, threshold=999)
    removenoops.remove_same_as(graph)
    constant_fold_graph(graph)
    if option.view:
        t.view()
    # check that the graph starts with a condition (which should be 'n > 5')
    # and that if this condition is false, it goes directly to 'return 0'.
    assert summary(graph) == {'int_gt': 1, 'int_lt': 1}
    assert len(graph.startblock.exits) == 2
    assert graph.startblock.exits[0].exitcase == False
    assert graph.startblock.exits[0].target is graph.returnblock
    check_graph(graph, [2], 0, t)
    check_graph(graph, [10], 100, t)
    check_graph(graph, [42], 0, t)
Example #16
0
def test_merge_several():
    def merge(n, m):
        r = -1
        if n == 0:
            if m == 0:
                r = 0
            elif m == 1:
                r = 1
            else:
                r = 2
        elif n == 1:
            r = 4
        else:
            r = 6
        return r

    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(merge, [int, int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, merge)
    remove_same_as(graph)
    merge_if_blocks(graph)
    assert len(graph.startblock.exits) == 3
    assert len(list(graph.iterblocks())) == 3
    interp = LLInterpreter(rtyper)
    for m in range(3):
        res = interp.eval_graph(graph, [0, m])
        assert res == m
    res = interp.eval_graph(graph, [1, 0])
    assert res == 4
    res = interp.eval_graph(graph, [2, 0])
    assert res == 6
Example #17
0
def test_remove_same_as_nonconst():
    from rpython.rlib.nonconst import NonConstant
    from rpython.rtyper.lltypesystem.lloperation import llop
    from rpython.rtyper.lltypesystem import lltype

    def f():
        if NonConstant(False):
            x = llop.same_as(lltype.Signed, 666)
        return 42

    t = TranslationContext()
    t.buildannotator().build_types(f, [])
    t.buildrtyper().specialize()
    f_graph = graphof(t, f)
    # simple_inline_function(t, nothing, f_graph)
    # here, the graph looks like  v21=same_as(True);  exitswitch: v21
    remove_same_as(f_graph)
    t.checkgraphs()
    # only one path should be left
    for block in f_graph.iterblocks():
        assert len(block.exits) <= 1

    for block in t.annotator.annotated:
        assert None not in block.operations

    interp = LLInterpreter(t.rtyper)
    result = interp.eval_graph(f_graph, [])
    assert result == 42
Example #18
0
def test_remove_same_as():
    def nothing(x):
        return x

    def f():
        nothing(False)
        if nothing(True):
            return 42
        else:
            return 666

    t = TranslationContext()
    t.buildannotator().build_types(f, [])
    t.buildrtyper().specialize()
    # now we make the 'if True' appear
    f_graph = graphof(t, f)
    simple_inline_function(t, nothing, f_graph)
    # here, the graph looks like  v21=same_as(True);  exitswitch: v21
    remove_same_as(f_graph)
    t.checkgraphs()
    # only one path should be left
    for block in f_graph.iterblocks():
        assert len(block.exits) <= 1

    interp = LLInterpreter(t.rtyper)
    result = interp.eval_graph(f_graph, [])
    assert result == 42
Example #19
0
    def remove_obvious_noops():
        for graph in graphs:
            removenoops.remove_same_as(graph)
            simplify.eliminate_empty_blocks(graph)
            simplify.transform_dead_op_vars(graph, translator)
            removenoops.remove_duplicate_casts(graph, translator)

        if config.print_statistics:
            print "after no-op removal:"
            print_statistics(translator.graphs[0], translator)
Example #20
0
    def remove_obvious_noops():
        for graph in graphs:
            removenoops.remove_same_as(graph)
            simplify.eliminate_empty_blocks(graph)
            simplify.transform_dead_op_vars(graph, translator)
            removenoops.remove_duplicate_casts(graph, translator)

        if config.print_statistics:
            print "after no-op removal:"
            print_statistics(translator.graphs[0], translator)
Example #21
0
    def check_auto_inlining(
        self,
        func,
        sig,
        multiplier=None,
        call_count_check=False,
        remove_same_as=False,
        heuristic=None,
        const_fold_first=False,
    ):
        t = self.translate(func, sig)
        if const_fold_first:
            from rpython.translator.backendopt.constfold import constant_fold_graph
            from rpython.translator.simplify import eliminate_empty_blocks

            for graph in t.graphs:
                constant_fold_graph(graph)
                eliminate_empty_blocks(graph)
        if option.view:
            t.view()
        # inline!
        sanity_check(t)  # also check before inlining (so we don't blame it)

        threshold = INLINE_THRESHOLD_FOR_TEST
        if multiplier is not None:
            threshold *= multiplier

        call_count_pred = None
        if call_count_check:
            call_count_pred = lambda lbl: True
            instrument_inline_candidates(t.graphs, threshold)

        if remove_same_as:
            for graph in t.graphs:
                removenoops.remove_same_as(graph)

        if heuristic is not None:
            kwargs = {"heuristic": heuristic}
        else:
            kwargs = {}
        auto_inlining(t, threshold, call_count_pred=call_count_pred, **kwargs)

        sanity_check(t)
        if option.view:
            t.view()
        interp = LLInterpreter(t.rtyper)

        def eval_func(args):
            return interp.eval_graph(graphof(t, func), args)

        return eval_func, t
Example #22
0
def remove_mallocs(translator, graphs=None):
    if graphs is None:
        graphs = translator.graphs
    tot = 0
    for graph in graphs:
        count = remove_simple_mallocs(graph, verbose=translator.config.translation.verbose)
        if count:
            # remove typical leftovers from malloc removal
            removenoops.remove_same_as(graph)
            simplify.eliminate_empty_blocks(graph)
            simplify.transform_dead_op_vars(graph, translator)
            tot += count
    log.malloc("removed %d simple mallocs in total" % tot)
    return tot
Example #23
0
    def check_auto_inlining(self,
                            func,
                            sig,
                            multiplier=None,
                            call_count_check=False,
                            remove_same_as=False,
                            heuristic=None,
                            const_fold_first=False):
        t = self.translate(func, sig)
        if const_fold_first:
            from rpython.translator.backendopt.constfold import constant_fold_graph
            from rpython.translator.simplify import eliminate_empty_blocks
            for graph in t.graphs:
                constant_fold_graph(graph)
                eliminate_empty_blocks(graph)
        if option.view:
            t.view()
        # inline!
        sanity_check(t)  # also check before inlining (so we don't blame it)

        threshold = INLINE_THRESHOLD_FOR_TEST
        if multiplier is not None:
            threshold *= multiplier

        call_count_pred = None
        if call_count_check:
            call_count_pred = lambda lbl: True
            instrument_inline_candidates(t.graphs, threshold)

        if remove_same_as:
            for graph in t.graphs:
                removenoops.remove_same_as(graph)

        if heuristic is not None:
            kwargs = {"heuristic": heuristic}
        else:
            kwargs = {}
        auto_inlining(t, threshold, call_count_pred=call_count_pred, **kwargs)

        sanity_check(t)
        if option.view:
            t.view()
        interp = LLInterpreter(t.rtyper)

        def eval_func(args):
            return interp.eval_graph(graphof(t, func), args)

        return eval_func, t
Example #24
0
def test_merge_if_blocks_bug():
    def fn(n):
        if n == 1: return 5
        elif n == 2: return 6
        elif n == 3: return 8
        elif n == 4: return -123
        elif n == 5: return 12973
        else: return n
    
    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt.removenoops import remove_same_as
    from rpython.translator.backendopt import merge_if_blocks
    remove_same_as(graph)
    merge_if_blocks.merge_if_blocks_once(graph)
    constant_fold_graph(graph)
    check_graph(graph, [4], -123, t)
    check_graph(graph, [9], 9, t)
Example #25
0
def test_merge_if_blocks_bug_2():
    def fn():
        n = llop.same_as(lltype.Signed, 66)
        if n == 1: return 5
        elif n == 2: return 6
        elif n == 3: return 8
        elif n == 4: return -123
        elif n == 5: return 12973
        else: return n
    
    graph, t = get_graph(fn, [])
    from rpython.translator.backendopt.removenoops import remove_same_as
    from rpython.translator.backendopt import merge_if_blocks
    remove_same_as(graph)
    merge_if_blocks.merge_if_blocks_once(graph)
    constant_fold_graph(graph)
    check_graph(graph, [], 66, t)
Example #26
0
def test_merge_if_blocks_bug():
    def fn(n):
        if n == 1: return 5
        elif n == 2: return 6
        elif n == 3: return 8
        elif n == 4: return -123
        elif n == 5: return 12973
        else: return n
    
    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt.removenoops import remove_same_as
    from rpython.translator.backendopt import merge_if_blocks
    remove_same_as(graph)
    merge_if_blocks.merge_if_blocks_once(graph)
    constant_fold_graph(graph)
    check_graph(graph, [4], -123, t)
    check_graph(graph, [9], 9, t)
Example #27
0
def do_test_merge(fn, testvalues):
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [type(testvalues[0])])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, fn)
    assert len(list(graph.iterblocks())) == 4  #startblock, blocks, returnblock
    remove_same_as(graph)
    merge_if_blocks_once(graph)
    assert len(graph.startblock.exits) == 4
    assert len(list(graph.iterblocks())) == 2  #startblock, returnblock
    interp = LLInterpreter(rtyper)
    for i in testvalues:
        expected = fn(i)
        actual = interp.eval_graph(graph, [i])
        assert actual == expected
Example #28
0
def test_knownswitch_after_exitswitch():
    def fn(n):
        cond = n > 10
        if cond:
            return cond + 5
        else:
            return cond + 17

    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt import removenoops
    removenoops.remove_same_as(graph)
    constant_fold_graph(graph)
    if option.view:
        t.view()
    assert summary(graph) == {'int_gt': 1}
    check_graph(graph, [2], 17, t)
    check_graph(graph, [42], 6, t)
Example #29
0
def test_join_blocks_cleans_links():
    from rpython.rtyper.lltypesystem import lltype
    from rpython.flowspace.model import Constant
    from rpython.translator.backendopt.removenoops import remove_same_as
    def f(x):
        return bool(x + 2)
    def g(x):
        if f(x):
            return 1
        else:
            return 2
    graph, t = translate(g, [int], backend_optimize=False)
    fgraph = graphof(t, f)
    fgraph.startblock.exits[0].args = [Constant(True, lltype.Bool)]
    # does not crash: previously join_blocks would barf on this
    remove_same_as(graph)
    backend_optimizations(t)
Example #30
0
 def check(self, f, argtypes, no_getfields=0):
     t = self.translate(f, argtypes)
     getfields = 0
     graph = graphof(t, f)
     removenoops.remove_same_as(graph)
     checkgraph(graph)
     storesink_graph(graph)
     checkgraph(graph)
     if option.view:
         t.view()
     for block in graph.iterblocks():
         for op in block.operations:
             if op.opname == 'getfield':
                 getfields += 1
     if no_getfields != getfields:
         py.test.fail("Expected %d, got %d getfields" %
                      (no_getfields, getfields))
Example #31
0
 def check(self, f, argtypes, no_getfields=0):
     t = self.translate(f, argtypes)
     getfields = 0
     graph = graphof(t, f)
     removenoops.remove_same_as(graph)
     checkgraph(graph)
     storesink_graph(graph)
     checkgraph(graph)
     if option.view:
         t.view()
     for block in graph.iterblocks():
         for op in block.operations:
             if op.opname == 'getfield':
                 getfields += 1
     if no_getfields != getfields:
         py.test.fail("Expected %d, got %d getfields" %
                      (no_getfields, getfields))
Example #32
0
def test_merge_if_blocks_bug_2():
    def fn():
        n = llop.same_as(lltype.Signed, 66)
        if n == 1: return 5
        elif n == 2: return 6
        elif n == 3: return 8
        elif n == 4: return -123
        elif n == 5: return 12973
        else: return n
    
    graph, t = get_graph(fn, [])
    from rpython.translator.backendopt.removenoops import remove_same_as
    from rpython.translator.backendopt import merge_if_blocks
    remove_same_as(graph)
    merge_if_blocks.merge_if_blocks_once(graph)
    constant_fold_graph(graph)
    check_graph(graph, [], 66, t)
Example #33
0
def do_test_merge(fn, testvalues):
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [type(testvalues[0])])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, fn)
    assert len(list(graph.iterblocks())) == 4 #startblock, blocks, returnblock
    remove_same_as(graph)
    merge_if_blocks_once(graph)
    assert len(graph.startblock.exits) == 4
    assert len(list(graph.iterblocks())) == 2 #startblock, returnblock
    interp = LLInterpreter(rtyper)
    for i in testvalues:
        expected = fn(i)
        actual = interp.eval_graph(graph, [i])
        assert actual == expected
Example #34
0
def test_knownswitch_after_exitswitch():
    def fn(n):
        cond = n > 10
        if cond:
            return cond + 5
        else:
            return cond + 17

    graph, t = get_graph(fn, [int])
    from rpython.translator.backendopt import removenoops
    removenoops.remove_same_as(graph)
    constant_fold_graph(graph)
    if option.view:
        t.view()
    assert summary(graph) == {'int_gt': 1}
    check_graph(graph, [2], 17, t)
    check_graph(graph, [42], 6, t)
Example #35
0
def test_dont_merge():
    def merge(n, m):
        r = -1
        if n == 0:
            r += m
        if n == 1:
            r += 2 * m
        else:
            r += 6
        return r
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(merge, [int, int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, merge)
    remove_same_as(graph)
    blocknum = len(list(graph.iterblocks()))
    merge_if_blocks(graph)
    assert blocknum == len(list(graph.iterblocks()))
Example #36
0
def test_dont_merge():
    def merge(n, m):
        r = -1
        if n == 0:
            r += m
        if n == 1:
            r += 2 * m
        else:
            r += 6
        return r

    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(merge, [int, int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, merge)
    remove_same_as(graph)
    blocknum = len(list(graph.iterblocks()))
    merge_if_blocks(graph)
    assert blocknum == len(list(graph.iterblocks()))
Example #37
0
def test_merge_passonvars():
    def merge(n, m):
        if n == 1:
            return m + 1
        elif n == 2:
            return m + 2
        elif n == 3:
            return m + 3
        return m + 4
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(merge, [int, int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, merge)
    assert len(list(graph.iterblocks())) == 8
    remove_same_as(graph)
    merge_if_blocks_once(graph)
    assert len(graph.startblock.exits) == 4
    interp = LLInterpreter(rtyper)
    for i in range(1, 5):
        res = interp.eval_graph(graph, [i, 1])
        assert res == i + 1
Example #38
0
def test_merge_passonvars():
    def merge(n, m):
        if n == 1:
            return m + 1
        elif n == 2:
            return m + 2
        elif n == 3:
            return m + 3
        return m + 4

    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(merge, [int, int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = tgraphof(t, merge)
    assert len(list(graph.iterblocks())) == 8
    remove_same_as(graph)
    merge_if_blocks_once(graph)
    assert len(graph.startblock.exits) == 4
    interp = LLInterpreter(rtyper)
    for i in range(1, 5):
        res = interp.eval_graph(graph, [i, 1])
        assert res == i + 1
Example #39
0
def test_switch_on_symbolic():
    symb1 = CDefinedIntSymbolic("1", 1)
    symb2 = CDefinedIntSymbolic("2", 2)
    symb3 = CDefinedIntSymbolic("3", 3)
    def fn(x):
        res = 0
        if x == symb1:
            res += x + 1
        elif x == symb2:
            res += x + 2
        elif x == symb3:
            res += x + 3
        res += 1
        return res
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = t.graphs[0]
    remove_same_as(graph)
    res = merge_if_blocks_once(graph)
    assert not res
    checkgraph(graph)
Example #40
0
def partial_escape(translator, graph):
    """
    Main function.
    Blocks, which we'll work on, are in a dequeue, called "worklist", and are
    indexing link-state tuples in "statemap".
    """
    insert_links(graph)
    worklist = deque([graph.startblock])
    statemap = defaultdict(list)
    statemap[graph.startblock] = [(None, {})]
    finished = set()
    entrymap = mkentrymap(graph)
    backedges = find_backedges(graph)

    number_getfield_removed = 0

    while worklist:
        block = worklist.popleft()
        must_be_materialized = block.is_final_block()
        for link in entrymap[block]:
            if link in backedges:
                must_be_materialized = True
        state = get_current_state(statemap[block],
                                  must_be_materialized=must_be_materialized)
        if block.is_final_block():
            continue

        new_operations = []
        # Going through the operations
        for op in block.operations:
            if op.opname == 'malloc':
                # Create new entry for every allocation that is not returned
                if can_remove(op):
                    vobj = VirtualObject(op.result.concretetype, op.args)
                    state[op.result] = vobj
                    vobj.aliases.add(op.result)
                else:
                    new_operations.append(op)
            elif op.opname == 'cast_pointer':
                if op.args[0] in state:
                    # Creating something like an 'alias' for the casting
                    state[op.result] = vobj = state[op.args[0]]
                    vobj.aliases.add(op.result)
                else:
                    new_operations.append(op)
            elif op.opname == 'setfield':
                if op.args[0] in state:
                    state[op.args[0]].vars[op.args[1].value,
                                           op.args[0].concretetype] = op.args[2]
                else:
                    materialize_object(op.args[2], state, new_operations)
                    new_operations.append(op)
            elif op.opname == 'getfield':
                key = op.args[1].value, op.args[0].concretetype
                if op.args[0] in state and key in state[op.args[0]].vars:
                    targ = state[op.args[0]].vars[key]
                    number_getfield_removed += 1
                    if targ in state:
                        state[op.result] = vobj = state[targ]
                        state[targ].aliases.add(vobj)
                    else:
                        new_operations.append(SpaceOperation('same_as',
                                                             [targ],
                                                             op.result))
                else:
                    materialize_object(op.args[0], state, new_operations)
                    new_operations.append(op)
            else:
                for arg in op.args:
                    materialize_object(arg, state, new_operations)
                new_operations.append(op)
        # for all backedges, materialize all arguments (loops aren't supported
        # properly yet)
        for exit in block.exits:
            if exit in backedges or exit.target.is_final_block():
                for arg in exit.args:
                    materialize_object(arg, state, new_operations)
        block.operations = new_operations

        # We're done with the internals of the block. Editing the lists:
        finished.add(block)
        for exit in block.exits:
            # Only adding to the worklist if all its ancestors are processed
            for lnk in entrymap[exit.target]:
                if lnk.prevblock not in finished and lnk not in backedges:
                    break
            else:
                if exit.target not in finished and exit.target not in worklist: # XXX
                    worklist.append(exit.target)
            # setting statemaps:
            statemap[exit.target].append((exit, state))
    if number_getfield_removed:
        if translator.config.translation.verbose:
            log.cse("partial escape analysis removed %s getfields in graph %s" % (number_getfield_removed, graph))
        else:
            log.dot()

    # Done. Cleaning up.
    remove_same_as(graph)
    transform_dead_op_vars(graph)
    eliminate_empty_blocks(graph)
    join_blocks(graph)
    checkgraph(graph)

    return number_getfield_removed