Example #1
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 #2
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 #3
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 #4
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 #5
0
 def simplify(self, block_subset=None, extra_passes=None):
     # Generic simplifications
     transform.transform_graph(self, block_subset=block_subset,
                               extra_passes=extra_passes)
     if block_subset is None:
         graphs = self.translator.graphs
     else:
         graphs = {}
         for block in block_subset:
             graph = self.annotated.get(block)
             if graph:
                 graphs[graph] = True
     for graph in graphs:
         simplify.eliminate_empty_blocks(graph)
Example #6
0
def remove_asserts(translator, graphs):
    rtyper = translator.rtyper
    excdata = rtyper.exceptiondata
    clsdef = translator.annotator.bookkeeper.getuniqueclassdef(AssertionError)
    ll_AssertionError = excdata.get_standard_ll_exc_instance(rtyper, clsdef)
    total_count = [0, 0]

    for graph in graphs:
        count = 0
        morework = True
        while morework:
            morework = False
            eliminate_empty_blocks(graph)
            join_blocks(graph)
            for link in graph.iterlinks():
                if (link.target is graph.exceptblock
                        and isinstance(link.args[1], Constant)
                        and link.args[1].value == ll_AssertionError):
                    if kill_assertion_link(graph, link):
                        count += 1
                        morework = True
                        break
                    else:
                        total_count[0] += 1
                        if translator.config.translation.verbose:
                            log.removeassert(
                                "cannot remove an assert from %s" %
                                (graph.name, ))
        if count:
            # now melt away the (hopefully) dead operation that compute
            # the condition
            total_count[1] += count
            if translator.config.translation.verbose:
                log.removeassert("removed %d asserts in %s" %
                                 (count, graph.name))
            checkgraph(graph)
    total_count = tuple(total_count)
    if total_count[0] == 0:
        if total_count[1] == 0:
            msg = None
        else:
            msg = "Removed %d asserts" % (total_count[1], )
    else:
        if total_count[1] == 0:
            msg = "Could not remove %d asserts" % (total_count[0], )
        else:
            msg = "Could not remove %d asserts, but removed %d asserts." % total_count
    if msg is not None:
        log.removeassert(msg)
Example #7
0
 def simplify(self, block_subset=None, extra_passes=None):
     # Generic simplifications
     transform.transform_graph(self,
                               block_subset=block_subset,
                               extra_passes=extra_passes)
     if block_subset is None:
         graphs = self.translator.graphs
     else:
         graphs = {}
         for block in block_subset:
             graph = self.annotated.get(block)
             if graph:
                 graphs[graph] = True
     for graph in graphs:
         simplify.eliminate_empty_blocks(graph)
Example #8
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 #9
0
def remove_asserts(translator, graphs):
    rtyper = translator.rtyper
    excdata = rtyper.exceptiondata
    clsdef = translator.annotator.bookkeeper.getuniqueclassdef(AssertionError)
    ll_AssertionError = excdata.get_standard_ll_exc_instance(rtyper, clsdef)
    total_count = [0, 0]

    for graph in graphs:
        count = 0
        morework = True
        while morework:
            morework = False
            eliminate_empty_blocks(graph)
            join_blocks(graph)
            for link in graph.iterlinks():
                if (link.target is graph.exceptblock
                    and isinstance(link.args[1], Constant)
                    and link.args[1].value == ll_AssertionError):
                    if kill_assertion_link(graph, link):
                        count += 1
                        morework = True
                        break
                    else:
                        total_count[0] += 1
                        if translator.config.translation.verbose:
                            log.removeassert("cannot remove an assert from %s" % (graph.name,))
        if count:
            # now melt away the (hopefully) dead operation that compute
            # the condition
            total_count[1] += count
            if translator.config.translation.verbose:
                log.removeassert("removed %d asserts in %s" % (count, graph.name))
            checkgraph(graph)
    total_count = tuple(total_count)
    if total_count[0] == 0:
        if total_count[1] == 0:
            msg = None
        else:
            msg = "Removed %d asserts" % (total_count[1],)
    else:
        if total_count[1] == 0:
            msg = "Could not remove %d asserts" % (total_count[0],)
        else:
            msg = "Could not remove %d asserts, but removed %d asserts." % total_count
    if msg is not None:
        log.removeassert(msg)
Example #10
0
def remove_tail_calls_to_self(translator, graph):
    entrymap = mkentrymap(graph)
    changed = False
    for link in entrymap[graph.returnblock]:
        block = link.prevblock
        if (len(block.exits) == 1 and len(block.operations) > 0
                and block.operations[-1].opname == 'direct_call'
                and block.operations[-1].result == link.args[0]):
            print "getgraph", graph
            if graph is graph:
                _remove_tail_call(translator, graph, block)
                changed = True
    if changed:
        from rpython.translator import simplify
        checkgraph(graph)
        simplify.remove_identical_vars(graph)
        simplify.eliminate_empty_blocks(graph)
        simplify.join_blocks(graph)
Example #11
0
def remove_tail_calls_to_self(translator, graph):
    entrymap = mkentrymap(graph)
    changed = False
    for link in entrymap[graph.returnblock]:
        block = link.prevblock
        if (len(block.exits) == 1 and
            len(block.operations) > 0 and
            block.operations[-1].opname == 'direct_call' and
            block.operations[-1].result == link.args[0]):
            print "getgraph", graph
            if graph is graph:
                _remove_tail_call(translator, graph, block)
                changed = True
    if changed:
        from rpython.translator import simplify
        checkgraph(graph)
        simplify.remove_identical_vars(graph)
        simplify.eliminate_empty_blocks(graph)
        simplify.join_blocks(graph)
Example #12
0
def tweak_generator_body_graph(Entry, graph):
    # First, always run simplify_graph in order to reduce the number of
    # variables passed around
    simplify_graph(graph)
    insert_empty_startblock(graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    op0 = op.simple_call(const(StopIteration))
    op1 = op.type(op0.result)
    stopblock.operations = [op0, op1]
    stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock))
    #
    for block in list(graph.iterblocks()):
        for exit in block.exits:
            if exit.target is graph.returnblock:
                exit.args = []
                exit.target = stopblock
        assert block is not stopblock
        for index in range(len(block.operations) - 1, -1, -1):
            hlop = block.operations[index]
            if hlop.opname == 'yield_':
                [v_yielded_value] = hlop.args
                del block.operations[index]
                newlink = split_block(block, index)
                newblock = newlink.target

                #
                class Resume(AbstractPosition):
                    _immutable_ = True
                    block = newblock

                Resume.__name__ = 'Resume%d' % len(mappings)
                mappings.append(Resume)
                varnames = get_variable_names(newlink.args)
                #
                _insert_reads(newblock, varnames)
                #
                op_resume = op.simple_call(const(Resume))
                block.operations.append(op_resume)
                v_resume = op_resume.result
                for i, name in enumerate(varnames):
                    block.operations.append(
                        op.setattr(v_resume, const(name), newlink.args[i]))
                op_pair = op.newtuple(v_resume, v_yielded_value)
                block.operations.append(op_pair)
                newlink.args = [op_pair.result]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        op_check = op.isinstance(block.inputargs[0], const(Resume))
        block.operations.append(op_check)
        block.exitswitch = op_check.result
        link1 = Link([block.inputargs[0]], Resume.block)
        link1.exitcase = True
        nextblock = Block([Variable('entry')])
        link2 = Link([block.inputargs[0]], nextblock)
        link2.exitcase = False
        block.closeblock(link1, link2)
        block = nextblock
    block.closeblock(
        Link([
            Constant(AssertionError),
            Constant(AssertionError("bad generator class"))
        ], graph.exceptblock))
    graph.startblock = regular_entry_block
    graph.signature = Signature(['entry'])
    graph.defaults = ()
    checkgraph(graph)
    eliminate_empty_blocks(graph)
Example #13
0
def tweak_generator_body_graph(Entry, graph):
    # First, always run simplify_graph in order to reduce the number of
    # variables passed around
    simplify_graph(graph)
    insert_empty_startblock(None, graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    op0 = op.simple_call(const(StopIteration))
    op1 = op.type(op0.result)
    stopblock.operations = [op0, op1]
    stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock))
    #
    for block in list(graph.iterblocks()):
        for exit in block.exits:
            if exit.target is graph.returnblock:
                exit.args = []
                exit.target = stopblock
        assert block is not stopblock
        for index in range(len(block.operations)-1, -1, -1):
            hlop = block.operations[index]
            if hlop.opname == 'yield_':
                [v_yielded_value] = hlop.args
                del block.operations[index]
                newlink = split_block(None, block, index)
                newblock = newlink.target
                #
                class Resume(AbstractPosition):
                    _immutable_ = True
                    block = newblock
                Resume.__name__ = 'Resume%d' % len(mappings)
                mappings.append(Resume)
                varnames = get_variable_names(newlink.args)
                #
                _insert_reads(newblock, varnames)
                #
                op_resume = op.simple_call(const(Resume))
                block.operations.append(op_resume)
                v_resume = op_resume.result
                for i, name in enumerate(varnames):
                    block.operations.append(
                        op.setattr(v_resume, const(name), newlink.args[i]))
                op_pair = op.newtuple(v_resume, v_yielded_value)
                block.operations.append(op_pair)
                newlink.args = [op_pair.result]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        op_check = op.simple_call(
            const(isinstance), block.inputargs[0], const(Resume))
        block.operations.append(op_check)
        block.exitswitch = op_check.result
        link1 = Link([block.inputargs[0]], Resume.block)
        link1.exitcase = True
        nextblock = Block([Variable('entry')])
        link2 = Link([block.inputargs[0]], nextblock)
        link2.exitcase = False
        block.closeblock(link1, link2)
        block = nextblock
    block.closeblock(Link([Constant(AssertionError),
                           Constant(AssertionError("bad generator class"))],
                          graph.exceptblock))
    graph.startblock = regular_entry_block
    graph.signature = Signature(['entry'])
    graph.defaults = ()
    checkgraph(graph)
    eliminate_empty_blocks(graph)
Example #14
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
Example #15
0
def tweak_generator_body_graph(Entry, graph):
    # First, always run simplify_graph in order to reduce the number of
    # variables passed around
    simplify_graph(graph)
    #
    assert graph.startblock.operations[0].opname == 'generator_mark'
    graph.startblock.operations.pop(0)
    #
    insert_empty_startblock(None, graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    v0 = Variable()
    v1 = Variable()
    stopblock.operations = [
        SpaceOperation('simple_call', [Constant(StopIteration)], v0),
        SpaceOperation('type', [v0], v1),
        ]
    stopblock.closeblock(Link([v1, v0], graph.exceptblock))
    #
    for block in list(graph.iterblocks()):
        for exit in block.exits:
            if exit.target is graph.returnblock:
                exit.args = []
                exit.target = stopblock
        assert block is not stopblock
        for index in range(len(block.operations)-1, -1, -1):
            op = block.operations[index]
            if op.opname == 'yield':
                [v_yielded_value] = op.args
                del block.operations[index]
                newlink = split_block(None, block, index)
                newblock = newlink.target
                #
                class Resume(AbstractPosition):
                    _immutable_ = True
                    block = newblock
                Resume.__name__ = 'Resume%d' % len(mappings)
                mappings.append(Resume)
                varnames = get_variable_names(newlink.args)
                #
                _insert_reads(newblock, varnames)
                #
                v_resume = Variable('resume')
                block.operations.append(
                    SpaceOperation('simple_call', [Constant(Resume)],
                                   v_resume))
                for i, name in enumerate(varnames):
                    block.operations.append(
                        SpaceOperation('setattr', [v_resume, Constant(name),
                                                   newlink.args[i]],
                                       Variable()))
                v_pair = Variable('pair')
                block.operations.append(
                    SpaceOperation('newtuple', [v_resume, v_yielded_value],
                                   v_pair))
                newlink.args = [v_pair]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        v_check = Variable()
        block.operations.append(
            SpaceOperation('simple_call', [Constant(isinstance),
                                           block.inputargs[0],
                                           Constant(Resume)],
                           v_check))
        block.exitswitch = v_check
        link1 = Link([block.inputargs[0]], Resume.block)
        link1.exitcase = True
        nextblock = Block([Variable('entry')])
        link2 = Link([block.inputargs[0]], nextblock)
        link2.exitcase = False
        block.closeblock(link1, link2)
        block = nextblock
    block.closeblock(Link([Constant(AssertionError),
                           Constant(AssertionError("bad generator class"))],
                          graph.exceptblock))
    graph.startblock = regular_entry_block
    graph.signature = Signature(['entry'])
    graph.defaults = ()
    checkgraph(graph)
    eliminate_empty_blocks(graph)