def test_funny_links(): from rpython.flowspace.model import Block, FunctionGraph, \ Variable, Constant, Link from rpython.flowspace.operation import op for i in range(2): v_i = Variable("i") block = Block([v_i]) g = FunctionGraph("is_one", block) op1 = op.eq(v_i, Constant(1)) block.operations.append(op1) block.exitswitch = op1.result 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 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().specialize() graph = graphof(t, fn) if inline is not None: from rpython.translator.backendopt.inline import auto_inline_graphs auto_inline_graphs(t, t.graphs, inline) if option.view: t.view() # to detect 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()), [graph]) 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 check_graph(graph, args, expected_result, t): if option.view: t.view() checkgraph(graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, args) assert res == expected_result
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 rpython.rtyper.llinterp import LLInterpreter from rpython.translator.c.genc import CStandaloneBuilder t = rtype(entrypoint, [s_list_of_strings]) t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=FrameworkGcPolicy2) cbuild.make_entrypoint_wrapper = False db = cbuild.build_database() 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_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 rpython.annotator.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_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_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(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 runner(self, name, transformer=False): db = self.db name_to_func = self.name_to_func entrygraph = self.entrygraph from rpython.rtyper.llinterp import LLInterpreter llinterp = LLInterpreter(self.rtyper) gct = db.gctransformer if self.__class__.__dict__.get('_used', False): teardowngraph = gct.frameworkgc__teardown_ptr.value._obj.graph llinterp.eval_graph(teardowngraph, []) self.__class__._used = True # FIIIIISH setupgraph = gct.frameworkgc_setup_ptr.value._obj.graph # setup => resets the gc llinterp.eval_graph(setupgraph, []) def run(args): ll_args = lltype.malloc(ARGS, immortal=True) ll_args[0] = name_to_func[name] for i in range(len(args)): ll_args[1+i] = args[i] res = llinterp.eval_graph(entrygraph, [ll_args]) return res if transformer: return run, gct else: return run
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 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 rpython.rtyper 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 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_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 rpython.rtyper.llinterp import LLInterpreter from rpython.translator.c.genc import CStandaloneBuilder t = rtype(entrypoint, [s_list_of_strings]) t.config.translation.gc = "minimark" 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_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 test_remove_same_as_nonconst(): from rpython.rlib.nonconst import NonConstant from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.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_nonconst(): from rpython.rlib.nonconst import NonConstant from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.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 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 rpython.rtyper 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().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() 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 interpret_from_graph(self, rtyper, graph): """ :param rtyper: see translation.driver.translator.rtyper :param graph: see translation.driver.translator.graphs[0] :return: the interpreted result """ interpreter = LLInterpreter(rtyper) return interpreter.eval_graph(graph) # interpret all translated operations
def test_half_exceptiontransformed_graphs(): from rpython.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 rpython.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 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 task_llinterpret_lltype(self): from rpython.rtyper.llinterp import LLInterpreter 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("result -> %s" % v)
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(graph.startblock, i) checkgraph(graph) interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graph, [1, 2]) assert result == 5
def task_llinterpret_lltype(self): from rpython.rtyper.llinterp import LLInterpreter 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("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_inline_all(self): def g(x): return x + 1 def f(x): return g(x) * g(x+1) * g(x+2) * g(x+3) * g(x+4) * g(x+5) t = self.translate(f, [int]) sanity_check(t) # also check before inlining (so we don't blame it) simple_inline_function(t, graphof(t, g), graphof(t, f)) sanity_check(t) assert summary(graphof(t, f)) == {'int_add': 11, 'int_mul': 5} interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graphof(t, f), [10]) assert result == f(10)
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 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 test_inline_all(self): def g(x): return x + 1 def f(x): return g(x) * g(x + 1) * g(x + 2) * g(x + 3) * g(x + 4) * g(x + 5) t = self.translate(f, [int]) sanity_check(t) # also check before inlining (so we don't blame it) simple_inline_function(t, graphof(t, g), graphof(t, f)) sanity_check(t) assert summary(graphof(t, f)) == {"int_add": 11, "int_mul": 5} interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graphof(t, f), [10]) assert result == f(10)
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(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_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 _setup_exception_handling_untranslated(self): # for running un-translated only, all exceptions occurring in the # llinterpreter are stored in '_exception_emulator', which is then # read back by the machine code reading at the address given by # pos_exception() and pos_exc_value(). _exception_emulator = lltype.malloc(rffi.CArray(lltype.Signed), 2, zero=True, flavor='raw', immortal=True) self._exception_emulator = _exception_emulator def _store_exception(lle): self._last_exception = lle # keepalive tp_i = rffi.cast(lltype.Signed, lle.args[0]) v_i = rffi.cast(lltype.Signed, lle.args[1]) _exception_emulator[0] = tp_i _exception_emulator[1] = v_i self.debug_ll_interpreter = LLInterpreter(self.rtyper) self.debug_ll_interpreter._store_exception = _store_exception def pos_exception(): return rffi.cast(lltype.Signed, _exception_emulator) def pos_exc_value(): return (rffi.cast(lltype.Signed, _exception_emulator) + rffi.sizeof(lltype.Signed)) self.pos_exception = pos_exception self.pos_exc_value = pos_exc_value self.insert_stack_check = lambda: (0, 0, 0)
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().specialize() exctransformer = t.getexceptiontransformer() exctransformer.create_exception_handling(graphof(t, common)) from rpython.annotator import model as annmodel from rpython.rtyper.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 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 rpython.rtyper.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().specialize() exctransformer = t.getexceptiontransformer() exctransformer.create_exception_handling(graphof(t, common)) from rpython.annotator import model as annmodel from rpython.rtyper.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 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 rpython.rtyper.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 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 test_call_final_function(): tmpfile = str(udir.join('test_call_final_function')) def f(x): return x * 6 def goodbye_world(): if we_are_translated(): fd = os.open(tmpfile, os.O_WRONLY | os.O_CREAT, 0644) os.close(fd) graph, t = translate(f, [int]) call_final_function(t, goodbye_world) # if os.path.exists(tmpfile): os.unlink(tmpfile) interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graph, [7]) assert result == 42 assert os.path.isfile(tmpfile)
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_remove_unaryops(): # We really want to use remove_unaryops for more complex operations, 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
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_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(x): result = 0 for i in range(0, x): result += i return result t = self.translate(f, [int]) sanity_check(t) # also check before inlining (so we don't blame it) for graph in t.graphs: if graph.name.startswith('ll_rangenext'): break else: assert 0, "cannot find ll_rangenext_*() function" simple_inline_function(t, graph, graphof(t, f)) sanity_check(t) interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graphof(t, f), [10]) assert result == 45