def check(self, fn, signature, args, expected_result, must_be_removed=True, inline=None): remover = self.MallocRemover() t = TranslationContext() t.buildannotator().build_types(fn, signature) t.buildrtyper(type_system=self.type_system).specialize() graph = graphof(t, fn) if inline is not None: from pypy.translator.backendopt.inline import auto_inline_graphs auto_inline_graphs(t, t.graphs, inline) if option.view: t.view() # to detect missing keepalives and broken intermediate graphs, # we do the loop ourselves instead of calling remove_simple_mallocs() while True: progress = remover.remove_mallocs_once(graph) simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks())) if progress and option.view: t.view() if expected_result is not Ellipsis: interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, args) assert res == expected_result if not progress: break if must_be_removed: self.check_malloc_removed(graph) return 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 test_funny_links(): from pypy.objspace.flow.model import Block, FunctionGraph, \ SpaceOperation, Variable, Constant, Link for i in range(2): v_i = Variable("i") v_case = Variable("case") block = Block([v_i]) g = FunctionGraph("is_one", block) block.operations.append( SpaceOperation("eq", [v_i, Constant(1)], v_case)) block.exitswitch = v_case tlink = Link([Constant(1)], g.returnblock, True) flink = Link([Constant(0)], g.returnblock, False) links = [tlink, flink] if i: links.reverse() block.closeblock(*links) t = TranslationContext() a = t.buildannotator() a.build_graph_types(g, [annmodel.SomeInteger()]) rtyper = t.buildrtyper() rtyper.specialize() interp = LLInterpreter(rtyper) assert interp.eval_graph(g, [1]) == 1 assert interp.eval_graph(g, [0]) == 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
def test_stackless_simple(): def g(x): return x + 1 class A(object): pass def entrypoint(argv): a = A() a.b = g(1) return a.b from pypy.rpython.llinterp import LLInterpreter from pypy.translator.c.genc import CStandaloneBuilder from pypy.translator.c import gc from pypy.annotation.listdef import s_list_of_strings t = rtype(entrypoint, [s_list_of_strings]) cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=StacklessFrameworkGcPolicy2) db = cbuild.generate_graphs_for_llinterp() entrypointptr = cbuild.getentrypointptr() entrygraph = entrypointptr._obj.graph r_list_of_strings = t.rtyper.getrepr(s_list_of_strings) ll_argv = r_list_of_strings.convert_const([]) llinterp = LLInterpreter(t.rtyper) # FIIIIISH setupgraph = db.gctransformer.frameworkgc_setup_ptr.value._obj.graph llinterp.eval_graph(setupgraph, []) res = llinterp.eval_graph(entrygraph, [ll_argv]) assert res == 2
def check_graph(graph, args, expected_result, t): if conftest.option.view: t.view() checkgraph(graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, args) assert res == expected_result
def rtype(self, fn, argtypes, resulttype, checkfunction=None): t = TranslationContext() a = t.buildannotator() a.build_types(prefn, [int]) typer = t.buildrtyper() typer.specialize() #t.view() s_result = a.typeannotation(resulttype) from pypy.rpython import annlowlevel # annotate, normalize and rtype fn after the fact annhelper = annlowlevel.MixLevelHelperAnnotator(typer) graph = annhelper.getgraph( fn, [a.typeannotation(argtype) for argtype in argtypes], s_result) annhelper.finish() t.checkgraphs() if checkfunction is not None: checkfunction(t) # sanity check prefn llinterp = LLInterpreter(typer) res = llinterp.eval_graph(graphof(t, prefn), [1]) assert res == 100 res = llinterp.eval_graph(graphof(t, prefn), [2]) assert res == 201 return t
def check(self, fn, signature, args, expected_result, expected_mallocs=0, expected_calls=0): t = TranslationContext() self.translator = t t.buildannotator().build_types(fn, signature) t.buildrtyper(type_system=self.type_system).specialize() graph = graphof(t, fn) if option.view: t.view() self.original_graph_count = len(t.graphs) # to detect broken intermediate graphs, # we do the loop ourselves instead of calling remove_simple_mallocs() maxiter = 100 mallocv = MallocVirtualizer(t.graphs, t.rtyper, verbose=True) while True: progress = mallocv.remove_mallocs_once() #simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks())) if progress and option.view: t.view() t.checkgraphs() if expected_result is not DONT_CHECK_RESULT: interp = LLInterpreter(t.rtyper) if not isinstance(expected_result, CHECK_RAISES): res = interp.eval_graph(graph, args) assert res == expected_result else: excinfo = py.test.raises(LLException, interp.eval_graph, graph, args) assert expected_result.excname in str(excinfo.value) if not progress: break maxiter -= 1 assert maxiter > 0, "infinite loop?" self.check_malloc_removed(graph, expected_mallocs, expected_calls) return 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_framework_simple(): def g(x): return x + 1 class A(object): pass def entrypoint(argv): a = A() a.b = g(1) return str(a.b) from pypy.rpython.llinterp import LLInterpreter from pypy.translator.c.genc import CStandaloneBuilder from pypy.translator.c import gc from pypy.annotation.listdef import s_list_of_strings t = rtype(entrypoint, [s_list_of_strings]) cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=FrameworkGcPolicy2) db = cbuild.generate_graphs_for_llinterp() entrypointptr = cbuild.getentrypointptr() entrygraph = entrypointptr._obj.graph r_list_of_strings = t.rtyper.getrepr(s_list_of_strings) ll_argv = r_list_of_strings.convert_const([]) llinterp = LLInterpreter(t.rtyper) # FIIIIISH setupgraph = db.gctransformer.frameworkgc_setup_ptr.value._obj.graph llinterp.eval_graph(setupgraph, []) res = llinterp.eval_graph(entrygraph, [ll_argv]) assert ''.join(res.chars) == "2"
def test_pseudohighlevelcallable(): t = TranslationContext() t.buildannotator() rtyper = t.buildrtyper() rtyper.specialize() a = MixLevelHelperAnnotator(rtyper) class A: value = 5 def double(self): return self.value * 2 def fn1(a): a2 = A() a2.value = a.double() return a2 s_A, r_A = a.s_r_instanceof(A) fn1ptr = a.delayedfunction(fn1, [s_A], s_A) pseudo = PseudoHighLevelCallable(fn1ptr, [s_A], s_A) def fn2(n): a = A() a.value = n a2 = pseudo(a) return a2.value graph = a.getgraph(fn2, [annmodel.SomeInteger()], annmodel.SomeInteger()) a.finish() llinterp = LLInterpreter(rtyper) res = llinterp.eval_graph(graph, [21]) assert res == 42
def test_split_block_exceptions(): for i in range(2): def raises(x): if x == 1: raise ValueError elif x == 2: raise KeyError return x def catches(x): try: y = x + 1 raises(y) except ValueError: return 0 except KeyError: return 1 return x graph, t = translate(catches, [int]) split_block(t.annotator, graph.startblock, i) checkgraph(graph) interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graph, [0]) assert result == 0 result = interp.eval_graph(graph, [1]) assert result == 1 result = interp.eval_graph(graph, [2]) assert result == 2
def check(self, fn, signature, args, expected_result, must_be_removed=True): remover = self.MallocRemover() t = TranslationContext() t.buildannotator().build_types(fn, signature) t.buildrtyper(type_system=self.type_system).specialize() graph = graphof(t, fn) if option.view: t.view() # to detect missing keepalives and broken intermediate graphs, # we do the loop ourselves instead of calling remove_simple_mallocs() while True: progress = remover.remove_mallocs_once(graph) simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks())) if progress and option.view: t.view() if expected_result is not Ellipsis: interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, args) assert res == expected_result if not progress: break if must_be_removed: self.check_malloc_removed(graph) return graph
def test_normalize_abstract_method(self): class Base: def fn(self): raise NotImplementedError class Sub1(Base): def fn(self): return 1 class Sub2(Base): def fn(self): return -2 def dummyfn(n): if n == 1: x = Sub1() else: x = Sub2() return x.fn() translator = self.rtype(dummyfn, [int], int) base_graph = graphof(translator, Base.fn.im_func) sub1_graph = graphof(translator, Sub1.fn.im_func) sub2_graph = graphof(translator, Sub2.fn.im_func) assert base_graph.getreturnvar().concretetype == lltype.Signed assert sub1_graph.getreturnvar().concretetype == lltype.Signed assert sub2_graph.getreturnvar().concretetype == lltype.Signed llinterp = LLInterpreter(translator.rtyper) res = llinterp.eval_graph(graphof(translator, dummyfn), [1]) assert res == 1 res = llinterp.eval_graph(graphof(translator, dummyfn), [2]) assert res == -2
def test_premature_death(self): import os from pypy.annotation.listdef import s_list_of_strings inputtypes = [s_list_of_strings] def debug(msg): os.write(2, "debug: " + msg + '\n') def entry_point(argv): #debug("entry point starting") for arg in argv: #debug(" argv -> " + arg) r = arg.replace('_', '-') #debug(' replaced -> ' + r) a = r.lower() #debug(" lowered -> " + a) return 0 t = self.translateopt(entry_point, inputtypes, mallocs=True) entry_point_graph = graphof(t, entry_point) argv = t.rtyper.getrepr(inputtypes[0]).convert_const(['./pypy-c']) interp = LLInterpreter(t.rtyper) interp.eval_graph(entry_point_graph, [argv])
def rtype(self, fn, argtypes, resulttype, checkfunction=None): t = TranslationContext() a = t.buildannotator() a.build_types(prefn, [int]) typer = t.buildrtyper() typer.specialize() #t.view() s_result = a.typeannotation(resulttype) from pypy.rpython import annlowlevel # annotate, normalize and rtype fn after the fact annhelper = annlowlevel.MixLevelHelperAnnotator(typer) graph = annhelper.getgraph(fn, [a.typeannotation(argtype) for argtype in argtypes], s_result) annhelper.finish() t.checkgraphs() if checkfunction is not None: checkfunction(t) # sanity check prefn llinterp = LLInterpreter(typer) res = llinterp.eval_graph(graphof(t, prefn), [1]) assert res == 100 res = llinterp.eval_graph(graphof(t, prefn), [2]) assert res == 201 return t
def check(self, fn, signature, args, expected_result, expected_mallocs=0, expected_calls=0): t = TranslationContext() self.translator = t t.buildannotator().build_types(fn, signature) t.buildrtyper(type_system=self.type_system).specialize() graph = graphof(t, fn) if option.view: t.view() self.original_graph_count = len(t.graphs) # to detect missing keepalives and broken intermediate graphs, # we do the loop ourselves instead of calling remove_simple_mallocs() maxiter = 100 mallocv = MallocVirtualizer(t.graphs, t.rtyper, verbose=True) while True: progress = mallocv.remove_mallocs_once() #simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks())) if progress and option.view: t.view() t.checkgraphs() if expected_result is not DONT_CHECK_RESULT: interp = LLInterpreter(t.rtyper) if not isinstance(expected_result, CHECK_RAISES): res = interp.eval_graph(graph, args) assert res == expected_result else: excinfo = py.test.raises(LLException, interp.eval_graph, graph, args) assert expected_result.excname in str(excinfo.value) if not progress: break maxiter -= 1 assert maxiter > 0, "infinite loop?" self.check_malloc_removed(graph, expected_mallocs, expected_calls) return graph
def test_half_exceptiontransformed_graphs(): from pypy.translator import exceptiontransform def f1(x): if x < 0: raise ValueError return 754 def g1(x): try: return f1(x) except ValueError: return 5 def f2(x): if x < 0: raise ValueError return 21 def g2(x): try: return f2(x) except ValueError: return 6 f3 = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed), 'f3', _callable=f1) def g3(x): try: return f3(x) except ValueError: return 7 def f(flag, x): if flag == 1: return g1(x) elif flag == 2: return g2(x) else: return g3(x) t = TranslationContext() t.buildannotator().build_types(f, [int, int]) t.buildrtyper().specialize() etrafo = exceptiontransform.ExceptionTransformer(t) etrafo.create_exception_handling(graphof(t, f1)) etrafo.create_exception_handling(graphof(t, g2)) etrafo.create_exception_handling(graphof(t, g3)) graph = graphof(t, f) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, [1, -64]) assert res == 5 res = interp.eval_graph(graph, [2, -897]) assert res == 6 res = interp.eval_graph(graph, [3, -9831]) assert res == 7
def test_half_exceptiontransformed_graphs(): from pypy.translator import exceptiontransform def f1(x): if x < 0: raise ValueError return 754 def g1(x): try: return f1(x) except ValueError: return 5 def f2(x): if x < 0: raise ValueError return 21 def g2(x): try: return f2(x) except ValueError: return 6 f3 = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed), "f3", _callable=f1) def g3(x): try: return f3(x) except ValueError: return 7 def f(flag, x): if flag == 1: return g1(x) elif flag == 2: return g2(x) else: return g3(x) t = TranslationContext() t.buildannotator().build_types(f, [int, int]) t.buildrtyper().specialize() etrafo = exceptiontransform.ExceptionTransformer(t) etrafo.create_exception_handling(graphof(t, f1)) etrafo.create_exception_handling(graphof(t, g2)) etrafo.create_exception_handling(graphof(t, g3)) graph = graphof(t, f) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, [1, -64]) assert res == 5 res = interp.eval_graph(graph, [2, -897]) assert res == 6 res = interp.eval_graph(graph, [3, -9831]) assert res == 7
def test_big(self): assert big() == 83 t = self.translateopt(big, [], inline_threshold=HUGE_THRESHOLD, mallocs=True) big_graph = graphof(t, big) self.check_malloc_removed(big_graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(big_graph, []) assert res == 83
def get_residual_graph(self): exc_data_ptr = self.hrtyper.exceptiondesc.exc_data_ptr llinterp = LLInterpreter(self.rtyper, exc_data_ptr=exc_data_ptr) if self.main_is_portal: residual_graph = llinterp.eval_graph(self.readportalgraph, self.main_args)._obj.graph else: residual_graphs = llinterp.eval_graph(self.readallportalsgraph, []) assert residual_graphs.ll_length() == 1 residual_graph = residual_graphs.ll_getitem_fast(0)._obj.graph return residual_graph
def task_llinterpret_lltype(self): from pypy.rpython.llinterp import LLInterpreter py.log.setconsumer("llinterp operation", None) translator = self.translator interp = LLInterpreter(translator.rtyper) bk = translator.annotator.bookkeeper graph = bk.getdesc(self.entry_point).getuniquegraph() v = interp.eval_graph(graph, self.extra.get("get_llinterp_args", lambda: [])()) log.llinterpret.event("result -> %s" % v)
def check_inlining(t, graph, args, result): callgraph, caller_candidates = find_malloc_removal_candidates(t, t.graphs) nice_callgraph = {} for caller, callee in callgraph: nice_callgraph.setdefault(caller, {})[callee] = True inline_and_remove(t, t.graphs) if option.view: t.view() interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, args) assert res == result return nice_callgraph, caller_candidates
def test_split_blocks_simple(): for i in range(4): def f(x, y): z = x + y w = x * y return z + w graph, t = translate(f, [int, int]) split_block(t.annotator, graph.startblock, i) checkgraph(graph) interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graph, [1, 2]) assert result == 5
def timeshift_from_portal(self, main, portal, main_args, inline=None, policy=None, backendoptimize=False): main_args = self._timeshift_from_portal(main, portal, main_args, inline=inline, policy=policy, backendoptimize=backendoptimize) self.main_args = main_args self.main_is_portal = main is portal exc_data_ptr = self.hrtyper.exceptiondesc.exc_data_ptr llinterp = LLInterpreter(self.rtyper, exc_data_ptr=exc_data_ptr) res = llinterp.eval_graph(self.maingraph, main_args) return res
def runner(self, f, nbargs=0, statistics=False, transformer=False, **extraconfigopts): if nbargs == 2: def entrypoint(args): x = args[0] y = args[1] r = f(x, y) return r elif nbargs == 0: def entrypoint(args): return f() else: raise NotImplementedError("pure laziness") from pypy.rpython.llinterp import LLInterpreter from pypy.translator.c.genc import CStandaloneBuilder ARGS = lltype.FixedSizeArray(lltype.Signed, nbargs) s_args = annmodel.SomePtr(lltype.Ptr(ARGS)) t = rtype(entrypoint, [s_args], gcname=self.gcname, stacklessgc=self.stacklessgc, **extraconfigopts) cbuild = CStandaloneBuilder(t, entrypoint, config=t.config, gcpolicy=self.gcpolicy) db = cbuild.generate_graphs_for_llinterp() entrypointptr = cbuild.getentrypointptr() entrygraph = entrypointptr._obj.graph if conftest.option.view: t.viewcg() llinterp = LLInterpreter(t.rtyper) # FIIIIISH setupgraph = db.gctransformer.frameworkgc_setup_ptr.value._obj.graph llinterp.eval_graph(setupgraph, []) def run(args): ll_args = lltype.malloc(ARGS, immortal=True) for i in range(nbargs): ll_args[i] = args[i] res = llinterp.eval_graph(entrygraph, [ll_args]) return res if statistics: statisticsgraph = db.gctransformer.statistics_ptr.value._obj.graph ll_gc = db.gctransformer.c_const_gc.value def statistics(index): return llinterp.eval_graph(statisticsgraph, [ll_gc, index]) return run, statistics elif transformer: return run, db.gctransformer else: return run
def task_llinterpret_lltype(self): from pypy.rpython.llinterp import LLInterpreter py.log.setconsumer("llinterp operation", None) translator = self.translator interp = LLInterpreter(translator.rtyper) bk = translator.annotator.bookkeeper graph = bk.getdesc(self.entry_point).getuniquegraph() v = interp.eval_graph(graph, self.extra.get('get_llinterp_args', lambda: [])()) log.llinterpret.event("result -> %s" % v)
def test_list_comp(self): def f(n1, n2): c = [i for i in range(n2)] return 33 t = self.translateopt(f, [int, int], inline_threshold=LARGE_THRESHOLD, mallocs=True) f_graph = graphof(t, f) self.check_malloc_removed(f_graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(f_graph, [11, 22]) assert res == 33
def test_split_blocks_conditional(): for i in range(3): def f(x, y): if x + 12: return y + 1 else: return y + 2 graph, t = translate(f, [int, int]) split_block(t.annotator, graph.startblock, i) checkgraph(graph) interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graph, [-12, 2]) assert result == 4 result = interp.eval_graph(graph, [0, 2]) assert result == 3
def test_recursive_gcd(): def gcd(a, b): if a == 1 or a == 0: return b if a > b: return gcd(b, a) return gcd(b % a, a) t = TranslationContext() t.buildannotator().build_types(gcd, [int, int]) t.buildrtyper().specialize() gcd_graph = graphof(t, gcd) remove_tail_calls_to_self(t, gcd_graph ) lli = LLInterpreter(t.rtyper) res = lli.eval_graph(gcd_graph, (15, 25)) assert res == 5
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_bug_inlined_if(self): def f(x, flag): if flag: y = x else: y = x+1 return y*5 def myfunc(x): return f(x, False) - f(x, True) assert myfunc(10) == 5 t = self.translateopt(myfunc, [int], inline_threshold=HUGE_THRESHOLD) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graphof(t, myfunc), [10]) assert res == 5
def check_malloc_removal(function, types, args, expected_result, must_remove=True): t = TranslationContext() t.buildannotator().build_types(function, types) t.buildrtyper().specialize() interp = LLInterpreter(t.rtyper) graph = graphof(t, function) res = interp.eval_graph(graph, args) assert res == expected_result malloc_to_stack(t) if must_remove: for block in graph.iterblocks(): for op in block.operations: assert op.opname != "malloc" res = interp.eval_graph(graph, args) assert res == expected_result return t
def check_inline(self, func, in_func, sig, entry=None, inline_guarded_calls=False, graph=False): if entry is None: entry = in_func t = self.translate(entry, sig) # inline! sanity_check(t) # also check before inlining (so we don't blame it) if option.view: t.view() raise_analyzer = canraise.RaiseAnalyzer(t) inliner = Inliner(t, graphof(t, in_func), func, t.rtyper.lltype_to_classdef_mapping(), inline_guarded_calls, raise_analyzer=raise_analyzer) inliner.inline_all() if option.view: t.view() sanity_check(t) interp = LLInterpreter(t.rtyper) def eval_func(args): return interp.eval_graph(graphof(t, entry), args) if graph: return eval_func, graphof(t, func) return eval_func
def test_secondary_backendopt(self): # checks an issue with a newly added graph that calls an # already-exception-transformed graph. This can occur e.g. # from a late-seen destructor added by the GC transformer # which ends up calling existing code. def common(n): if n > 5: raise ValueError def main(n): common(n) def later(n): try: common(n) return 0 except ValueError: return 1 t = TranslationContext() t.buildannotator().build_types(main, [int]) t.buildrtyper(type_system="lltype").specialize() exctransformer = t.getexceptiontransformer() exctransformer.create_exception_handling(graphof(t, common)) from pypy.annotation import model as annmodel from pypy.rpython.annlowlevel import MixLevelHelperAnnotator annhelper = MixLevelHelperAnnotator(t.rtyper) later_graph = annhelper.getgraph(later, [annmodel.SomeInteger()], annmodel.SomeInteger()) annhelper.finish() annhelper.backend_optimize() # ^^^ as the inliner can't handle exception-transformed graphs, # this should *not* inline common() into later(). if conftest.option.view: later_graph.show() common_graph = graphof(t, common) found = False for block in later_graph.iterblocks(): for op in block.operations: if op.opname == "direct_call" and op.args[0].value._obj.graph is common_graph: found = True assert found, "cannot find the call (buggily inlined?)" from pypy.rpython.llinterp import LLInterpreter llinterp = LLInterpreter(t.rtyper) res = llinterp.eval_graph(later_graph, [10]) assert res == 1
def test_secondary_backendopt(self): # checks an issue with a newly added graph that calls an # already-exception-transformed graph. This can occur e.g. # from a late-seen destructor added by the GC transformer # which ends up calling existing code. def common(n): if n > 5: raise ValueError def main(n): common(n) def later(n): try: common(n) return 0 except ValueError: return 1 t = TranslationContext() t.buildannotator().build_types(main, [int]) t.buildrtyper(type_system='lltype').specialize() exctransformer = t.getexceptiontransformer() exctransformer.create_exception_handling(graphof(t, common)) from pypy.annotation import model as annmodel from pypy.rpython.annlowlevel import MixLevelHelperAnnotator annhelper = MixLevelHelperAnnotator(t.rtyper) later_graph = annhelper.getgraph(later, [annmodel.SomeInteger()], annmodel.SomeInteger()) annhelper.finish() annhelper.backend_optimize() # ^^^ as the inliner can't handle exception-transformed graphs, # this should *not* inline common() into later(). if conftest.option.view: later_graph.show() common_graph = graphof(t, common) found = False for block in later_graph.iterblocks(): for op in block.operations: if (op.opname == 'direct_call' and op.args[0].value._obj.graph is common_graph): found = True assert found, "cannot find the call (buggily inlined?)" from pypy.rpython.llinterp import LLInterpreter llinterp = LLInterpreter(t.rtyper) res = llinterp.eval_graph(later_graph, [10]) assert res == 1
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 check_malloc_removal(function, types, args, expected_result, must_remove=True): t = TranslationContext() t.buildannotator().build_types(function, types) t.buildrtyper().specialize() interp = LLInterpreter(t.rtyper) graph = graphof(t, function) res = interp.eval_graph(graph, args) assert res == expected_result malloc_to_stack(t) if must_remove: for block in graph.iterblocks(): for op in block.operations: if op.opname == "malloc": assert op.args[1].value['flavor'] == 'stack' res = interp.eval_graph(graph, args) assert res == expected_result return t
def test_range_iter(self): def fn(start, stop, step): res = 0 if step == 0: if stop >= start: r = range(start, stop, 1) else: r = range(start, stop, -1) else: r = range(start, stop, step) for i in r: res = res * 51 + i return res t = self.translateopt(fn, [int, int, int], merge_if_blocks=True) interp = LLInterpreter(t.rtyper) for args in [2, 7, 0], [7, 2, 0], [10, 50, 7], [50, -10, -3]: assert interp.eval_graph(graphof(t, fn), args) == intmask(fn(*args))
def test_for_loop(self): def f(n): total = 0 for i in range(n): total += i return total t = self.translateopt(f, [int], mallocs=True) # this also checks that the BASE_INLINE_THRESHOLD is enough # for 'for' loops f_graph = graph = graphof(t, f) self.check_malloc_removed(f_graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(f_graph, [11]) assert res == 55
def test_remove_unaryops(): # We really want to use remove_unaryops for things like ooupcast and # oodowncast in dynamically typed languages, but it's easier to test # it with operations on ints here. def f(x): i = llop.int_invert(lltype.Signed, x) i = llop.int_add(lltype.Signed, x, 1) return llop.int_neg(lltype.Signed, i) t = TranslationContext() t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() f_graph = graphof(t, f) remove_unaryops(f_graph, ["int_neg", "int_invert"]) t.checkgraphs() interp = LLInterpreter(t.rtyper) result = interp.eval_graph(f_graph, [-2]) assert result == -1