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)
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
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 pypy.translator.backendopt import malloc, inline inline.auto_inlining(t, 20) malloc.remove_mallocs(t, t.graphs) from pypy.translator import simplify simplify.join_blocks(graph)
def test_remove_same_as_nonconst(): from pypy.rlib.nonconst import NonConstant from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.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
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)
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
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 pypy.translator.backendopt import removenoops, inline inline.auto_inline_graphs(t, t.graphs, threshold=999) removenoops.remove_same_as(graph) constant_fold_graph(graph) if conftest.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)
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
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 pypy.translator.backendopt import removenoops, inline inline.auto_inline_graphs(t, t.graphs, threshold=999) constant_fold_graph(graph) removenoops.remove_same_as(graph) if conftest.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)
def test_remove_same_as_nonconst(): from pypy.rlib.nonconst import NonConstant from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.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
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 pypy.translator.backendopt import removenoops, inline inline.auto_inline_graphs(t, t.graphs, threshold=999) constant_fold_graph(graph) removenoops.remove_same_as(graph) if conftest.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)
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 pypy.translator.backendopt import removenoops, inline inline.auto_inline_graphs(t, t.graphs, threshold=999) removenoops.remove_same_as(graph) constant_fold_graph(graph) if conftest.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)
def check_auto_inlining(self, func, sig, multiplier=None, call_count_check=False, checkvirtual=False, remove_same_as=False): t = self.translate(func, sig) if checkvirtual: check_virtual_methods() 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) auto_inlining(t, threshold, call_count_pred=call_count_pred) 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
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 pypy.translator.backendopt import malloc, inline inline.auto_inlining(t, 20) malloc.remove_mallocs(t, t.graphs) from pypy.translator import simplify simplify.join_blocks(graph)
def check_auto_inlining(self, func, sig, multiplier=None, call_count_check=False, checkvirtual=False, remove_same_as=False): t = self.translate(func, sig) if checkvirtual: check_virtual_methods() 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) auto_inlining(t, threshold, call_count_pred=call_count_pred) 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
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
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)
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)
def check_auto_inlining(self, func, sig, multiplier=None, call_count_check=False, checkvirtual=False, remove_same_as=False, heuristic=None, const_fold_first=False): t = self.translate(func, sig) if checkvirtual: check_virtual_methods() if const_fold_first: from pypy.translator.backendopt.constfold import constant_fold_graph from pypy.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
def remove_mallocs(translator, graphs=None, type_system="lltypesystem"): if graphs is None: graphs = translator.graphs tot = 0 for graph in graphs: count = remove_simple_mallocs(graph, type_system=type_system, 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
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 pypy.translator.backendopt import removenoops removenoops.remove_same_as(graph) constant_fold_graph(graph) if conftest.option.view: t.view() assert summary(graph) == {'int_gt': 1} check_graph(graph, [2], 17, t) check_graph(graph, [42], 6, t)
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 pypy.translator.backendopt.removenoops import remove_same_as from pypy.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)
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 pypy.translator.backendopt.removenoops import remove_same_as from pypy.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)
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))
def test_join_blocks_cleans_links(): from pypy.rpython.lltypesystem import lltype from pypy.objspace.flow.model import Constant from pypy.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)
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
def remove_mallocs(translator, graphs=None, type_system="lltypesystem"): if graphs is None: graphs = translator.graphs tot = 0 for graph in graphs: count = remove_simple_mallocs( graph, type_system=type_system, 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
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))
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
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 pypy.translator.backendopt import removenoops removenoops.remove_same_as(graph) constant_fold_graph(graph) if conftest.option.view: t.view() assert summary(graph) == {'int_gt': 1} check_graph(graph, [2], 17, t) check_graph(graph, [42], 6, t)
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 pypy.translator.backendopt.removenoops import remove_same_as from pypy.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)
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 pypy.translator.backendopt.removenoops import remove_same_as from pypy.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)
def check_auto_inlining(self, func, sig, multiplier=None, call_count_check=False, checkvirtual=False, remove_same_as=False, heuristic=None, const_fold_first=False): t = self.translate(func, sig) if checkvirtual: check_virtual_methods() if const_fold_first: from pypy.translator.backendopt.constfold import constant_fold_graph from pypy.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
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()))
def test_ignore_breaking_transformations(): def f(): pass f._annspecialcase_ = "override:ignore" def g(i): if i == 1: return "ab" else: try: return f() except: return "hello!" t, typer, graph = gengraph(g, [int]) from pypy.translator import simplify from pypy.translator.backendopt import removenoops from pypy.objspace.flow.model import checkgraph removenoops.remove_same_as(graph) simplify.eliminate_empty_blocks(graph) #should not crash: checkgraph(graph)
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()))
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
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
def backend_optimizations(translator, graphs=None, secondary=False, **kwds): # sensible keywords are # raisingop2direct_call, inline_threshold, mallocs # merge_if_blocks, constfold, heap2stack # clever_malloc_removal, remove_asserts config = translator.config.translation.backendopt.copy(as_default=True) config.set(**kwds) if graphs is None: graphs = translator.graphs if config.print_statistics: print "before optimizations:" print_statistics(translator.graphs[0], translator, "per-graph.txt") if config.raisingop2direct_call: raisingop2direct_call(translator, graphs) if translator.rtyper.type_system.name == 'ootypesystem': check_virtual_methods() # remove obvious no-ops 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) if config.inline or config.mallocs: heuristic = get_function(config.inline_heuristic) if config.inline: threshold = config.inline_threshold else: threshold = 0 inline_malloc_removal_phase(config, translator, graphs, threshold, inline_heuristic=heuristic) constfold(config, graphs) if config.clever_malloc_removal: threshold = config.clever_malloc_removal_threshold heuristic = get_function(config.clever_malloc_removal_heuristic) log.inlineandremove("phase with threshold factor: %s" % threshold) log.inlineandremove("heuristic: %s.%s" % (heuristic.__module__, heuristic.__name__)) count = mallocprediction.clever_inlining_and_malloc_removal( translator, graphs, threshold = threshold, heuristic=heuristic) log.inlineandremove("removed %d simple mallocs in total" % count) constfold(config, graphs) if config.print_statistics: print "after clever inlining and malloc removal" print_statistics(translator.graphs[0], translator) if config.profile_based_inline and not secondary: threshold = config.profile_based_inline_threshold heuristic = get_function(config.profile_based_inline_heuristic) inline.instrument_inline_candidates(graphs, threshold) counters = translator.driver_instrument_result( config.profile_based_inline) n = len(counters) def call_count_pred(label): if label >= n: return False return counters[label] > 250 # xxx introduce an option for this inline_malloc_removal_phase(config, translator, graphs, threshold, inline_heuristic=heuristic, call_count_pred=call_count_pred) constfold(config, graphs) if config.remove_asserts: remove_asserts(translator, graphs) if config.heap2stack: assert graphs is translator.graphs # XXX for now malloc_to_stack(translator) if config.merge_if_blocks: log.mergeifblocks("starting to merge if blocks") for graph in graphs: merge_if_blocks(graph, translator.config.translation.verbose) if config.print_statistics: print "after if-to-switch:" print_statistics(translator.graphs[0], translator) for graph in graphs: checkgraph(graph)