def xxx_test_later_along_link(): S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True}) s1 = lltype.malloc(S1) s1.x = 123 s2 = lltype.malloc(S1) s2.x = 60 def fn(x, y): if x: x = s1.x else: x = s2.x y *= 2 return (x+1) - y graph, t = get_graph(fn, [int, int]) assert summary(graph) == {'int_is_true': 1, 'getfield': 2, 'int_mul': 1, 'int_add': 1, 'int_sub': 1} constant_fold_graph(graph) assert summary(graph) == {'int_is_true': 1, 'int_mul': 1, 'int_sub': 1} check_graph(graph, [-1], 124, t) check_graph(graph, [0], 61, t)
def test_keepalive_const_arrayitems(): A1 = lltype.GcArray(lltype.Signed) a1 = lltype.malloc(A1, 10) a1[6] = 1234 def fn(): p1 = lltype.direct_arrayitems(a1) p2 = lltype.direct_ptradd(p1, 6) return p2[0] graph, t = get_graph(fn, []) assert summary(graph) == { 'direct_arrayitems': 1, 'direct_ptradd': 1, 'getarrayitem': 1 } constant_fold_graph(graph) # kill all references to 'a1' a1 = fn = None del graph.func import gc gc.collect() assert summary(graph) == {'getarrayitem': 1} check_graph(graph, [], 1234, t)
def test_isinstance(): class A: pass class B(A): pass def g(n): if n > 10: return A() else: b = B() b.value = 321 return b def fn(n): x = g(n) assert isinstance(x, B) return x.value t, graph = check(fn, [5], 321) assert summary(graph)['debug_assert'] == 1 from rpython.translator.backendopt.removenoops import remove_debug_assert remove_debug_assert(graph) assert "debug_assert" not in summary(graph) from rpython.translator.simplify import transform_dead_op_vars transform_dead_op_vars(graph, t) assert summary(graph)["direct_call"] == 1
def test_access_directly_specialized(self): def g(b): return b.v0 def f(n): b = B(n) x = g(b) y = g(hint(b, access_directly=True)) return x + y t, typer, graph = self.gengraph(f, [int]) desc = typer.annotator.bookkeeper.getdesc(g) g_graphs = desc._cache.items() assert len(g_graphs) == 2 g_graphs.sort() assert g_graphs[0][0] is None assert get_force_virtualizable_flags(g_graphs[0][1]) == [{}] expected = [{'access_directly': True}] assert get_force_virtualizable_flags(g_graphs[1][1]) == expected self.replace_force_virtualizable(typer, [g_graphs[0][1], g_graphs[1][1]]) assert summary(g_graphs[0][1]) == {'direct_call': 1, self.GETFIELD: 1} assert summary(g_graphs[1][1]) == {self.GETFIELD: 1} res = self.interpret(f, [23]) assert res == 46
def test_access_directly_escape(self): class Global: pass glob = Global() def g(b): glob.b = b def h(b): return b.v0 def f(n): b = B(n) g(b) g(hint(b, access_directly=True)) return h(glob.b) t, typer, graph = self.gengraph(f, [int]) desc = typer.annotator.bookkeeper.getdesc(g) g_graphs = desc._cache.items() assert len(g_graphs) == 2 g_graphs.sort() assert g_graphs[0][0] is None assert summary(g_graphs[0][1]) == {self.SETFIELD: 1} assert summary(g_graphs[1][1]) == {self.SETFIELD: 1} h_graph = t._graphof(h) assert summary(h_graph) == {'jit_force_virtualizable': 1, self.GETFIELD: 1} assert get_force_virtualizable_flags(h_graph) == [{}] res = self.interpret(f, [23]) assert res == 23
def test_dont_constfold_debug_print(): def fn(): llop.debug_print(lltype.Void, "hello world") graph, t = get_graph(fn, []) assert summary(graph) == {'debug_print': 1} constant_fold_graph(graph) assert summary(graph) == {'debug_print': 1}
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 rpython.translator.backendopt import removenoops, inline inline.auto_inline_graphs(t, t.graphs, threshold=999) removenoops.remove_same_as(graph) constant_fold_graph(graph) if 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_multiple_incoming_links(): S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True}) s1 = lltype.malloc(S1) s1.x = 123 s2 = lltype.malloc(S1) s2.x = 60 s3 = lltype.malloc(S1) s3.x = 15 def fn(x): y = x * 10 if x == 1: x = s1.x elif x == 2: x = s2.x elif x == 3: x = s3.x y = s1.x return (x+1) + y graph, t = get_graph(fn, [int]) constant_fold_graph(graph) assert summary(graph) == {'int_mul': 1, 'int_eq': 3, 'int_add': 2} for link in graph.iterlinks(): if Constant(139) in link.args: break else: raise AssertionError("139 not found in the graph as a constant") for i in range(4): check_graph(graph, [i], fn(i), t)
def test_remove_duplicate_write_barrier(): from rpython.translator.c.genc import CStandaloneBuilder from rpython.flowspace.model import summary class A(object): pass glob_a_1 = A() glob_a_2 = A() def f(a, cond): a.x = a a.z = a if cond: a.y = a def g(): f(glob_a_1, 5) f(glob_a_2, 0) t = rtype(g, []) t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, g, t.config, gcpolicy=FrameworkGcPolicy2) db = cbuild.generate_graphs_for_llinterp() ff = graphof(t, f) #ff.show() assert summary(ff)['direct_call'] == 1 # only one remember_young_pointer
def test_simple_melting_away(): def fn(n): assert n >= 1 return n - 1 graph, t = get_graph(fn, [int]) assert summary(graph) == {'int_ge': 1, 'int_sub': 1} remove_asserts(t, [graph]) assert summary(graph) == {'int_ge': 1, 'debug_assert': 1, 'int_sub': 1} check_graph(graph, [1], 0, t) from rpython.translator.backendopt.removenoops import remove_debug_assert remove_debug_assert(graph) assert summary(graph) == {'int_ge': 1, 'int_sub': 1} from rpython.translator.simplify import transform_dead_op_vars transform_dead_op_vars(graph) assert summary(graph) == {'int_sub': 1}
def test_isinstance(self): class A: pass class B(A): pass def g(n): if n > 10: return A() else: b = B() b.value = 321 return b def fn(n): x = g(n) assert isinstance(x, B) return x.value t = self.translateopt(fn, [int], really_remove_asserts=True, remove_asserts=True) graph = graphof(t, fn) assert "direct_call" not in summary(graph)
def test_access_directly(self): def g(b): b.v0 += 1 return b.v0 def f(n): b = B(n) b = hint(b, access_directly=True) return g(b) t, typer, graph = self.gengraph(f, [int]) g_graph = t._graphof(g) expected = [{'access_directly': True}] * 3 assert get_force_virtualizable_flags(g_graph) == expected self.replace_force_virtualizable(typer, [g_graph]) assert summary(g_graph) == { self.GETFIELD: 2, self.SETFIELD: 1, 'int_add': 1 } res = self.interpret(f, [23]) assert res == 24
def test_simple(S1=None): if S1 is None: S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True}) s1 = lltype.malloc(S1) s1.x = 123 def g(y): return y + 1 def fn(): return g(s1.x) graph, t = get_graph(fn, []) assert summary(graph) == {'getfield': 1, 'direct_call': 1} constant_fold_graph(graph) assert summary(graph) == {'direct_call': 1} check_graph(graph, [], 124, t)
def test_access_directly_method(self): class A: _virtualizable2_ = ['v0'] def __init__(self, v): self.v0 = v def meth1(self, x): return self.g(x+1) def g(self, y): return self.v0 * y def f(n): a = A(n) a = hint(a, access_directly=True) return a.meth1(100) t, typer, graph = self.gengraph(f, [int]) g_graph = t._graphof(A.g.im_func) self.replace_force_virtualizable(typer, [g_graph]) assert summary(g_graph) == {self.GETFIELD: 1, 'int_mul': 1} res = self.interpret(f, [23]) assert res == 2323
def test_dict_to_switch_translate(): from rpython.flowspace.model import summary d = dict_to_switch({1: 17, 2: 19}) r = interpret(d, [1]) assert r == 17 r = interpret(d, [2]) assert r == 19 with pytest.raises(LLException): interpret(d, [10]) d = dict_to_switch({'1': 17, '2': 19}) r = interpret(d, ['1']) assert r == 17 r = interpret(d, ['2']) assert r == 19 with pytest.raises(LLException): interpret(d, ['a']) d = dict_to_switch({'1': 17, '2': 19, '3': 1121, 'a': -12}) def f(i): c = chr(i) if not i: c = 'abc' try: return d(c) except KeyError: return -1 t, typer, g = gengraph(f, [int]) lookupg = t.graphs[1] assert summary(lookupg)['direct_call'] == 1 # should be char based
def test_remove_duplicate_write_barrier(): from rpython.translator.c.genc import CStandaloneBuilder from rpython.flowspace.model import summary class A(object): pass glob_a_1 = A() glob_a_2 = A() def f(a, cond): a.x = a a.z = a if cond: a.y = a def g(): f(glob_a_1, 5) f(glob_a_2, 0) t = rtype(g, []) t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, g, t.config, gcpolicy=FrameworkGcPolicy2) cbuild.make_entrypoint_wrapper = False db = cbuild.build_database() ff = graphof(t, f) #ff.show() assert summary(ff)['direct_call'] == 1 # only one remember_young_pointer
def test_move_pushes_earlier_rename_3(): def g(a): pass def f(a, b): llop.gc_push_roots(lltype.Void, b) g(a) llop.gc_pop_roots(lltype.Void, b) while a > 10: a -= 2 c = lltype.cast_opaque_ptr(PSTRUCT, b) while a > 10: a -= 2 llop.gc_push_roots(lltype.Void, c) g(a) llop.gc_pop_roots(lltype.Void, c) return c graph = make_graph(f, [int, llmemory.GCREF]) regalloc = allocate_registers(graph) expand_push_roots(graph, regalloc) move_pushes_earlier(graph, regalloc) expand_pop_roots(graph, regalloc) assert graphmodel.summary(graph) == { 'gc_save_root': 1, 'gc_restore_root': 2, 'cast_opaque_ptr': 1, 'int_gt': 2, 'int_sub': 2, 'direct_call': 2, } add_enter_leave_roots_frame(graph, regalloc, Constant('fake gcdata')) postprocess_double_check(graph)
def test_move_pushes_earlier_1(): def g(a): return a - 1 def f(a, b): a *= 2 while a > 10: llop.gc_push_roots(lltype.Void, b) a = g(a) llop.gc_pop_roots(lltype.Void, b) return b graph = make_graph(f, [int, llmemory.GCREF]) regalloc = allocate_registers(graph) expand_push_roots(graph, regalloc) move_pushes_earlier(graph, regalloc) expand_pop_roots(graph, regalloc) add_enter_leave_roots_frame(graph, regalloc, Constant('fake gcdata')) assert graphmodel.summary(graph) == { 'int_mul': 1, 'gc_enter_roots_frame': 1, 'gc_save_root': 1, 'gc_restore_root': 1, 'int_gt': 1, 'direct_call': 1, 'gc_leave_roots_frame': 1, } assert len(graph.startblock.operations) == 3 assert graph.startblock.operations[0].opname == 'int_mul' assert graph.startblock.operations[1].opname == 'gc_enter_roots_frame' assert graph.startblock.operations[2].opname == 'gc_save_root' assert graph.startblock.operations[2].args[0].value == 0 postprocess_double_check(graph)
def test_keepalive_const_fieldptr(): S1 = lltype.GcStruct('S1', ('x', lltype.Signed)) s1 = lltype.malloc(S1) s1.x = 1234 def fn(): p1 = lltype.direct_fieldptr(s1, 'x') return p1[0] graph, t = get_graph(fn, []) assert summary(graph) == {'direct_fieldptr': 1, 'getarrayitem': 1} constant_fold_graph(graph) # kill all references to 's1' s1 = fn = None del graph.func import gc; gc.collect() assert summary(graph) == {'getarrayitem': 1} check_graph(graph, [], 1234, t)
def test_fold_exitswitch(): S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True}) s1 = lltype.malloc(S1) s1.x = 123 s2 = lltype.malloc(S1) s2.x = 60 def fn(n): if s1.x: return n * 5 else: return n - 7 graph, t = get_graph(fn, [int]) assert summary(graph) == {'getfield': 1, 'int_is_true': 1, 'int_mul': 1, 'int_sub': 1} constant_fold_graph(graph) assert summary(graph) == {'int_mul': 1} check_graph(graph, [12], 60, t)
def test_keepalive_const_arrayitems(): A1 = lltype.GcArray(lltype.Signed) a1 = lltype.malloc(A1, 10) a1[6] = 1234 def fn(): p1 = lltype.direct_arrayitems(a1) p2 = lltype.direct_ptradd(p1, 6) return p2[0] graph, t = get_graph(fn, []) assert summary(graph) == {'direct_arrayitems': 1, 'direct_ptradd': 1, 'getarrayitem': 1} constant_fold_graph(graph) # kill all references to 'a1' a1 = fn = None del graph.func import gc; gc.collect() assert summary(graph) == {'getarrayitem': 1} check_graph(graph, [], 1234, t)
def test_nonmovable(self): for (nonmovable, opname) in [(True, 'malloc_nonmovable'), (False, 'malloc')]: class A(object): _alloc_nonmovable_ = nonmovable def f(): return A() t, typer, graph = self.gengraph(f, []) assert summary(graph) == {opname: 1, 'cast_pointer': 1, 'setfield': 1}
def test_fn1(self): def fn1(x, y): if x > 0: t = x+y, x-y else: t = x-y, x+y s, d = t return s*d graph = self.check(fn1, [int, int], [15, 10], 125) insns = summary(graph) assert insns['int_mul'] == 1
def test_fn1(self): def fn1(x, y): if x > 0: t = x + y, x - y else: t = x - y, x + y s, d = t return s * d graph = self.check(fn1, [int, int], [15, 10], 125) insns = summary(graph) assert insns['int_mul'] == 1
def test_fold_concat(self): const = self.const def g(tail): return const("head")+tail def f(): return g(const("tail")) from rpython.conftest import option t, typer, fgraph = self.gengraph(f, [], backendopt=True) if option.view: t.view() assert summary(fgraph) == {}
def test_always_inline(self): def f(x, y, z, k): p = (((x, y), z), k) return p[0][0][0] + p[-1] f._always_inline_ = True def g(x, y, z, k): a = f(x, y, z, k) return a eval_func, t = self.check_auto_inlining(g, [int, int, int, int], multiplier=0.1) graph = graphof(t, g) s = summary(graph) assert len(s) > 3
def test_immutable(self): class I(object): _immutable_ = True def __init__(self, v): self.v = v i = I(3) def f(): return i.v t, typer, graph = self.gengraph(f, [], backendopt=True) assert summary(graph) == {}
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_llexternal(self): from rpython.rtyper.lltypesystem.rffi import llexternal from rpython.rtyper.lltypesystem import lltype z = llexternal('z', [lltype.Signed], lltype.Signed) def f(x): y = -1 if x > 0: y = z(x) return y + x t,g = self.transform_func(f, [int], True) # llexternals normally should not raise, the graph should have no exception # checking assert summary(g) == {'int_gt': 1, 'int_add': 1, 'direct_call': 1}
def test_first_subfield_access_is_cast_pointer(): B = lltype.GcStruct("B", ('x', lltype.Signed)) C = lltype.GcStruct("C", ('super', B), ('y', lltype.Signed)) def f(): c = lltype.malloc(C) c.super.x = 1 c.y = 2 return c.super.x + c.y s, t = ll_rtype(f, []) from rpython.translator.translator import graphof from rpython.flowspace.model import summary graph = graphof(t, f) graphsum = summary(graph) assert 'getsubstruct' not in graphsum assert 'cast_pointer' in graphsum
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_char_index_0_checked(self): constchar = self.constchar errorres = constchar(ord('?')) def fn(c): try: return c[0] except IndexError: return errorres x = self.interpret(fn, [constchar(65)]) assert x == constchar(65) def f(): return ord(fn(constchar(65))) + ord(constchar(66)) t, typer, fgraph = self.gengraph(f, [], backendopt=True) # all constant folded assert not summary(fgraph)
def test_char_index_0(self): def fn(c): return c[0] x = self.interpret(fn, [self.constchar(65)]) assert x == chr(65) def f(): return ord(fn('a')) + ord(fn('b')) t, typer, fgraph = self.gengraph(f, [], backendopt=True) # all constant folded assert not summary(fgraph) def fn(c): return c[-1] # not optimized, works anyway x = self.interpret(fn, [self.constchar(65)]) assert x == chr(65)
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 rpython.translator.backendopt import removenoops removenoops.remove_same_as(graph) constant_fold_graph(graph) if option.view: t.view() assert summary(graph) == {'int_gt': 1} check_graph(graph, [2], 17, t) check_graph(graph, [42], 6, t)
def test_int_add_nonneg_ovf(self): def f(x): try: a = ovfcheck(x + 50) except OverflowError: return 0 try: a += ovfcheck(100 + x) except OverflowError: return 1 return a t, rtyper, graph = self.gengraph(f, [int]) assert summary(graph).get('int_add_nonneg_ovf') == 2 res = self.interpret(f, [-3]) assert res == 144 res = self.interpret(f, [sys.maxint-50]) assert res == 1 res = self.interpret(f, [sys.maxint]) assert res == 0
def test_implicit_cast(self): z = llexternal('z', [USHORT, ULONG, USHORT, DOUBLE], USHORT, sandboxsafe=True) # to allow the wrapper to be inlined def f(x, y, xx, yy): return z(x, y, xx, yy) a = RPythonAnnotator() r = a.build_types(f, [int, int, int, int]) rtyper = RPythonTyper(a) rtyper.specialize() a.translator.rtyper = rtyper backend_optimizations(a.translator) if option.view: a.translator.view() graph = graphof(a.translator, f) s = summary(graph) # there should be not too many operations here by now expected = {'force_cast': 3, 'cast_int_to_float': 1, 'direct_call': 1} for k, v in expected.items(): assert s[k] == v
def test_untagged_subclasses(): def g(x): return x.attrvalue # should not produce a call to ll_unboxed_getclass def fn(n): y = C(12) if n > 0: x = B(5) else: x = D(5) return g(x) interp, graph = get_interpreter(fn, [-1000], taggedpointers=True) t = interp.typer.annotator.translator ggraph = graphof(t, g) assert summary(ggraph) == {'cast_pointer': 2, 'getfield': 2} res = interp.eval_graph(graph, [-1000]) assert res == 68 res = interp.eval_graph(graph, [3]) assert res == 66
def test_access_directly(self): def g(b): b.v0 += 1 return b.v0 def f(n): b = B(n) b = hint(b, access_directly=True) return g(b) t, typer, graph = self.gengraph(f, [int]) g_graph = t._graphof(g) expected = [{'access_directly': True}] * 3 assert get_force_virtualizable_flags(g_graph) == expected self.replace_force_virtualizable(typer, [g_graph]) assert summary(g_graph) == {self.GETFIELD: 2, self.SETFIELD: 1, 'int_add': 1} res = self.interpret(f, [23]) assert res == 24
def test_inline_all_exc(self): def g(x): if x < -100: raise ValueError return x + 1 def f(x): n1 = g(x) * g(x + 1) try: n2 = g(x + 2) * g(x + 3) except ValueError: n2 = 1 n3 = g(x + 4) * g(x + 5) return n1 * n2 * n3 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, "cast_pointer": 12, "getfield": 6, "int_lt": 6} interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graphof(t, f), [10]) assert result == f(10)
def check(self, f1, expected): t = TranslationContext(list_comprehension_operations=True) graph = t.buildflowgraph(f1) if option.view: graph.show() assert summary(graph) == expected