def test_wrong_startblock_incref(): class B(object): pass def g(b): while True: b.x -= 10 if b.x < 0: return b.x def f(n): b = B() b.x = n return g(b) # XXX obscure: remove the first empty block in the graph of 'g' t = TranslationContext() graph = t.buildflowgraph(g) assert graph.startblock.operations == [] graph.startblock = graph.startblock.exits[0].target from pypy.objspace.flow.model import checkgraph checkgraph(graph) t._prebuilt_graphs[g] = graph fn = compile_func(f, [int], t) res = fn(112) assert res == -8
def test_data_flow_families(): def snippet_fn(xx, yy): while yy > 0: if 0 < xx: yy = yy - xx else: yy = yy + xx return yy t = TranslationContext() graph = t.buildflowgraph(snippet_fn) operations = [] for block in graph.iterblocks(): operations += block.operations variable_families = DataFlowFamilyBuilder(graph).get_variable_families() # we expect to find xx only once: v_xx = variable_families.find_rep(graph.getargs()[0]) found = 0 for op in operations: if op.opname in ('add', 'sub', 'lt'): assert variable_families.find_rep(op.args[1]) == v_xx found += 1 assert found == 3
def test_wrong_startblock_incref(): class B(object): pass def g(b): while True: b.x -= 10 if b.x < 0: return b.x def f(n): b = B() b.x = n return g(b) # XXX obscure: remove the first empty block in the graph of 'g' t = TranslationContext() graph = t.buildflowgraph(g) assert graph.startblock.operations == [] graph.startblock = graph.startblock.exits[0].target from pypy.objspace.flow.model import checkgraph checkgraph(graph) t._prebuilt_graphs[g] = graph fn = compile_func(f, [int], t) res = fn(112) assert res == -8
def test_detect_list_comprehension(): def f1(l): return [x*17 for x in l] t = TranslationContext(list_comprehension_operations=True) graph = t.buildflowgraph(f1) if conftest.option.view: graph.show() assert summary(graph) == { 'newlist': 1, 'iter': 1, 'next': 1, 'mul': 1, 'getattr': 1, 'simple_call': 1, 'hint': 2, }
def test_simple_loop(): def snippet_fn(x, y): while y > 0: y -= x return y t = TranslationContext() graph = t.buildflowgraph(snippet_fn) if option.view: t.view() loops = find_inner_loops(graph) assert len(loops) == 1 loop = loops[0] assert loop.headblock.operations[0].opname == 'gt' assert len(loop.links) == 2 assert loop.links[0] in loop.headblock.exits assert loop.links[1] in loop.links[0].target.exits assert loop.links[1].target is loop.headblock
def test_detect_list_comprehension(): def f1(l): return [x * 17 for x in l] t = TranslationContext(list_comprehension_operations=True) graph = t.buildflowgraph(f1) if conftest.option.view: graph.show() assert summary(graph) == { 'newlist': 1, 'iter': 1, 'next': 1, 'mul': 1, 'getattr': 1, 'simple_call': 1, 'hint': 2, }
def test_simple_compute_reachability(): def f(x): if x < 0: if x == -1: return x+1 else: return x+2 else: if x == 1: return x-1 else: return x-2 t = TranslationContext() g = t.buildflowgraph(f) reach = compute_reachability(g) assert len(reach[g.startblock]) == 7 assert len(reach[g.startblock.exits[0].target]) == 3 assert len(reach[g.startblock.exits[1].target]) == 3
def test_simple_loop(): def snippet_fn(x, y): while y > 0: y -= x return y t = TranslationContext() graph = t.buildflowgraph(snippet_fn) if option.view: t.view() loops = find_inner_loops(graph) assert len(loops) == 1 loop = loops[0] assert loop.headblock.operations[0].opname == 'gt' assert len(loop.links) == 2 assert loop.links[0] in loop.headblock.exits assert loop.links[1] in loop.links[0].target.exits assert loop.links[1].target is loop.headblock
def test_two_loops(): def snippet_fn(x, y): while y > 0: y -= x while y < 0: y += x return y t = TranslationContext() graph = t.buildflowgraph(snippet_fn) if option.view: t.view() loops = find_inner_loops(graph) assert len(loops) == 2 assert loops[0].headblock is not loops[1].headblock for loop in loops: assert loop.headblock.operations[0].opname in ('gt', 'lt') assert len(loop.links) == 2 assert loop.links[0] in loop.headblock.exits assert loop.links[1] in loop.links[0].target.exits assert loop.links[1].target is loop.headblock
def test_nested_loops(): def snippet_fn(x, z): y = 0 while y <= 10: while z < y: z += y y += 1 return z t = TranslationContext() graph = t.buildflowgraph(snippet_fn) if option.view: t.view() loops = find_inner_loops(graph) assert len(loops) == 1 loop = loops[0] assert loop.headblock.operations[0].opname == 'lt' assert len(loop.links) == 2 assert loop.links[0] in loop.headblock.exits assert loop.links[1] in loop.links[0].target.exits assert loop.links[1].target is loop.headblock
def test_SSI_to_SSA(): def snippet_fn(v1, v2, v3): if v1: # v4 = is_true(v1) while v3: # v5 = is_true(v3) pass passed_over = 0 else: v6 = snippet_fn(v3, v2, v1) # v6 = simple_call(v3, v2, v1) passed_over = v6 v7 = passed_over # v7 = inputarg return v7+v1 # v8 = add(v7, v1) t = TranslationContext() graph = t.buildflowgraph(snippet_fn) SSI_to_SSA(graph) allvars = [] for block in graph.iterblocks(): allvars += [v.name for v in block.getvariables()] # see comments above for where the 8 remaining variables are expected to be assert len(dict.fromkeys(allvars)) == 8
def test_SSI_to_SSA(): def snippet_fn(v1, v2, v3): if v1: # v4 = is_true(v1) while v3: # v5 = is_true(v3) pass passed_over = 0 else: v6 = snippet_fn(v3, v2, v1) # v6 = simple_call(v3, v2, v1) passed_over = v6 v7 = passed_over # v7 = inputarg return v7 + v1 # v8 = add(v7, v1) t = TranslationContext() graph = t.buildflowgraph(snippet_fn) SSI_to_SSA(graph) allvars = [] for block in graph.iterblocks(): allvars += [v.name for v in block.getvariables()] # see comments above for where the 8 remaining variables are expected to be assert len(dict.fromkeys(allvars)) == 8
def test_nested_loops(): def snippet_fn(x, z): y = 0 while y <= 10: while z < y: z += y y += 1 return z t = TranslationContext() graph = t.buildflowgraph(snippet_fn) if option.view: t.view() loops = find_inner_loops(graph) assert len(loops) == 1 loop = loops[0] assert loop.headblock.operations[0].opname == 'lt' assert len(loop.links) == 2 assert loop.links[0] in loop.headblock.exits assert loop.links[1] in loop.links[0].target.exits assert loop.links[1].target is loop.headblock
def test_measure_median_execution_cost(self): def f(x): x += 1 x += 1 x += 1 while True: x += 1 x += 1 x += 1 if x: break x += 1 x += 1 x += 1 x += 1 x += 1 x += 1 return x t = TranslationContext() graph = t.buildflowgraph(f) res = measure_median_execution_cost(graph) assert round(res, 5) == round(32.333333333, 5)
def test_two_loops(): def snippet_fn(x, y): while y > 0: y -= x while y < 0: y += x return y t = TranslationContext() graph = t.buildflowgraph(snippet_fn) if option.view: t.view() loops = find_inner_loops(graph) assert len(loops) == 2 assert loops[0].headblock is not loops[1].headblock for loop in loops: assert loop.headblock.operations[0].opname in ('gt', 'lt') assert len(loop.links) == 2 assert loop.links[0] in loop.headblock.exits assert loop.links[1] in loop.links[0].target.exits assert loop.links[1].target is loop.headblock
def test_compile_array_access(self): def access_array(index): my_array = numpy.array([3,99,2]) my_array[0] = 1 return my_array[index] fn = self.compile(access_array, [int]) assert fn(0) == 1 assert fn(1) == 99 t = TranslationContext() t.buildannotator().build_types(access_array, [int]) t.buildrtyper().specialize() graph = t.buildflowgraph(access_array) from pypy.translator.tool.make_dot import make_dot filename = make_dot('access_array', graph) from pypy.translator.c.genc import CExtModuleBuilder b = CExtModuleBuilder(t, access_array) filename = b.generate_source()
def test_measure_median_execution_cost(self): def f(x): x += 1 x += 1 x += 1 while True: x += 1 x += 1 x += 1 if x: break x += 1 x += 1 x += 1 x += 1 x += 1 x += 1 return x t = TranslationContext() graph = t.buildflowgraph(f) res = measure_median_execution_cost(graph) assert round(res, 5) == round(32.333333333, 5)
def test_data_flow_families(): def snippet_fn(xx, yy): while yy > 0: if 0 < xx: yy = yy - xx else: yy = yy + xx return yy t = TranslationContext() graph = t.buildflowgraph(snippet_fn) operations = [] for block in graph.iterblocks(): operations += block.operations variable_families = DataFlowFamilyBuilder(graph).get_variable_families() # we expect to find xx only once: v_xx = variable_families.find_rep(graph.getargs()[0]) found = 0 for op in operations: if op.opname in ('add', 'sub', 'lt'): assert variable_families.find_rep(op.args[1]) == v_xx found += 1 assert found == 3
def test_example(): t = TranslationContext(simplifying=True) t.buildflowgraph(example)
def test_example(): t = TranslationContext(simplifying=True) t.buildflowgraph(example)
def check(self, f1, expected): t = TranslationContext(list_comprehension_operations=True) graph = t.buildflowgraph(f1) if conftest.option.view: graph.show() assert summary(graph) == expected
class Translation(object): def __init__(self, entry_point, argtypes=None, **kwds): self.driver = driver.TranslationDriver(overrides=DEFAULTS) self.config = self.driver.config self.entry_point = entry_point self.context = TranslationContext(config=self.config) # hook into driver events driver_own_event = self.driver._event def _event(kind, goal, func): self.driver_event(kind, goal, func) driver_own_event(kind, goal, func) self.driver._event = _event self.driver_setup = False self.update_options(argtypes, kwds) # for t.view() to work just after construction graph = self.context.buildflowgraph(entry_point) self.context._prebuilt_graphs[entry_point] = graph def view(self): self.context.view() def viewcg(self): self.context.viewcg() def driver_event(self, kind, goal, func): if kind == 'pre': #print goal self.ensure_setup() elif kind == 'post': pass def ensure_setup(self, argtypes=None, policy=None, standalone=False): if not self.driver_setup: if standalone: assert argtypes is None else: if argtypes is None: argtypes = [] self.driver.setup(self.entry_point, argtypes, policy, empty_translator=self.context) self.ann_argtypes = argtypes self.ann_policy = policy self.driver_setup = True else: # check consistency if standalone: assert argtypes is None assert self.ann_argtypes is None elif argtypes is not None and argtypes != self.ann_argtypes: raise Exception("inconsistent argtype supplied") if policy is not None and policy != self.ann_policy: raise Exception("inconsistent annotation polish supplied") def update_options(self, argtypes, kwds): if argtypes or kwds.get('policy') or kwds.get('standalone'): self.ensure_setup(argtypes, kwds.get('policy'), kwds.get('standalone')) kwds.pop('policy', None) kwds.pop('standalone', None) gc = kwds.pop('gc', None) if gc: self.config.translation.gc = gc self.config.translation.set(**kwds) def ensure_opt(self, name, value=None, fallback=None): if value is not None: self.update_options(None, {name: value}) return value val = getattr(self.config.translation, name, None) if fallback is not None and val is None: self.update_options(None, {name: fallback}) return fallback if val is not None: return val raise Exception( "the %r option should have been specified at this point" % name) def ensure_type_system(self, type_system=None): if self.config.translation.backend is not None: return self.ensure_opt('type_system') return self.ensure_opt('type_system', type_system, 'lltype') def ensure_backend(self, backend=None): backend = self.ensure_opt('backend', backend) self.ensure_type_system() return backend # disable some goals (steps) def disable(self, to_disable): self.driver.disable(to_disable) def set_backend_extra_options(self, **extra_options): for name in extra_options: backend, option = name.split('_', 1) self.ensure_backend(backend) self.driver.set_backend_extra_options(extra_options) # backend independent def annotate(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) return self.driver.annotate() # type system dependent def rtype(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) ts = self.ensure_type_system() return getattr(self.driver, 'rtype_' + ts)() def backendopt(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) ts = self.ensure_type_system('lltype') return getattr(self.driver, 'backendopt_' + ts)() # backend depedent def source(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) backend = self.ensure_backend() getattr(self.driver, 'source_' + backend)() def source_c(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('c') self.driver.source_c() def source_cl(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('cl') self.driver.source_cl() def compile(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) backend = self.ensure_backend() getattr(self.driver, 'compile_' + backend)() return self.driver.c_entryp def compile_c(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('c') self.driver.compile_c() return self.driver.c_entryp def compile_cli(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('cli') self.driver.compile_cli() return self.driver.c_entryp def source_cli(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('cli') self.driver.source_cli() def compile_jvm(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('jvm') self.driver.compile_jvm() return self.driver.c_entryp def source_jvm(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('jvm') self.driver.source_jvm()
class Translation(object): def __init__(self, entry_point, argtypes=None, **kwds): self.driver = driver.TranslationDriver(overrides=DEFAULTS) self.config = self.driver.config self.entry_point = entry_point self.context = TranslationContext(config=self.config) # hook into driver events driver_own_event = self.driver._event def _event(kind, goal, func): self.driver_event(kind, goal, func) driver_own_event(kind, goal, func) self.driver._event = _event self.driver_setup = False self.update_options(argtypes, kwds) # for t.view() to work just after construction graph = self.context.buildflowgraph(entry_point) self.context._prebuilt_graphs[entry_point] = graph def view(self): self.context.view() def viewcg(self): self.context.viewcg() def driver_event(self, kind, goal, func): if kind == 'pre': #print goal self.ensure_setup() elif kind == 'post': pass def ensure_setup(self, argtypes=None, policy=None, standalone=False): if not self.driver_setup: if standalone: assert argtypes is None else: if argtypes is None: argtypes = [] self.driver.setup(self.entry_point, argtypes, policy, empty_translator=self.context) self.ann_argtypes = argtypes self.ann_policy = policy self.driver_setup = True else: # check consistency if standalone: assert argtypes is None assert self.ann_argtypes is None elif argtypes is not None and argtypes != self.ann_argtypes: raise Exception("inconsistent argtype supplied") if policy is not None and policy != self.ann_policy: raise Exception("inconsistent annotation polish supplied") def update_options(self, argtypes, kwds): if argtypes or kwds.get('policy') or kwds.get('standalone'): self.ensure_setup(argtypes, kwds.get('policy'), kwds.get('standalone')) kwds.pop('policy', None) kwds.pop('standalone', None) gc = kwds.pop('gc', None) if gc: self.config.translation.gc = gc self.config.translation.set(**kwds) def ensure_opt(self, name, value=None, fallback=None): if value is not None: self.update_options(None, {name: value}) return value val = getattr(self.config.translation, name, None) if fallback is not None and val is None: self.update_options(None, {name: fallback}) return fallback if val is not None: return val raise Exception( "the %r option should have been specified at this point" %name) def ensure_type_system(self, type_system=None): if self.config.translation.backend is not None: return self.ensure_opt('type_system') return self.ensure_opt('type_system', type_system, 'lltype') def ensure_backend(self, backend=None): backend = self.ensure_opt('backend', backend) self.ensure_type_system() return backend # disable some goals (steps) def disable(self, to_disable): self.driver.disable(to_disable) def set_backend_extra_options(self, **extra_options): for name in extra_options: backend, option = name.split('_', 1) self.ensure_backend(backend) self.driver.set_backend_extra_options(extra_options) # backend independent def annotate(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) return self.driver.annotate() # type system dependent def rtype(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) ts = self.ensure_type_system() return getattr(self.driver, 'rtype_'+ts)() def backendopt(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) ts = self.ensure_type_system('lltype') return getattr(self.driver, 'backendopt_'+ts)() # backend depedent def source(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) backend = self.ensure_backend() getattr(self.driver, 'source_'+backend)() def source_c(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('c') self.driver.source_c() def source_cl(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('cl') self.driver.source_cl() def compile(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) backend = self.ensure_backend() getattr(self.driver, 'compile_'+backend)() return self.driver.c_entryp def compile_c(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('c') self.driver.compile_c() return self.driver.c_entryp def compile_cli(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('cli') self.driver.compile_cli() return self.driver.c_entryp def source_cli(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('cli') self.driver.source_cli() def compile_jvm(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('jvm') self.driver.compile_jvm() return self.driver.c_entryp def source_jvm(self, argtypes=None, **kwds): self.update_options(argtypes, kwds) self.ensure_backend('jvm') self.driver.source_jvm()