PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/translator/backendopt/test/test_all.py

https://bitbucket.org/pypy/pypy/
Python | 291 lines | 285 code | 5 blank | 1 comment | 7 complexity | a80155e5c1c6b04414d68a03e11c7915 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from rpython.translator.backendopt.all import backend_optimizations
  3. from rpython.translator.backendopt.all import INLINE_THRESHOLD_FOR_TEST
  4. from rpython.translator.backendopt.support import md5digest
  5. from rpython.translator.backendopt.test.test_malloc import TestMallocRemoval as MallocRemovalTest
  6. from rpython.translator.translator import TranslationContext, graphof
  7. from rpython.flowspace.model import Constant, summary
  8. from rpython.rtyper.llinterp import LLInterpreter
  9. from rpython.rlib.rarithmetic import intmask
  10. from rpython.conftest import option
  11. class A:
  12. def __init__(self, x, y):
  13. self.bounds = (x, y)
  14. def mean(self, percentage=50):
  15. x, y = self.bounds
  16. total = x*percentage + y*(100-percentage)
  17. return total//100
  18. def condition(n):
  19. return n >= 100
  20. def firstthat(function, condition):
  21. for n in range(101):
  22. if condition(function(n)):
  23. return n
  24. else:
  25. return -1
  26. def myfunction(n):
  27. a = A(117, n)
  28. return a.mean()
  29. def big():
  30. """This example should be turned into a simple 'while' loop with no
  31. malloc nor direct_call by back-end optimizations, given a high enough
  32. inlining threshold.
  33. """
  34. return firstthat(myfunction, condition)
  35. LARGE_THRESHOLD = 10*INLINE_THRESHOLD_FOR_TEST
  36. HUGE_THRESHOLD = 100*INLINE_THRESHOLD_FOR_TEST
  37. class TestLLType(object):
  38. check_malloc_removed = MallocRemovalTest.check_malloc_removed
  39. def translateopt(self, func, sig, **optflags):
  40. t = TranslationContext()
  41. opts = {'translation.list_comprehension_operations': True}
  42. t.config.set(**opts)
  43. t.buildannotator().build_types(func, sig)
  44. t.buildrtyper().specialize()
  45. if option.view:
  46. t.view()
  47. backend_optimizations(t, **optflags)
  48. if option.view:
  49. t.view()
  50. return t
  51. def test_big(self):
  52. assert big() == 83
  53. t = self.translateopt(big, [], inline_threshold=HUGE_THRESHOLD,
  54. mallocs=True)
  55. big_graph = graphof(t, big)
  56. self.check_malloc_removed(big_graph)
  57. interp = LLInterpreter(t.rtyper)
  58. res = interp.eval_graph(big_graph, [])
  59. assert res == 83
  60. def test_for_loop(self):
  61. def f(n):
  62. total = 0
  63. for i in range(n):
  64. total += i
  65. return total
  66. t = self.translateopt(f, [int], mallocs=True)
  67. # this also checks that the BASE_INLINE_THRESHOLD is enough
  68. # for 'for' loops
  69. f_graph = graph = graphof(t, f)
  70. self.check_malloc_removed(f_graph)
  71. interp = LLInterpreter(t.rtyper)
  72. res = interp.eval_graph(f_graph, [11])
  73. assert res == 55
  74. def test_premature_death(self):
  75. import os
  76. from rpython.annotator.listdef import s_list_of_strings
  77. inputtypes = [s_list_of_strings]
  78. def debug(msg):
  79. os.write(2, "debug: " + msg + '\n')
  80. def entry_point(argv):
  81. #debug("entry point starting")
  82. for arg in argv:
  83. #debug(" argv -> " + arg)
  84. r = arg.replace('_', '-')
  85. #debug(' replaced -> ' + r)
  86. a = r.lower()
  87. #debug(" lowered -> " + a)
  88. return 0
  89. t = self.translateopt(entry_point, inputtypes, mallocs=True)
  90. entry_point_graph = graphof(t, entry_point)
  91. argv = t.rtyper.getrepr(inputtypes[0]).convert_const(['./pypy-c'])
  92. interp = LLInterpreter(t.rtyper)
  93. interp.eval_graph(entry_point_graph, [argv])
  94. def test_idempotent(self):
  95. def s(x):
  96. res = 0
  97. i = 1
  98. while i <= x:
  99. res += i
  100. i += 1
  101. return res
  102. def g(x):
  103. return s(100) + s(1) + x
  104. def idempotent(n1, n2):
  105. c = [i for i in range(n2)]
  106. return 33 + big() + g(10)
  107. t = self.translateopt(idempotent, [int, int],
  108. constfold=False)
  109. #backend_optimizations(t, inline_threshold=0, constfold=False)
  110. digest1 = md5digest(t)
  111. digest2 = md5digest(t)
  112. def compare(digest1, digest2):
  113. diffs = []
  114. assert digest1.keys() == digest2.keys()
  115. for name in digest1:
  116. if digest1[name] != digest2[name]:
  117. diffs.append(name)
  118. assert not diffs
  119. compare(digest1, digest2)
  120. #XXX Inlining and constfold are currently non-idempotent.
  121. # Maybe they just renames variables but the graph changes in some way.
  122. backend_optimizations(t, inline_threshold=0, constfold=False)
  123. digest3 = md5digest(t)
  124. compare(digest1, digest3)
  125. def test_bug_inlined_if(self):
  126. def f(x, flag):
  127. if flag:
  128. y = x
  129. else:
  130. y = x+1
  131. return y*5
  132. def myfunc(x):
  133. return f(x, False) - f(x, True)
  134. assert myfunc(10) == 5
  135. t = self.translateopt(myfunc, [int], inline_threshold=HUGE_THRESHOLD)
  136. interp = LLInterpreter(t.rtyper)
  137. res = interp.eval_graph(graphof(t, myfunc), [10])
  138. assert res == 5
  139. def test_range_iter(self):
  140. def fn(start, stop, step):
  141. res = 0
  142. if step == 0:
  143. if stop >= start:
  144. r = range(start, stop, 1)
  145. else:
  146. r = range(start, stop, -1)
  147. else:
  148. r = range(start, stop, step)
  149. for i in r:
  150. res = res * 51 + i
  151. return res
  152. t = self.translateopt(fn, [int, int, int], merge_if_blocks=True)
  153. interp = LLInterpreter(t.rtyper)
  154. for args in [2, 7, 0], [7, 2, 0], [10, 50, 7], [50, -10, -3]:
  155. assert interp.eval_graph(graphof(t, fn), args) == intmask(fn(*args))
  156. def test_constant_diffuse(self):
  157. def g(x,y):
  158. if x < 0:
  159. return 0
  160. return x + y
  161. def f(x):
  162. return g(x,7)+g(x,11)
  163. t = self.translateopt(f, [int])
  164. fgraph = graphof(t, f)
  165. for link in fgraph.iterlinks():
  166. assert Constant(7) not in link.args
  167. assert Constant(11) not in link.args
  168. def test_isinstance(self):
  169. class A:
  170. pass
  171. class B(A):
  172. pass
  173. def g(n):
  174. if n > 10:
  175. return A()
  176. else:
  177. b = B()
  178. b.value = 321
  179. return b
  180. def fn(n):
  181. x = g(n)
  182. assert isinstance(x, B)
  183. return x.value
  184. t = self.translateopt(fn, [int], really_remove_asserts=True,
  185. remove_asserts=True)
  186. graph = graphof(t, fn)
  187. assert "direct_call" not in summary(graph)
  188. def test_list_comp(self):
  189. def f(n1, n2):
  190. c = [i for i in range(n2)]
  191. return 33
  192. t = self.translateopt(f, [int, int], inline_threshold=LARGE_THRESHOLD,
  193. mallocs=True)
  194. f_graph = graphof(t, f)
  195. self.check_malloc_removed(f_graph)
  196. interp = LLInterpreter(t.rtyper)
  197. res = interp.eval_graph(f_graph, [11, 22])
  198. assert res == 33
  199. def test_secondary_backendopt(self):
  200. # checks an issue with a newly added graph that calls an
  201. # already-exception-transformed graph. This can occur e.g.
  202. # from a late-seen destructor added by the GC transformer
  203. # which ends up calling existing code.
  204. def common(n):
  205. if n > 5:
  206. raise ValueError
  207. def main(n):
  208. common(n)
  209. def later(n):
  210. try:
  211. common(n)
  212. return 0
  213. except ValueError:
  214. return 1
  215. t = TranslationContext()
  216. t.buildannotator().build_types(main, [int])
  217. t.buildrtyper().specialize()
  218. exctransformer = t.getexceptiontransformer()
  219. exctransformer.create_exception_handling(graphof(t, common))
  220. from rpython.annotator import model as annmodel
  221. from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
  222. annhelper = MixLevelHelperAnnotator(t.rtyper)
  223. later_graph = annhelper.getgraph(later, [annmodel.SomeInteger()],
  224. annmodel.SomeInteger())
  225. annhelper.finish()
  226. annhelper.backend_optimize()
  227. # ^^^ as the inliner can't handle exception-transformed graphs,
  228. # this should *not* inline common() into later().
  229. if option.view:
  230. later_graph.show()
  231. common_graph = graphof(t, common)
  232. found = False
  233. for block in later_graph.iterblocks():
  234. for op in block.operations:
  235. if (op.opname == 'direct_call' and
  236. op.args[0].value._obj.graph is common_graph):
  237. found = True
  238. assert found, "cannot find the call (buggily inlined?)"
  239. from rpython.rtyper.llinterp import LLInterpreter
  240. llinterp = LLInterpreter(t.rtyper)
  241. res = llinterp.eval_graph(later_graph, [10])
  242. assert res == 1