PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/translator/backendopt/test/test_writeanalyze.py

https://bitbucket.org/pypy/pypy/
Python | 407 lines | 342 code | 59 blank | 6 comment | 18 complexity | b3289dd76ee46b187463ffeb0dc5fb1b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from rpython.rtyper.lltypesystem import lltype
  3. from rpython.translator.translator import TranslationContext, graphof
  4. from rpython.translator.backendopt.writeanalyze import WriteAnalyzer, top_set
  5. from rpython.translator.backendopt.writeanalyze import ReadWriteAnalyzer
  6. from rpython.translator.backendopt.all import backend_optimizations
  7. from rpython.conftest import option
  8. class BaseTest(object):
  9. Analyzer = WriteAnalyzer
  10. def translate(self, func, sig):
  11. t = TranslationContext()
  12. t.buildannotator().build_types(func, sig)
  13. t.buildrtyper().specialize()
  14. if option.view:
  15. t.view()
  16. return t, self.Analyzer(t)
  17. class TestWriteAnalyze(BaseTest):
  18. def test_writes_simple(self):
  19. def g(x):
  20. return True
  21. def f(x):
  22. return g(x - 1)
  23. t, wa = self.translate(f, [int])
  24. fgraph = graphof(t, f)
  25. result = wa.analyze(fgraph.startblock.operations[0])
  26. assert not result
  27. def test_writes_recursive(self):
  28. from rpython.translator.transform import insert_ll_stackcheck
  29. def g(x):
  30. return f(x)
  31. def f(x):
  32. if x:
  33. return g(x - 1)
  34. return 1
  35. t, wa = self.translate(f, [int])
  36. insert_ll_stackcheck(t)
  37. ggraph = graphof(t, g)
  38. result = wa.analyze(ggraph.startblock.operations[-1])
  39. assert not result
  40. def test_write_to_new_struct(self):
  41. class A(object):
  42. pass
  43. def f(x):
  44. a = A()
  45. a.baz = x # writes to a fresh new struct are ignored
  46. return a
  47. t, wa = self.translate(f, [int])
  48. fgraph = graphof(t, f)
  49. result = wa.analyze_direct_call(fgraph)
  50. assert not result
  51. def test_write_to_new_struct_2(self):
  52. class A(object):
  53. pass
  54. def f(x):
  55. a = A()
  56. # a few extra blocks
  57. i = 10
  58. while i > 0:
  59. i -= 1
  60. # done
  61. a.baz = x # writes to a fresh new struct are ignored
  62. return a
  63. t, wa = self.translate(f, [int])
  64. fgraph = graphof(t, f)
  65. result = wa.analyze_direct_call(fgraph)
  66. assert not result
  67. def test_write_to_new_struct_3(self):
  68. class A(object):
  69. pass
  70. prebuilt = A()
  71. def f(x):
  72. if x > 5:
  73. a = A()
  74. else:
  75. a = A()
  76. a.baz = x
  77. return a
  78. t, wa = self.translate(f, [int])
  79. fgraph = graphof(t, f)
  80. result = wa.analyze_direct_call(fgraph)
  81. assert not result
  82. def test_write_to_new_struct_4(self):
  83. class A(object):
  84. pass
  85. prebuilt = A()
  86. def f(x):
  87. if x > 5:
  88. a = A()
  89. else:
  90. a = prebuilt
  91. a.baz = x
  92. return a
  93. t, wa = self.translate(f, [int])
  94. fgraph = graphof(t, f)
  95. result = wa.analyze_direct_call(fgraph)
  96. assert len(result) == 1 and 'baz' in list(result)[0][-1]
  97. def test_write_to_new_struct_5(self):
  98. class A(object):
  99. baz = 123
  100. def f(x):
  101. if x:
  102. a = A()
  103. else:
  104. a = A()
  105. a.baz += 1
  106. t, wa = self.translate(f, [int])
  107. fgraph = graphof(t, f)
  108. result = wa.analyze_direct_call(fgraph)
  109. assert not result
  110. def test_method(self):
  111. class A(object):
  112. def f(self):
  113. self.x = 1
  114. return 1
  115. def m(self):
  116. raise ValueError
  117. class B(A):
  118. def f(self):
  119. return 2
  120. def m(self):
  121. return 3
  122. def f(a):
  123. return a.f()
  124. def m(a):
  125. return a.m()
  126. def h(flag):
  127. if flag:
  128. obj = A()
  129. else:
  130. obj = B()
  131. f(obj)
  132. m(obj)
  133. t, wa = self.translate(h, [int])
  134. hgraph = graphof(t, h)
  135. # fiiiish :-(
  136. block = hgraph.startblock.exits[0].target.exits[0].target
  137. op_call_f = block.operations[0]
  138. op_call_m = block.operations[1]
  139. # check that we fished the expected ops
  140. def check_call(op, fname):
  141. assert op.opname == "direct_call"
  142. assert op.args[0].value._obj._name == fname
  143. check_call(op_call_f, "f")
  144. check_call(op_call_m, "m")
  145. result = wa.analyze(op_call_f)
  146. assert len(result) == 1
  147. (struct, T, name), = result
  148. assert struct == "struct"
  149. assert name.endswith("x")
  150. assert not wa.analyze(op_call_m)
  151. def test_instantiate(self):
  152. from rpython.rlib.objectmodel import instantiate
  153. class A:
  154. pass
  155. class B(A):
  156. pass
  157. def g(x):
  158. if x:
  159. C = A
  160. else:
  161. C = B
  162. a = instantiate(C)
  163. def f(x):
  164. return g(x)
  165. t, wa = self.translate(f, [int])
  166. fgraph = graphof(t, f)
  167. result = wa.analyze(fgraph.startblock.operations[0])
  168. assert not result
  169. def test_llexternal(self):
  170. from rpython.rtyper.lltypesystem.rffi import llexternal
  171. z = llexternal('z', [lltype.Signed], lltype.Signed)
  172. def f(x):
  173. return z(x)
  174. t, wa = self.translate(f, [int])
  175. fgraph = graphof(t, f)
  176. backend_optimizations(t)
  177. assert fgraph.startblock.operations[0].opname == 'direct_call'
  178. result = wa.analyze(fgraph.startblock.operations[0])
  179. assert not result
  180. def test_contains(self):
  181. def g(x, y, z):
  182. l = [x]
  183. return f(l, y, z)
  184. def f(x, y, z):
  185. return y in x
  186. t, wa = self.translate(g, [int, int, int])
  187. ggraph = graphof(t, g)
  188. assert ggraph.startblock.operations[-1].opname == 'direct_call'
  189. result = wa.analyze(ggraph.startblock.operations[-1])
  190. assert not result
  191. def test_list(self):
  192. def g(x, y, z):
  193. return f(x, y, z)
  194. def f(x, y, z):
  195. l = [0] * x
  196. l.append(y)
  197. return len(l) + z
  198. t, wa = self.translate(g, [int, int, int])
  199. ggraph = graphof(t, g)
  200. assert ggraph.startblock.operations[0].opname == 'direct_call'
  201. result = sorted(wa.analyze(ggraph.startblock.operations[0]))
  202. array, A = result[0]
  203. assert array == "array"
  204. assert A.TO.OF == lltype.Signed
  205. struct, S1, name = result[1]
  206. assert struct == "struct"
  207. assert S1.TO.items == A
  208. assert S1.TO.length == lltype.Signed
  209. assert name == "items"
  210. struct, S2, name = result[2]
  211. assert struct == "struct"
  212. assert name == "length"
  213. assert S1 is S2
  214. def test_llexternal_with_callback(self):
  215. from rpython.rtyper.lltypesystem.rffi import llexternal
  216. from rpython.rtyper.lltypesystem import lltype
  217. class Abc:
  218. pass
  219. abc = Abc()
  220. FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
  221. z = llexternal('z', [lltype.Ptr(FUNC)], lltype.Signed)
  222. def g(n):
  223. abc.foobar = n
  224. return n + 1
  225. def f(x):
  226. return z(g)
  227. t, wa = self.translate(f, [int])
  228. fgraph = graphof(t, f)
  229. backend_optimizations(t)
  230. assert fgraph.startblock.operations[0].opname == 'direct_call'
  231. result = wa.analyze(fgraph.startblock.operations[0])
  232. assert len(result) == 1
  233. (struct, T, name), = result
  234. assert struct == "struct"
  235. assert name.endswith("foobar")
  236. class TestLLtypeReadWriteAnalyze(BaseTest):
  237. Analyzer = ReadWriteAnalyzer
  238. def test_read_simple(self):
  239. def g(x):
  240. return True
  241. def f(x):
  242. return g(x - 1)
  243. t, wa = self.translate(f, [int])
  244. fgraph = graphof(t, f)
  245. result = wa.analyze(fgraph.startblock.operations[0])
  246. assert not result
  247. def test_read_really(self):
  248. class A(object):
  249. def __init__(self, y):
  250. self.y = y
  251. def f(self):
  252. self.x = 1
  253. return self.y
  254. def h(flag):
  255. obj = A(flag)
  256. return obj.f()
  257. t, wa = self.translate(h, [int])
  258. hgraph = graphof(t, h)
  259. op_call_f = hgraph.startblock.operations[-1]
  260. # check that we fished the expected ops
  261. assert op_call_f.opname == "direct_call"
  262. assert op_call_f.args[0].value._obj._name == 'A.f'
  263. result = wa.analyze(op_call_f)
  264. assert len(result) == 2
  265. result = list(result)
  266. result.sort()
  267. [(struct1, T1, name1), (struct2, T2, name2)] = result
  268. assert struct1 == "readstruct"
  269. assert name1.endswith("y")
  270. assert struct2 == "struct"
  271. assert name2.endswith("x")
  272. assert T1 == T2
  273. def test_cutoff(self):
  274. py.test.skip("cutoff: disabled")
  275. from rpython.rlib.unroll import unrolling_iterable
  276. cutoff = 20
  277. attrs = unrolling_iterable(["s%s" % i for i in range(cutoff + 5)])
  278. class A(object):
  279. def __init__(self, y):
  280. for attr in attrs:
  281. setattr(self, attr, y)
  282. def f(self):
  283. self.x = 1
  284. res = 0
  285. for attr in attrs:
  286. res += getattr(self, attr)
  287. return res
  288. def h(flag):
  289. obj = A(flag)
  290. return obj.f()
  291. t, wa = self.translate(h, [int])
  292. wa.cutoff = cutoff
  293. hgraph = graphof(t, h)
  294. op_call_f = hgraph.startblock.operations[-1]
  295. # check that we fished the expected ops
  296. assert op_call_f.opname == "direct_call"
  297. assert op_call_f.args[0].value._obj._name == 'A.f'
  298. result = wa.analyze(op_call_f)
  299. assert result is top_set
  300. def test_contains(self):
  301. def g(x, y, z):
  302. l = [x]
  303. return f(l, y, z)
  304. def f(x, y, z):
  305. return y in x
  306. t, wa = self.translate(g, [int, int, int])
  307. ggraph = graphof(t, g)
  308. assert ggraph.startblock.operations[-1].opname == 'direct_call'
  309. result = wa.analyze(ggraph.startblock.operations[-1])
  310. ARRAYPTR = list(result)[0][1]
  311. assert list(result) == [("readarray", ARRAYPTR)]
  312. assert isinstance(ARRAYPTR.TO, lltype.GcArray)
  313. def test_adt_method(self):
  314. def ll_callme(n):
  315. return n
  316. ll_callme = lltype.staticAdtMethod(ll_callme)
  317. S = lltype.GcStruct('S', ('x', lltype.Signed),
  318. adtmeths = {'yep': True,
  319. 'callme': ll_callme})
  320. def g(p, x, y, z):
  321. p.x = x
  322. if p.yep:
  323. z *= p.callme(y)
  324. return z
  325. def f(x, y, z):
  326. p = lltype.malloc(S)
  327. return g(p, x, y, z)
  328. t, wa = self.translate(f, [int, int, int])
  329. fgraph = graphof(t, f)
  330. assert fgraph.startblock.operations[-1].opname == 'direct_call'
  331. result = wa.analyze(fgraph.startblock.operations[-1])
  332. assert list(result) == [("struct", lltype.Ptr(S), "x")]
  333. def test_interiorfield(self):
  334. A = lltype.GcArray(lltype.Struct('x', ('x', lltype.Signed),
  335. ('y', lltype.Signed)))
  336. def g(x):
  337. a = lltype.malloc(A, 1)
  338. a[0].y = 3
  339. return f(a, x)
  340. def f(a, x):
  341. a[0].x = x
  342. return a[0].y
  343. t, wa = self.translate(g, [int])
  344. ggraph = graphof(t, g)
  345. result = wa.analyze(ggraph.startblock.operations[-1])
  346. res = list(result)
  347. assert ('readinteriorfield', lltype.Ptr(A), 'y') in res
  348. assert ('interiorfield', lltype.Ptr(A), 'x') in res