PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/jit/backend/test/calling_convention_test.py

https://bitbucket.org/pypy/pypy/
Python | 354 lines | 323 code | 31 blank | 0 comment | 21 complexity | 229a4b880a18c93030e62e57d2186a9b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.jit.metainterp.history import (AbstractFailDescr,
  2. AbstractDescr,
  3. BasicFailDescr,
  4. BoxInt, Box, BoxPtr,
  5. JitCellToken,
  6. ConstInt, ConstPtr,
  7. BoxObj, Const,
  8. ConstObj, BoxFloat, ConstFloat)
  9. from pypy.jit.metainterp.resoperation import ResOperation, rop
  10. from pypy.jit.metainterp.typesystem import deref
  11. from pypy.jit.codewriter.effectinfo import EffectInfo
  12. from pypy.jit.tool.oparser import parse
  13. from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi, rclass
  14. from pypy.rpython.ootypesystem import ootype
  15. from pypy.rpython.annlowlevel import llhelper
  16. from pypy.rpython.llinterp import LLException
  17. from pypy.jit.codewriter import heaptracker, longlong
  18. from pypy.rlib.rarithmetic import intmask
  19. from pypy.jit.backend.detect_cpu import getcpuclass
  20. from pypy.jit.backend.test.runner_test import Runner
  21. def boxfloat(x):
  22. return BoxFloat(longlong.getfloatstorage(x))
  23. def constfloat(x):
  24. return ConstFloat(longlong.getfloatstorage(x))
  25. class FakeStats(object):
  26. pass
  27. class TestCallingConv(Runner):
  28. type_system = 'lltype'
  29. Ptr = lltype.Ptr
  30. FuncType = lltype.FuncType
  31. def setup_class(cls):
  32. cls.cpu = getcpuclass()(rtyper=None, stats=FakeStats())
  33. cls.cpu.setup_once()
  34. def _prepare_args(self, args, floats, ints):
  35. local_floats = list(floats)
  36. local_ints = list(ints)
  37. expected_result = 0.0
  38. arguments = []
  39. for i in range(len(args)):
  40. x = args[i]
  41. if x[0] == 'f':
  42. x = local_floats.pop()
  43. t = longlong.getfloatstorage(x)
  44. arguments.append(t)
  45. else:
  46. x = local_ints.pop()
  47. arguments.append(x)
  48. expected_result += x
  49. return arguments, expected_result
  50. @classmethod
  51. def get_funcbox(cls, cpu, func_ptr):
  52. addr = llmemory.cast_ptr_to_adr(func_ptr)
  53. return ConstInt(heaptracker.adr2int(addr))
  54. def test_call_aligned_with_spilled_values(self):
  55. from pypy.rlib.libffi import types
  56. cpu = self.cpu
  57. if not cpu.supports_floats:
  58. py.test.skip('requires floats')
  59. def func(*args):
  60. return float(sum(args))
  61. F = lltype.Float
  62. I = lltype.Signed
  63. floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
  64. ints = [7, 11, 23, 13, -42, 1111, 95, 1]
  65. for case in range(256):
  66. local_floats = list(floats)
  67. local_ints = list(ints)
  68. args = []
  69. spills = []
  70. funcargs = []
  71. float_count = 0
  72. int_count = 0
  73. for i in range(8):
  74. if case & (1<<i):
  75. args.append('f%d' % float_count)
  76. spills.append('force_spill(f%d)' % float_count)
  77. float_count += 1
  78. funcargs.append(F)
  79. else:
  80. args.append('i%d' % int_count)
  81. spills.append('force_spill(i%d)' % int_count)
  82. int_count += 1
  83. funcargs.append(I)
  84. arguments = ', '.join(args)
  85. spill_ops = '\n'.join(spills)
  86. FUNC = self.FuncType(funcargs, F)
  87. FPTR = self.Ptr(FUNC)
  88. func_ptr = llhelper(FPTR, func)
  89. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  90. EffectInfo.MOST_GENERAL)
  91. funcbox = self.get_funcbox(cpu, func_ptr)
  92. ops = '[%s]\n' % arguments
  93. ops += '%s\n' % spill_ops
  94. ops += 'f99 = call(ConstClass(func_ptr), %s, descr=calldescr)\n' % arguments
  95. ops += 'finish(f99, %s)\n' % arguments
  96. loop = parse(ops, namespace=locals())
  97. looptoken = JitCellToken()
  98. done_number = self.cpu.get_fail_descr_number(loop.operations[-1].getdescr())
  99. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  100. argvals, expected_result = self._prepare_args(args, floats, ints)
  101. res = self.cpu.execute_token(looptoken, *argvals)
  102. x = longlong.getrealfloat(cpu.get_latest_value_float(0))
  103. assert abs(x - expected_result) < 0.0001
  104. def test_call_aligned_with_imm_values(self):
  105. from pypy.rlib.libffi import types
  106. cpu = self.cpu
  107. if not cpu.supports_floats:
  108. py.test.skip('requires floats')
  109. def func(*args):
  110. return float(sum(args))
  111. F = lltype.Float
  112. I = lltype.Signed
  113. floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
  114. ints = [7, 11, 23, 13, -42, 1111, 95, 1]
  115. for case in range(256):
  116. result = 0.0
  117. args = []
  118. argslist = []
  119. local_floats = list(floats)
  120. local_ints = list(ints)
  121. for i in range(8):
  122. if case & (1<<i):
  123. args.append(F)
  124. arg = local_floats.pop()
  125. result += arg
  126. argslist.append(constfloat(arg))
  127. else:
  128. args.append(I)
  129. arg = local_ints.pop()
  130. result += arg
  131. argslist.append(ConstInt(arg))
  132. FUNC = self.FuncType(args, F)
  133. FPTR = self.Ptr(FUNC)
  134. func_ptr = llhelper(FPTR, func)
  135. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  136. EffectInfo.MOST_GENERAL)
  137. funcbox = self.get_funcbox(cpu, func_ptr)
  138. res = self.execute_operation(rop.CALL,
  139. [funcbox] + argslist,
  140. 'float', descr=calldescr)
  141. assert abs(res.getfloat() - result) < 0.0001
  142. def test_call_aligned_with_args_on_the_stack(self):
  143. from pypy.rlib.libffi import types
  144. cpu = self.cpu
  145. if not cpu.supports_floats:
  146. py.test.skip('requires floats')
  147. def func(*args):
  148. return float(sum(args))
  149. F = lltype.Float
  150. I = lltype.Signed
  151. floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
  152. ints = [7, 11, 23, 13, -42, 1111, 95, 1]
  153. for case in range(256):
  154. result = 0.0
  155. args = []
  156. argslist = []
  157. local_floats = list(floats)
  158. local_ints = list(ints)
  159. for i in range(8):
  160. if case & (1<<i):
  161. args.append(F)
  162. arg = local_floats.pop()
  163. result += arg
  164. argslist.append(boxfloat(arg))
  165. else:
  166. args.append(I)
  167. arg = local_ints.pop()
  168. result += arg
  169. argslist.append(BoxInt(arg))
  170. FUNC = self.FuncType(args, F)
  171. FPTR = self.Ptr(FUNC)
  172. func_ptr = llhelper(FPTR, func)
  173. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  174. EffectInfo.MOST_GENERAL)
  175. funcbox = self.get_funcbox(cpu, func_ptr)
  176. res = self.execute_operation(rop.CALL,
  177. [funcbox] + argslist,
  178. 'float', descr=calldescr)
  179. assert abs(res.getfloat() - result) < 0.0001
  180. def test_call_alignment_call_assembler(self):
  181. from pypy.rlib.libffi import types
  182. cpu = self.cpu
  183. if not cpu.supports_floats:
  184. py.test.skip('requires floats')
  185. fdescr3 = BasicFailDescr(3)
  186. fdescr4 = BasicFailDescr(4)
  187. def assembler_helper(failindex, virtualizable):
  188. assert 0, 'should not be called, but was with failindex (%d)' % failindex
  189. return 13
  190. FUNCPTR = lltype.Ptr(lltype.FuncType([lltype.Signed, llmemory.GCREF],
  191. lltype.Signed))
  192. class FakeJitDriverSD:
  193. index_of_virtualizable = -1
  194. _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
  195. assembler_helper_adr = llmemory.cast_ptr_to_adr(
  196. _assembler_helper_ptr)
  197. floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
  198. ints = [7, 11, 23, 42, -42, 1111, 95, 1]
  199. for case in range(256):
  200. float_count = 0
  201. int_count = 0
  202. args = []
  203. called_ops = ''
  204. total_index = -1
  205. for i in range(8):
  206. if case & (1<<i):
  207. args.append('f%d' % float_count)
  208. else:
  209. args.append('i%d' % int_count)
  210. called_ops += 'f%d = cast_int_to_float(i%d)\n' % (
  211. float_count, int_count)
  212. int_count += 1
  213. if total_index == -1:
  214. total_index = float_count
  215. float_count += 1
  216. else:
  217. called_ops += 'f%d = float_add(f%d, f%d)\n' % (
  218. float_count + 1, total_index, float_count)
  219. total_index = float_count + 1
  220. float_count += 2
  221. arguments = ', '.join(args)
  222. called_ops = '[%s]\n' % arguments + called_ops
  223. called_ops += 'finish(f%d, descr=fdescr3)\n' % total_index
  224. # compile called loop
  225. called_loop = parse(called_ops, namespace=locals())
  226. called_looptoken = JitCellToken()
  227. called_looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
  228. done_number = self.cpu.get_fail_descr_number(called_loop.operations[-1].getdescr())
  229. self.cpu.compile_loop(called_loop.inputargs, called_loop.operations, called_looptoken)
  230. argvals, expected_result = self._prepare_args(args, floats, ints)
  231. res = cpu.execute_token(called_looptoken, *argvals)
  232. assert res.identifier == 3
  233. t = longlong.getrealfloat(cpu.get_latest_value_float(0))
  234. assert abs(t - expected_result) < 0.0001
  235. ARGS = []
  236. RES = lltype.Float
  237. for x in args:
  238. if x[0] == 'f':
  239. ARGS.append(lltype.Float)
  240. else:
  241. ARGS.append(lltype.Signed)
  242. FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
  243. lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
  244. EffectInfo.MOST_GENERAL)
  245. ops = '''
  246. [%s]
  247. f99 = call_assembler(%s, descr=called_looptoken)
  248. guard_not_forced()[]
  249. finish(f99, descr=fdescr4)
  250. ''' % (arguments, arguments)
  251. loop = parse(ops, namespace=locals())
  252. # we want to take the fast path
  253. self.cpu.done_with_this_frame_float_v = done_number
  254. try:
  255. othertoken = JitCellToken()
  256. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  257. # prepare call to called_loop
  258. argvals, _ = self._prepare_args(args, floats, ints)
  259. res = cpu.execute_token(othertoken, *argvals)
  260. x = longlong.getrealfloat(cpu.get_latest_value_float(0))
  261. assert res.identifier == 4
  262. assert abs(x - expected_result) < 0.0001
  263. finally:
  264. del self.cpu.done_with_this_frame_float_v
  265. def test_call_with_singlefloats(self):
  266. cpu = self.cpu
  267. if not cpu.supports_floats or not cpu.supports_singlefloats:
  268. py.test.skip('requires floats and singlefloats')
  269. import random
  270. from pypy.rlib.libffi import types
  271. from pypy.rlib.rarithmetic import r_singlefloat
  272. def func(*args):
  273. res = 0.0
  274. for i, x in enumerate(args):
  275. res += (i + 1.1) * float(x)
  276. return res
  277. F = lltype.Float
  278. S = lltype.SingleFloat
  279. I = lltype.Signed
  280. floats = [random.random() - 0.5 for i in range(8)]
  281. singlefloats = [r_singlefloat(random.random() - 0.5) for i in range(8)]
  282. ints = [random.randrange(-99, 99) for i in range(8)]
  283. for repeat in range(100):
  284. args = []
  285. argvalues = []
  286. argslist = []
  287. local_floats = list(floats)
  288. local_singlefloats = list(singlefloats)
  289. local_ints = list(ints)
  290. for i in range(8):
  291. case = random.randrange(0, 3)
  292. if case == 0:
  293. args.append(F)
  294. arg = local_floats.pop()
  295. argslist.append(boxfloat(arg))
  296. elif case == 1:
  297. args.append(S)
  298. arg = local_singlefloats.pop()
  299. argslist.append(BoxInt(longlong.singlefloat2int(arg)))
  300. else:
  301. args.append(I)
  302. arg = local_ints.pop()
  303. argslist.append(BoxInt(arg))
  304. argvalues.append(arg)
  305. FUNC = self.FuncType(args, F)
  306. FPTR = self.Ptr(FUNC)
  307. func_ptr = llhelper(FPTR, func)
  308. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  309. EffectInfo.MOST_GENERAL)
  310. funcbox = self.get_funcbox(cpu, func_ptr)
  311. res = self.execute_operation(rop.CALL,
  312. [funcbox] + argslist,
  313. 'float', descr=calldescr)
  314. expected = func(*argvalues)
  315. assert abs(res.getfloat() - expected) < 0.0001