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

/rpython/jit/backend/test/calling_convention_test.py

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