Beispiel #1
0
def test_find_loop_blocks3():
    import os

    def ps(loops):
        return 42.0, 42.1

    def f(loops):
        benchtime, stones = ps(abs(loops))
        s = ""  # annotator happiness
        if loops >= 0:
            s = (
                "RPystone(%s) time for %d passes = %f" % (23, loops, benchtime)
                + "\n"
                + ("This machine benchmarks at %f pystones/second" % stones)
            )
        os.write(1, s)
        if loops == 12345:
            f(loops - 1)

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert backedges == []
    loop_blocks = find_loop_blocks(graph)
    assert len(loop_blocks) == 0
Beispiel #2
0
def test_find_loop_blocks3():
    import os

    def ps(loops):
        return 42.0, 42.1

    def f(loops):
        benchtime, stones = ps(abs(loops))
        s = ''  # annotator happiness
        if loops >= 0:
            s = ("RPystone(%s) time for %d passes = %f" %
                 (23, loops, benchtime) + '\n' +
                 ("This machine benchmarks at %f pystones/second" % stones))
        os.write(1, s)
        if loops == 12345:
            f(loops - 1)

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert backedges == []
    loop_blocks = find_loop_blocks(graph)
    assert len(loop_blocks) == 0
Beispiel #3
0
def test_find_loop_blocks_simple():
    def f(a):
        if a <= 0:
            return 1
        return f(a - 1)

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert backedges == []
    loop_blocks = find_loop_blocks(graph)
    assert len(loop_blocks) == 0
Beispiel #4
0
def test_find_loop_blocks_simple():
    def f(a):
        if a <= 0:
            return 1
        return f(a - 1)

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert backedges == []
    loop_blocks = find_loop_blocks(graph)
    assert len(loop_blocks) == 0
Beispiel #5
0
def test_find_backedges():
    def f(k):
        result = 0
        for i in range(k):
            result += 1
        for j in range(k):
            result += 1
        return result

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert len(backedges) == 2
Beispiel #6
0
def test_find_backedges():
    def f(k):
        result = 0
        for i in range(k):
            result += 1
        for j in range(k):
            result += 1
        return result

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert len(backedges) == 2
Beispiel #7
0
def test_find_loop_blocks2():
    class A:
        pass

    def f(n):
        a1 = A()
        a1.x = 1
        a2 = A()
        a2.x = 2
        if n > 0:
            a = a1
        else:
            a = a2
        return a.x

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert backedges == []
    loop_blocks = find_loop_blocks(graph)
    assert len(loop_blocks) == 0
Beispiel #8
0
def test_find_loop_blocks2():
    class A:
        pass

    def f(n):
        a1 = A()
        a1.x = 1
        a2 = A()
        a2.x = 2
        if n > 0:
            a = a1
        else:
            a = a2
        return a.x

    t = TranslationContext()
    t.buildannotator().build_types(f, [int])
    t.buildrtyper().specialize()
    graph = graphof(t, f)
    backedges = find_backedges(graph)
    assert backedges == []
    loop_blocks = find_loop_blocks(graph)
    assert len(loop_blocks) == 0
Beispiel #9
0
    def look_inside_graph(self, graph):
        from rpython.translator.backendopt.support import find_backedges
        contains_loop = bool(find_backedges(graph))
        try:
            func = graph.func
        except AttributeError:
            see_function = True
        else:
            if hasattr(func, '_jit_look_inside_'):
                see_function = func._jit_look_inside_   # override guessing
            else:
                see_function = (self.look_inside_function(func) and not
                                self._reject_function(func))
            contains_loop = contains_loop and not getattr(
                    func, '_jit_unroll_safe_', False)

        res = see_function and not contains_unsupported_variable_type(graph,
                            self.supports_floats,
                            self.supports_longlong,
                            self.supports_singlefloats)
        if res and contains_loop:
            self.unsafe_loopy_graphs.add(graph)
        res = res and not contains_loop
        if (see_function and not res and
            getattr(graph, "access_directly", False)):
            # This happens when we have a function which has an argument with
            # the access_directly flag, and the annotator has determined we will
            # see the function. (See
            # pypy/annotation/specialize.py:default_specialize) However,
            # look_inside_graph just decided that we will not see it. (It has a
            # loop or unsupported variables.) If we return False, the call will
            # be turned into a residual call, but the graph is access_directly!
            # If such a function is called and accesses a virtualizable, the JIT
            # will not notice, and the virtualizable will fall out of sync. So,
            # we fail loudly now.
            raise ValueError("access_directly on a function which we don't see %s" % graph)
        return res
Beispiel #10
0
    def look_inside_graph(self, graph):
        from rpython.translator.backendopt.support import find_backedges
        contains_loop = bool(find_backedges(graph))
        try:
            func = graph.func
        except AttributeError:
            see_function = True
        else:
            if hasattr(func, '_jit_look_inside_'):
                see_function = func._jit_look_inside_   # override guessing
            else:
                see_function = (self.look_inside_function(func) and not
                                self._reject_function(func))
            contains_loop = contains_loop and not getattr(
                    func, '_jit_unroll_safe_', False)

        res = see_function and not contains_unsupported_variable_type(graph,
                            self.supports_floats,
                            self.supports_longlong,
                            self.supports_singlefloats)
        if res and contains_loop:
            self.unsafe_loopy_graphs.add(graph)
        res = res and not contains_loop
        if (see_function and not res and
            getattr(graph, "access_directly", False)):
            # This happens when we have a function which has an argument with
            # the access_directly flag, and the annotator has determined we will
            # see the function. (See
            # pypy/annotation/specialize.py:default_specialize) However,
            # look_inside_graph just decided that we will not see it. (It has a
            # loop or unsupported variables.) If we return False, the call will
            # be turned into a residual call, but the graph is access_directly!
            # If such a function is called and accesses a virtualizable, the JIT
            # will not notice, and the virtualizable will fall out of sync. So,
            # we fail loudly now.
            raise ValueError("access_directly on a function which we don't see %s" % graph)
        return res
Beispiel #11
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