PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/metainterp/optimizeopt/test/test_dependency.py

https://bitbucket.org/pypy/pypy/
Python | 693 lines | 683 code | 8 blank | 2 comment | 14 complexity | f01d0be8171049f0cb0dd671f47625f4 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import pytest
  3. from rpython.jit.metainterp.compile import invent_fail_descr_for_op
  4. from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop
  5. from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, Dependency,
  6. IndexVar, MemoryRef, Node)
  7. from rpython.jit.metainterp.optimizeopt.vector import VectorLoop
  8. from rpython.jit.metainterp.optimizeopt.test.test_util import (
  9. LLtypeMixin, BaseTest, FakeMetaInterpStaticData, convert_old_style_to_targets,
  10. FakeJitDriverStaticData)
  11. from rpython.jit.metainterp.resoperation import rop, ResOperation
  12. from rpython.jit.backend.llgraph.runner import ArrayDescr
  13. from rpython.jit.tool.oparser import OpParser
  14. from rpython.rtyper.lltypesystem import rffi
  15. from rpython.rtyper.lltypesystem import lltype
  16. from rpython.conftest import option
  17. class FakeDependencyGraph(DependencyGraph):
  18. """ A dependency graph that is able to emit every instruction
  19. one by one. """
  20. def __init__(self, loop):
  21. self.loop = loop
  22. if isinstance(loop, list):
  23. self.nodes = loop
  24. else:
  25. operations = loop.operations
  26. self.nodes = [Node(op,i) for i,op in \
  27. enumerate(operations)]
  28. self.schedulable_nodes = list(reversed(self.nodes))
  29. self.guards = []
  30. class DependencyBaseTest(BaseTest):
  31. def setup_method(self, method):
  32. self.test_name = method.__name__
  33. def build_dependency(self, ops):
  34. loop = self.parse_loop(ops)
  35. graph = DependencyGraph(loop)
  36. self.show_dot_graph(graph, self.test_name)
  37. for node in graph.nodes:
  38. assert node.independent(node)
  39. graph.parsestr = ops
  40. return graph
  41. def match_op(self, expected, actual, remap):
  42. if expected.getopnum() != actual.getopnum():
  43. return False
  44. expargs = expected.getarglist()
  45. actargs = [remap.get(arg, None) for arg in actual.getarglist()]
  46. if not all([e == a or a is None for e,a in zip(expargs,actargs)]):
  47. return False
  48. if expected.getfailargs():
  49. expargs = expected.getfailargs()
  50. actargs = [remap.get(arg, None) for arg in actual.getfailargs()]
  51. if not all([e == a or a is None for e,a in zip(expargs,actargs)]):
  52. return False
  53. return True
  54. def ensure_operations(self, opstrlist, trace, inthatorder=True):
  55. oparse = OpParser('', self.cpu, self.namespace, None,
  56. None, True, None)
  57. oplist = []
  58. for op_str in opstrlist:
  59. op = oparse.parse_next_op(op_str)
  60. if not op.returns_void():
  61. var = op_str.split('=')[0].strip()
  62. if '[' in var:
  63. var = var[:var.find('[')]
  64. elem = op_str[:len(var)]
  65. oparse._cache['lltype', elem] = op
  66. oplist.append(op)
  67. oplist_i = 0
  68. match = False
  69. remap = {}
  70. last_match = 0
  71. for i, op in enumerate(trace.operations):
  72. if oplist_i >= len(oplist):
  73. break
  74. curtomatch = oplist[oplist_i]
  75. if self.match_op(curtomatch, op, remap):
  76. if not op.returns_void():
  77. remap[curtomatch] = op
  78. oplist_i += 1
  79. last_match = i
  80. msg = "could not find all ops in the trace sequence\n\n"
  81. if oplist_i != len(oplist):
  82. l = [str(o) for o in oplist[oplist_i:]]
  83. msg += "sequence\n " + '\n '.join(l)
  84. msg += "\n\ndoes not match\n "
  85. l = [str(o) for o in trace.operations[last_match+1:]]
  86. msg += '\n '.join(l)
  87. assert oplist_i == len(oplist), msg
  88. def parse_loop(self, ops, add_label=True):
  89. loop = self.parse(ops)
  90. loop.operations = filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations)
  91. token = JitCellToken()
  92. if add_label:
  93. label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token))
  94. else:
  95. label = loop.operations[0]
  96. label.setdescr(TargetToken(token))
  97. jump = loop.operations[-1]
  98. loop = VectorLoop(label, loop.operations[0:-1], jump)
  99. loop.jump.setdescr(token)
  100. class Optimizer(object):
  101. metainterp_sd = FakeMetaInterpStaticData(self.cpu)
  102. jitdriver_sd = FakeJitDriverStaticData()
  103. opt = Optimizer()
  104. opt.jitdriver_sd.vec = True
  105. for op in loop.operations:
  106. if op.is_guard() and not op.getdescr():
  107. descr = invent_fail_descr_for_op(op.getopnum(), opt)
  108. op.setdescr(descr)
  109. return loop
  110. def parse_trace(self, source, inc_label_jump=True, pargs=2, iargs=10,
  111. fargs=6, additional_args=None, replace_args=None):
  112. args = []
  113. for prefix, rang in [('p',range(pargs)),
  114. ('i',range(iargs)),
  115. ('f',range(fargs))]:
  116. for i in rang:
  117. args.append(prefix + str(i))
  118. assert additional_args is None or isinstance(additional_args,list)
  119. for arg in additional_args or []:
  120. args.append(arg)
  121. for k,v in (replace_args or {}).items():
  122. for i,_ in enumerate(args):
  123. if k == args[i]:
  124. args[i] = v
  125. break
  126. indent = " "
  127. joinedargs = ','.join(args)
  128. fmt = (indent, joinedargs, source, indent, joinedargs)
  129. src = "%s[%s]\n%s\n%sjump(%s)" % fmt
  130. loop = self.parse_loop(src)
  131. # needed to assign the right number to the input
  132. # arguments
  133. [str(arg) for arg in loop.inputargs]
  134. loop.graph = FakeDependencyGraph(loop)
  135. loop.setup_vectorization()
  136. return loop
  137. def assert_edges(self, graph, edge_list, exceptions):
  138. """ Check if all dependencies are met. for complex cases
  139. adding None instead of a list of integers skips the test.
  140. This checks both if a dependency forward and backward exists.
  141. """
  142. assert len(edge_list) == len(graph.nodes) + 2
  143. edge_list = edge_list[1:-1]
  144. for idx,edges in enumerate(edge_list):
  145. if edges is None:
  146. continue
  147. node_a = graph.getnode(idx)
  148. dependencies = node_a.provides()[:]
  149. for idx_b in edges:
  150. if idx_b == 0 or idx_b >= len(graph.nodes) + 2 -1:
  151. continue
  152. idx_b -= 1
  153. node_b = graph.getnode(idx_b)
  154. dependency = node_a.getedge_to(node_b)
  155. if dependency is None and idx_b not in exceptions.setdefault(idx,[]):
  156. self.show_dot_graph(graph, self.test_name + '_except')
  157. assert dependency is not None or node_b.getopnum() == rop.JUMP, \
  158. " it is expected that instruction at index" + \
  159. " %s depends on instr on index %s but it does not.\n%s" \
  160. % (node_a.getindex(), node_b.getindex(), graph)
  161. elif dependency is not None:
  162. dependencies.remove(dependency)
  163. assert dependencies == [], \
  164. "dependencies unexpected %s.\n%s" \
  165. % (dependencies,graph)
  166. def assert_dependencies(self, graph, full_check=True):
  167. import re
  168. deps = {}
  169. exceptions = {}
  170. for i,line in enumerate(graph.parsestr.splitlines()):
  171. dep_pattern = re.compile("#\s*(\d+):")
  172. dep_match = dep_pattern.search(line)
  173. if dep_match:
  174. label = int(dep_match.group(1))
  175. deps_list = []
  176. deps[label] = []
  177. for to in [d for d in line[dep_match.end():].split(',') if len(d) > 0]:
  178. exception = to.endswith("?")
  179. if exception:
  180. to = to[:-1]
  181. exceptions.setdefault(label,[]).append(int(to))
  182. deps[label].append(int(to))
  183. if full_check:
  184. edges = [ None ] * len(deps)
  185. for k,l in deps.items():
  186. edges[k] = l
  187. self.assert_edges(graph, edges, exceptions)
  188. return graph
  189. def assert_independent(self, graph, a, b):
  190. a -= 1
  191. b -= 1
  192. a = graph.getnode(a)
  193. b = graph.getnode(b)
  194. assert a.independent(b), "{a} and {b} are dependent!".format(a=a,b=b)
  195. def assert_dependent(self, graph, a, b):
  196. a -= 1
  197. b -= 1
  198. a = graph.getnode(a)
  199. b = graph.getnode(b)
  200. assert not a.independent(b), "{a} and {b} are independent!".format(a=a,b=b)
  201. def show_dot_graph(self, graph, name):
  202. if option and option.viewdeps:
  203. from rpython.translator.tool.graphpage import GraphPage
  204. page = GraphPage()
  205. page.source = graph.as_dot()
  206. page.links = []
  207. page.display()
  208. def debug_print_operations(self, loop):
  209. print('--- loop instr numbered ---')
  210. for i,op in enumerate(loop.operations):
  211. print "[",i,"]",op,
  212. if op.is_guard():
  213. print op.getfailargs()
  214. else:
  215. print ""
  216. def assert_memory_ref_adjacent(self, m1, m2):
  217. assert m1.is_adjacent_to(m2)
  218. assert m2.is_adjacent_to(m1)
  219. def assert_memory_ref_not_adjacent(self, m1, m2):
  220. assert not m1.is_adjacent_to(m2)
  221. assert not m2.is_adjacent_to(m1)
  222. class BaseTestDependencyGraph(DependencyBaseTest):
  223. def test_index_var_basic(self):
  224. b = FakeBox()
  225. i = IndexVar(b,1,1,0)
  226. j = IndexVar(b,1,1,0)
  227. assert i.is_identity()
  228. assert i.same_variable(j)
  229. assert i.constant_diff(j) == 0
  230. def test_index_var_diff(self):
  231. b = FakeBox()
  232. i = IndexVar(b,4,2,0)
  233. j = IndexVar(b,1,1,1)
  234. assert not i.is_identity()
  235. assert not j.is_identity()
  236. assert not i.same_mulfactor(j)
  237. assert i.constant_diff(j) == -1
  238. def test_memoryref_basic(self):
  239. i = FakeBox()
  240. a = FakeBox()
  241. m1 = memoryref(a, i, (1,1,0))
  242. m2 = memoryref(a, i, (1,1,0))
  243. assert m1.alias(m2)
  244. @py.test.mark.parametrize('coeff1,coeff2,state',
  245. # +------------------ adjacent
  246. # |+----------------- adjacent_after
  247. # ||+---------------- adjacent_befure
  248. # |||+--------------- alias
  249. # ||||
  250. [((1,1,0), (1,1,0), 'ffft'),
  251. ((4,2,0), (8,4,0), 'ffft'),
  252. ((4,2,0), (8,2,0), 'ffft'),
  253. ((4,2,1), (8,4,0), 'tftf'),
  254. ])
  255. def test_memoryref_adjacent_alias(self, coeff1, coeff2, state):
  256. i = FakeBox()
  257. a = FakeBox()
  258. m1 = memoryref(a, i, coeff1)
  259. m2 = memoryref(a, i, coeff2)
  260. adja = state[0] == 't'
  261. adja_after = state[1] == 't'
  262. adja_before = state[2] == 't'
  263. alias = state[3] == 't'
  264. assert m1.is_adjacent_to(m2) == adja
  265. assert m2.is_adjacent_to(m1) == adja
  266. assert m1.is_adjacent_after(m2) == adja_after
  267. assert m2.is_adjacent_after(m1) == adja_before
  268. assert m1.alias(m2) == alias
  269. def test_dependency_empty(self):
  270. graph = self.build_dependency("""
  271. [] # 0: 1
  272. jump() # 1:
  273. """)
  274. self.assert_dependencies(graph, full_check=True)
  275. def test_dependency_of_constant_not_used(self):
  276. graph = self.build_dependency("""
  277. [] # 0: 2
  278. i1 = int_add(1,1) # 1: 2
  279. jump() # 2:
  280. """)
  281. self.assert_dependencies(graph, full_check=True)
  282. def test_dependency_simple(self):
  283. graph = self.build_dependency("""
  284. [] # 0: 4
  285. i1 = int_add(1,1) # 1: 2
  286. i2 = int_add(i1,1) # 2: 3
  287. guard_value(i2,3) [] # 3: 4
  288. jump() # 4:
  289. """)
  290. graph = self.assert_dependencies(graph, full_check=True)
  291. self.assert_dependent(graph, 1,2)
  292. self.assert_dependent(graph, 2,3)
  293. self.assert_dependent(graph, 1,3)
  294. def test_def_use_jump_use_def(self):
  295. graph = self.build_dependency("""
  296. [i3] # 0: 1
  297. i1 = int_add(i3,1) # 1: 2, 3
  298. guard_value(i1,0) [] # 2: 3
  299. jump(i1) # 3:
  300. """)
  301. self.assert_dependencies(graph, full_check=True)
  302. def test_dependency_guard(self):
  303. graph = self.build_dependency("""
  304. [i3] # 0: 2,3
  305. i1 = int_add(1,1) # 1: 2
  306. guard_value(i1,0) [i3] # 2: 3
  307. jump(i3) # 3:
  308. """)
  309. self.assert_dependencies(graph, full_check=True)
  310. def test_dependency_guard_2(self):
  311. graph = self.build_dependency("""
  312. [i1] # 0: 1,2?,3
  313. i2 = int_le(i1, 10) # 1: 2
  314. guard_true(i2) [i1] # 2:
  315. i3 = int_add(i1,1) # 3: 4
  316. jump(i3) # 4:
  317. """)
  318. self.assert_dependencies(graph, full_check=True)
  319. def test_no_edge_duplication(self):
  320. graph = self.build_dependency("""
  321. [i1] # 0: 1,2?,3
  322. i2 = int_lt(i1,10) # 1: 2
  323. guard_false(i2) [i1] # 2:
  324. i3 = int_add(i1,i1) # 3: 4
  325. jump(i3) # 4:
  326. """)
  327. self.assert_dependencies(graph, full_check=True)
  328. def test_no_edge_duplication_in_guard_failargs(self):
  329. graph = self.build_dependency("""
  330. [i1] # 0: 1,2?,3?
  331. i2 = int_lt(i1,10) # 1: 2
  332. guard_false(i2) [i1,i1,i2,i1,i2,i1] # 2: 3
  333. jump(i1) # 3:
  334. """)
  335. self.assert_dependencies(graph, full_check=True)
  336. def test_dependencies_1(self):
  337. graph = self.build_dependency("""
  338. [i0, i1, i2] # 0: 1,3,6,7,11?
  339. i4 = int_gt(i1, 0) # 1: 2
  340. guard_true(i4) [] # 2: 5, 11?
  341. i6 = int_sub(i1, 1) # 3: 4
  342. i8 = int_gt(i6, 0) # 4: 5
  343. guard_false(i8) [] # 5: 10
  344. i10 = int_add(i2, 1) # 6: 8
  345. i12 = int_sub(i0, 1) # 7: 9, 11
  346. i14 = int_add(i10, 1) # 8: 11
  347. i16 = int_gt(i12, 0) # 9: 10
  348. guard_true(i16) [] # 10: 11
  349. jump(i12, i1, i14) # 11:
  350. """)
  351. self.assert_dependencies(graph, full_check=True)
  352. self.assert_independent(graph, 6, 2)
  353. self.assert_independent(graph, 6, 1)
  354. def test_prevent_double_arg(self):
  355. graph = self.build_dependency("""
  356. [i0, i1, i2] # 0: 1,3
  357. i4 = int_gt(i1, i0) # 1: 2
  358. guard_true(i4) [] # 2: 3
  359. jump(i0, i1, i2) # 3:
  360. """)
  361. self.assert_dependencies(graph, full_check=True)
  362. def test_ovf_dep(self):
  363. graph = self.build_dependency("""
  364. [i0, i1, i2] # 0: 2,3
  365. i4 = int_sub_ovf(1, 0) # 1: 2
  366. guard_overflow() [i2] # 2: 3
  367. jump(i0, i1, i2) # 3:
  368. """)
  369. self.assert_dependencies(graph, full_check=True)
  370. def test_exception_dep(self):
  371. graph = self.build_dependency("""
  372. [p0, i1, i2] # 0: 1,3?
  373. i4 = call_i(p0, 1, descr=nonwritedescr) # 1: 2,3
  374. guard_no_exception() [] # 2: 3
  375. jump(p0, i1, i2) # 3:
  376. """)
  377. self.assert_dependencies(graph, full_check=True)
  378. def test_call_dependency_on_ptr_but_not_index_value(self):
  379. graph = self.build_dependency("""
  380. [p0, p1, i2] # 0: 1,2?,3?,4?,5?
  381. i3 = int_add(i2,1) # 1: 2
  382. i4 = call_i(p0, i3, descr=nonwritedescr) # 2: 3,4,5?
  383. guard_no_exception() [i2] # 3:
  384. p2 = getarrayitem_gc_r(p1, i3, descr=arraydescr) # 4: 5
  385. jump(p2, p1, i3) # 5:
  386. """)
  387. self.assert_dependencies(graph, full_check=True)
  388. def test_call_dependency(self):
  389. graph = self.build_dependency("""
  390. [p0, p1, i2, i5] # 0: 1,2?,3?,4?,5?
  391. i3 = int_add(i2,1) # 1: 2
  392. i4 = call_i(i5, i3, descr=nonwritedescr) # 2: 3,4,5?
  393. guard_no_exception() [i2] # 3: 5?
  394. p2 = getarrayitem_gc_r(p1,i3,descr=chararraydescr) # 4: 5
  395. jump(p2, p1, i3, i5) # 5:
  396. """)
  397. self.assert_dependencies(graph, full_check=True)
  398. def test_call_not_forced_exception(self):
  399. graph = self.build_dependency("""
  400. [p0, p1, i2, i5] # 0: 1,2,4?,5,6
  401. i4 = call_i(i5, i2, descr=nonwritedescr) # 1: 2,4,6
  402. guard_not_forced() [i2] # 2: 3
  403. guard_no_exception() [] # 3: 6
  404. i3 = int_add(i2,1) # 4: 5
  405. p2 = getarrayitem_gc_r(p1,i3,descr=chararraydescr) # 5: 6
  406. jump(p2, p1, i2, i5) # 6:
  407. """)
  408. self.assert_dependencies(graph, full_check=True)
  409. assert graph.nodes[1].priority == 100
  410. assert graph.nodes[2].priority == 100
  411. def test_setarrayitem_dependency(self):
  412. graph = self.build_dependency("""
  413. [p0, i1] # 0: 1,2?,3?,4?
  414. setarrayitem_raw(p0, i1, 1, descr=floatarraydescr) # 1: 2,3
  415. i2 = getarrayitem_raw_i(p0, i1, descr=floatarraydescr) # 2: 4
  416. setarrayitem_raw(p0, i1, 2, descr=floatarraydescr) # 3: 4
  417. jump(p0, i2) # 4:
  418. """)
  419. self.assert_dependencies(graph, full_check=True)
  420. def test_setarrayitem_alias_dependency(self):
  421. # #1 depends on #2, i1 and i2 might alias, reordering would destroy
  422. # coorectness
  423. graph = self.build_dependency("""
  424. [p0, i1, i2] # 0: 1,2?,3?
  425. setarrayitem_raw(p0, i1, 1, descr=floatarraydescr) # 1: 2
  426. setarrayitem_raw(p0, i2, 2, descr=floatarraydescr) # 2: 3
  427. jump(p0, i1, i2) # 3:
  428. """)
  429. self.assert_dependencies(graph, full_check=True)
  430. self.assert_dependent(graph, 1,2)
  431. def test_setarrayitem_dont_depend_with_memref_info(self):
  432. graph = self.build_dependency("""
  433. [p0, i1] # 0: 1,2,3?,4?
  434. setarrayitem_raw(p0, i1, 1, descr=chararraydescr) # 1: 4
  435. i2 = int_add(i1,1) # 2: 3
  436. setarrayitem_raw(p0, i2, 2, descr=chararraydescr) # 3: 4
  437. jump(p0, i1) # 4:
  438. """)
  439. self.assert_dependencies(graph, full_check=True)
  440. self.assert_independent(graph, 1,2)
  441. self.assert_independent(graph, 1,3) # they modify 2 different cells
  442. def test_dependency_complex_trace(self):
  443. graph = self.build_dependency("""
  444. [i0, i1, i2, i3, i4, i5, i6, i7] # 0:
  445. i9 = int_mul(i0, 8) # 1: 2
  446. i10 = raw_load_i(i3, i9, descr=arraydescr) # 2: 5, 10
  447. i11 = int_mul(i0, 8) # 3: 4
  448. i12 = raw_load_i(i4, i11, descr=arraydescr) # 4: 5,10
  449. i13 = int_add(i10, i12) # 5: 7,10
  450. i14 = int_mul(i0, 8) # 6: 7
  451. raw_store(i3, i14, i13, descr=arraydescr) # 7: 10,12,20
  452. i16 = int_add(i0, 1) # 8: 9,10,11,13,16,18
  453. i17 = int_lt(i16, i7) # 9: 10
  454. guard_true(i17) [i7, i13, i5, i4, i3, i12, i10, i16] # 10: 17, 20
  455. i18 = int_mul(i16, 9) # 11: 12
  456. i19 = raw_load_i(i3, i18, descr=arraydescr) # 12: 15, 20
  457. i20 = int_mul(i16, 8) # 13: 14
  458. i21 = raw_load_i(i4, i20, descr=arraydescr) # 14: 15, 20
  459. i22 = int_add(i19, i21) # 15: 17, 20
  460. i23 = int_mul(i16, 8) # 16: 17
  461. raw_store(i5, i23, i22, descr=arraydescr) # 17: 20
  462. i24 = int_add(i16, 1) # 18: 19, 20
  463. i25 = int_lt(i24, i7) # 19: 20
  464. guard_true(i25) [i7, i22, i5, i4, i3, i21, i19, i24] # 20:
  465. jump(i24, i19, i21, i3, i4, i5, i22, i7) # 21:
  466. """)
  467. self.assert_dependencies(graph, full_check=True)
  468. self.assert_dependent(graph, 2,12)
  469. self.assert_dependent(graph, 7,12)
  470. self.assert_dependent(graph, 4,12)
  471. def test_getfield(self):
  472. graph = self.build_dependency("""
  473. [p0, p1] # 0: 1,2,5
  474. p2 = getfield_gc_r(p0, descr=valuedescr) # 1: 3,5
  475. p3 = getfield_gc_r(p0, descr=valuedescr) # 2: 4
  476. guard_nonnull(p2) [p2] # 3: 4,5
  477. guard_nonnull(p3) [p3] # 4: 5
  478. jump(p0,p2) # 5:
  479. """)
  480. self.assert_dependencies(graph, full_check=True)
  481. def test_cyclic(self):
  482. graph = self.build_dependency("""
  483. [p0, p1, p5, p6, p7, p9, p11, p12] # 0: 1,6
  484. p13 = getfield_gc_r(p9, descr=valuedescr) # 1: 2,5
  485. guard_nonnull(p13) [] # 2: 4,5
  486. i14 = getfield_gc_i(p9, descr=valuedescr) # 3: 5
  487. p15 = getfield_gc_r(p13, descr=valuedescr) # 4: 5
  488. guard_class(p15, 14073732) [p1, p0, p9, i14, p15, p13, p5, p6, p7] # 5: 6
  489. jump(p0,p1,p5,p6,p7,p9,p11,p12) # 6:
  490. """)
  491. self.assert_dependencies(graph, full_check=True)
  492. def test_iterate(self):
  493. n1,n2,n3,n4,n5 = [FakeNode(i+1) for i in range(5)]
  494. # n1 -> n2 -> n4 -> n5
  495. # +---> n3 --^
  496. n1.edge_to(n2); n2.edge_to(n4); n4.edge_to(n5)
  497. n1.edge_to(n3); n3.edge_to(n4);
  498. paths = list(n5.iterate_paths(n1, backwards=True))
  499. assert all([path.check_acyclic() for path in paths])
  500. assert len(paths) == 2
  501. assert paths[0].as_str() == "n5 -> n4 -> n2 -> n1"
  502. assert paths[1].as_str() == "n5 -> n4 -> n3 -> n1"
  503. paths = list(n1.iterate_paths(n5))
  504. assert all([path.check_acyclic() for path in paths])
  505. assert len(paths) == 2
  506. assert paths[0].as_str() == "n1 -> n2 -> n4 -> n5"
  507. assert paths[1].as_str() == "n1 -> n3 -> n4 -> n5"
  508. def test_iterate_one_many_one(self):
  509. r = range(19)
  510. n0 = FakeNode(0)
  511. nodes = [FakeNode(i+1) for i in r]
  512. nend = FakeNode(len(r)+1)
  513. assert len(list(n0.iterate_paths(nodes[0], backwards=True))) == 0
  514. for i in r:
  515. n0.edge_to(nodes[i])
  516. nodes[i].edge_to(nend)
  517. paths = list(nend.iterate_paths(n0, backwards=True))
  518. assert all([path.check_acyclic() for path in paths])
  519. assert len(paths) == len(r)
  520. for i in r:
  521. assert paths[i].as_str() == "n%d -> %s -> n0" % (len(r)+1, nodes[i])
  522. # forward
  523. paths = list(n0.iterate_paths(nend))
  524. assert all([path.check_acyclic() for path in paths])
  525. assert len(paths) == len(r)
  526. for i in r:
  527. assert paths[i].as_str() == "n0 -> %s -> n%d" % (nodes[i], len(r)+1)
  528. def test_iterate_blacklist_diamond(self):
  529. blacklist = {}
  530. n1,n2,n3,n4 = [FakeNode(i+1) for i in range(4)]
  531. # n1 -> n2 -> n4
  532. # +---> n3 --^
  533. n1.edge_to(n2); n2.edge_to(n4);
  534. n1.edge_to(n3); n3.edge_to(n4);
  535. paths = list(n1.iterate_paths(n4, blacklist=True))
  536. assert len(paths) == 2
  537. assert paths[0].as_str() == "n1 -> n2 -> n4"
  538. assert paths[1].as_str() == "n1 -> n3 -> n4"
  539. def test_iterate_blacklist_double_diamond(self):
  540. blacklist = {}
  541. n1,n2,n3,n4,n5,n6,n7,n8 = [FakeNode(i+1) for i in range(8)]
  542. # n1 -> n2 -> n4 -> n5 -> n6 --> n8
  543. # +---> n3 --^ +---> n7 --^
  544. n1.edge_to(n2); n2.edge_to(n4);
  545. n1.edge_to(n3); n3.edge_to(n4);
  546. n4.edge_to(n5)
  547. n5.edge_to(n6); n6.edge_to(n8);
  548. n5.edge_to(n7); n7.edge_to(n8);
  549. paths = list(n1.iterate_paths(n8, blacklist=True))
  550. assert len(paths) == 3
  551. assert paths[0].as_str() == "n1 -> n2 -> n4 -> n5 -> n6 -> n8"
  552. assert paths[1].as_str() == "n1 -> n2 -> n4 -> n5 -> n7 -> n8"
  553. assert paths[2].as_str() == "n1 -> n3 -> n4"
  554. def test_iterate_blacklist_split_path(self):
  555. blacklist = {}
  556. n1,n2,n3,n4,n5,n6,n7,n8 = [FakeNode(i+1) for i in range(8)]
  557. n1.edge_to(n2);
  558. n3.edge_to(n2);
  559. n2.edge_to(n4);
  560. n3.edge_to(n4);
  561. paths = list(n4.iterate_paths(n3, backwards=True, blacklist=True))
  562. assert len(paths) == 2
  563. assert paths[0].as_str() == "n4 -> n2 -> n3"
  564. assert paths[1].as_str() == "n4 -> n3"
  565. n5.edge_to(n1)
  566. n5.edge_to(n3)
  567. paths = list(n4.iterate_paths(n5, backwards=True, blacklist=True))
  568. assert len(paths) == 3
  569. assert paths[0].as_str() == "n4 -> n2 -> n1 -> n5"
  570. assert paths[1].as_str() == "n4 -> n2 -> n3 -> n5"
  571. assert paths[2].as_str() == "n4 -> n3"
  572. def test_sccs(self):
  573. n1,n2 = FakeNode(1), FakeNode(2)
  574. n1.edge_to(n2); n2.edge_to(n1)
  575. graph = FakeDependencyGraph([n1,n2])
  576. cycle = graph.cycles()
  577. assert cycle == [n1, n2]
  578. n3 = FakeNode(0)
  579. graph.nodes = [n3]
  580. cycle = graph.cycles()
  581. assert cycle is None
  582. def test_cycles_2(self):
  583. n1,n2,n3,n4 = FakeNode(1), FakeNode(2), FakeNode(3), FakeNode(4)
  584. n1.edge_to(n3); n3.edge_to(n4); n4.edge_to(n1)
  585. graph = FakeDependencyGraph([n1,n2])
  586. graph.nodes = [n1,n2,n3]
  587. cycle = graph.cycles()
  588. assert cycle is not None
  589. assert cycle == [n1,n3,n4]
  590. class FakeMemoryRefResOp(object):
  591. def __init__(self, array, descr):
  592. self.array = array
  593. self.descr = descr
  594. def getarg(self, index):
  595. return self.array
  596. def getdescr(self):
  597. return self.descr
  598. FLOAT = ArrayDescr(lltype.GcArray(lltype.Float), None)
  599. def memoryref(array, var, mod=(1,1,0), descr=None, raw=False):
  600. if descr is None:
  601. descr = FLOAT
  602. mul, div, off = mod
  603. op = FakeMemoryRefResOp(array, descr)
  604. return MemoryRef(op,
  605. IndexVar(var, mul, div, off),
  606. raw)
  607. class FakeBox(object):
  608. pass
  609. class FakeNode(Node):
  610. def __init__(self, i):
  611. Node.__init__(self, None, i)
  612. pass
  613. def __repr__(self):
  614. return "n%d" % self.opidx
  615. class TestLLtype(BaseTestDependencyGraph, LLtypeMixin):
  616. pass