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 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_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_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 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 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_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 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_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_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_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_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 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 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 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 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 specialize(self, func, argtypes): from pypy.rpython.llinterp import LLInterpreter t = TranslationContext(list_comprehension_operations=True) t.buildannotator().build_types(func, argtypes) if conftest.option.view: t.view() t.buildrtyper(self.typesystem).specialize() backend_optimizations(t) if conftest.option.view: t.view() graph = graphof(t, func) interp = LLInterpreter(t.rtyper) return interp, graph
def test_transform_dead_op_vars_bug(): from pypy.rpython.llinterp import LLInterpreter, LLException exc = ValueError() def f1(): raise exc # this function used to be considered side-effects-free def f2(): f1() # <- so this call was removed graph, t = translate(f2, [], backend_optimize=False) transform_dead_op_vars(graph, t) interp = LLInterpreter(t.rtyper) e = py.test.raises(LLException, 'interp.eval_graph(graph, [])') assert 'ValueError' in str(e.value)
def maybe_on_top_of_llinterp(rtyper, fnptr): # Run a generated graph on top of the llinterp for testing. # When translated, this just returns the fnptr. funcobj = get_funcobj(fnptr) if hasattr(funcobj, 'graph'): llinterp = LLInterpreter(rtyper) #, exc_data_ptr=exc_data_ptr) def on_top_of_llinterp(*args): return llinterp.eval_graph(funcobj.graph, list(args)) else: assert hasattr(funcobj, '_callable') def on_top_of_llinterp(*args): return funcobj._callable(*args) return on_top_of_llinterp
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_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 check_trees(func, argtypes): t = translate(func, argtypes) if option.view: t.view() graph = graphof(t, func) build_trees(graph) if option.view: t.view() interp = LLInterpreter(t.rtyper) def eval_func(*args): return interp.eval_graph(graph, args) return graph, eval_func
def jittest(driver): graph = driver.translator.graphs[0] interp = LLInterpreter(driver.translator.rtyper, malloc_check=False) def returns_null(T, *args, **kwds): return lltype.nullptr(T) interp.heap.malloc_nonmovable = returns_null # XXX get_policy = driver.extra['jitpolicy'] jitpolicy = get_policy(driver) from pypy.jit.backend.llgraph.runner import LLtypeCPU apply_jit(jitpolicy, interp, graph, LLtypeCPU)
def get_interpreter(func, values, view='auto', viewbefore='auto', policy=None, someobjects=False, type_system="lltype", backendopt=False, config=None, malloc_check=True, **extraconfigopts): extra_key = [(key, value) for key, value in extraconfigopts.iteritems()] extra_key.sort() extra_key = tuple(extra_key) key = ((func, ) + tuple([typeOf(x) for x in values]) + (someobjects, backendopt, extra_key)) try: (t, interp, graph) = _tcache[key] except KeyError: def annotation(x): T = typeOf(x) if T == Ptr(PyObject) and someobjects: return object else: return lltype_to_annotation(T) if policy is None and not someobjects: from pypy.annotation.policy import AnnotatorPolicy policy = AnnotatorPolicy() policy.allow_someobjects = False t, typer, graph = gengraph(func, [annotation(x) for x in values], viewbefore, policy, type_system=type_system, backendopt=backendopt, config=config, **extraconfigopts) interp = LLInterpreter(typer, malloc_check=malloc_check) _tcache[key] = (t, interp, graph) # keep the cache small _lastinterpreted.append(key) if len(_lastinterpreted) >= 4: del _tcache[_lastinterpreted.pop(0)] if view == 'auto': view = getattr(conftest.option, 'view', False) if view: t.view() return interp, graph
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