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
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
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
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
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
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
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