PageRenderTime 70ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/jit/codewriter/test/test_jtransform.py

https://bitbucket.org/pypy/pypy/
Python | 1220 lines | 1103 code | 78 blank | 39 comment | 69 complexity | 5f10b67e397876afd067cc223f2e4790 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import random
  3. try:
  4. from itertools import product
  5. except ImportError:
  6. # Python 2.5, this is taken from the CPython docs, but simplified.
  7. def product(*args):
  8. # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
  9. # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
  10. pools = map(tuple, args)
  11. result = [[]]
  12. for pool in pools:
  13. result = [x+[y] for x in result for y in pool]
  14. for prod in result:
  15. yield tuple(prod)
  16. from pypy.objspace.flow.model import FunctionGraph, Block, Link
  17. from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
  18. from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rffi
  19. from pypy.rpython.lltypesystem.module import ll_math
  20. from pypy.translator.unsimplify import varoftype
  21. from pypy.jit.codewriter import heaptracker, effectinfo
  22. from pypy.jit.codewriter.flatten import ListOfKind
  23. from pypy.jit.codewriter.jtransform import Transformer, UnsupportedMallocFlags
  24. from pypy.jit.metainterp.history import getkind
  25. def const(x):
  26. return Constant(x, lltype.typeOf(x))
  27. class FakeRTyper:
  28. class type_system: name = 'lltypesystem'
  29. instance_reprs = {}
  30. class FakeCPU:
  31. rtyper = FakeRTyper()
  32. def calldescrof(self, FUNC, ARGS, RESULT):
  33. return ('calldescr', FUNC, ARGS, RESULT)
  34. def fielddescrof(self, STRUCT, name):
  35. return ('fielddescr', STRUCT, name)
  36. def interiorfielddescrof(self, ARRAY, name):
  37. return ('interiorfielddescr', ARRAY, name)
  38. def arraydescrof(self, ARRAY):
  39. return FakeDescr(('arraydescr', ARRAY))
  40. def sizeof(self, STRUCT):
  41. return FakeDescr(('sizedescr', STRUCT))
  42. class FakeDescr(tuple):
  43. def as_vtable_size_descr(self):
  44. return self
  45. class FakeLink:
  46. args = []
  47. def __init__(self, exitcase):
  48. self.exitcase = self.llexitcase = exitcase
  49. class FakeResidualCallControl:
  50. def guess_call_kind(self, op):
  51. return 'residual'
  52. def getcalldescr(self, op):
  53. return 'calldescr'
  54. def calldescr_canraise(self, calldescr):
  55. return True
  56. class FakeRegularCallControl:
  57. def guess_call_kind(self, op):
  58. return 'regular'
  59. def graphs_from(self, op):
  60. return ['somegraph']
  61. def get_jitcode(self, graph, called_from=None):
  62. assert graph == 'somegraph'
  63. return 'somejitcode'
  64. class FakeResidualIndirectCallControl:
  65. def guess_call_kind(self, op):
  66. return 'residual'
  67. def getcalldescr(self, op):
  68. return 'calldescr'
  69. def calldescr_canraise(self, calldescr):
  70. return True
  71. class FakeRegularIndirectCallControl:
  72. def guess_call_kind(self, op):
  73. return 'regular'
  74. def graphs_from(self, op):
  75. return ['somegraph1', 'somegraph2']
  76. def getcalldescr(self, op):
  77. return 'calldescr'
  78. def get_jitcode(self, graph, called_from=None):
  79. assert graph in ('somegraph1', 'somegraph2')
  80. return 'somejitcode' + graph[-1]
  81. def calldescr_canraise(self, calldescr):
  82. return False
  83. class FakeCallInfoCollection:
  84. def __init__(self):
  85. self.seen = []
  86. def add(self, oopspecindex, calldescr, func):
  87. self.seen.append((oopspecindex, calldescr, func))
  88. def has_oopspec(self, oopspecindex):
  89. for i, c, f in self.seen:
  90. if i == oopspecindex:
  91. return True
  92. return False
  93. def callinfo_for_oopspec(self, oopspecindex):
  94. assert oopspecindex == effectinfo.EffectInfo.OS_STREQ_NONNULL
  95. class c:
  96. class adr:
  97. ptr = 1
  98. return ('calldescr', c)
  99. class FakeBuiltinCallControl:
  100. def __init__(self):
  101. self.callinfocollection = FakeCallInfoCollection()
  102. def guess_call_kind(self, op):
  103. return 'builtin'
  104. def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
  105. assert oopspecindex is not None # in this test
  106. EI = effectinfo.EffectInfo
  107. if oopspecindex != EI.OS_ARRAYCOPY:
  108. PSTR = lltype.Ptr(rstr.STR)
  109. PUNICODE = lltype.Ptr(rstr.UNICODE)
  110. INT = lltype.Signed
  111. UNICHAR = lltype.UniChar
  112. FLOAT = lltype.Float
  113. argtypes = {
  114. EI.OS_MATH_SQRT: ([FLOAT], FLOAT),
  115. EI.OS_STR2UNICODE:([PSTR], PUNICODE),
  116. EI.OS_STR_CONCAT: ([PSTR, PSTR], PSTR),
  117. EI.OS_STR_SLICE: ([PSTR, INT, INT], PSTR),
  118. EI.OS_STREQ_NONNULL: ([PSTR, PSTR], INT),
  119. EI.OS_UNI_CONCAT: ([PUNICODE, PUNICODE], PUNICODE),
  120. EI.OS_UNI_SLICE: ([PUNICODE, INT, INT], PUNICODE),
  121. EI.OS_UNI_EQUAL: ([PUNICODE, PUNICODE], lltype.Bool),
  122. EI.OS_UNIEQ_SLICE_CHECKNULL:([PUNICODE, INT, INT, PUNICODE], INT),
  123. EI.OS_UNIEQ_SLICE_NONNULL: ([PUNICODE, INT, INT, PUNICODE], INT),
  124. EI.OS_UNIEQ_SLICE_CHAR: ([PUNICODE, INT, INT, UNICHAR], INT),
  125. EI.OS_UNIEQ_NONNULL: ([PUNICODE, PUNICODE], INT),
  126. EI.OS_UNIEQ_NONNULL_CHAR: ([PUNICODE, UNICHAR], INT),
  127. EI.OS_UNIEQ_CHECKNULL_CHAR: ([PUNICODE, UNICHAR], INT),
  128. EI.OS_UNIEQ_LENGTHOK: ([PUNICODE, PUNICODE], INT),
  129. }
  130. argtypes = argtypes[oopspecindex]
  131. assert argtypes[0] == [v.concretetype for v in op.args[1:]]
  132. assert argtypes[1] == op.result.concretetype
  133. if oopspecindex == EI.OS_STR2UNICODE:
  134. assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE
  135. else:
  136. assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE
  137. return 'calldescr-%d' % oopspecindex
  138. def calldescr_canraise(self, calldescr):
  139. return False
  140. def test_optimize_goto_if_not():
  141. v1 = Variable()
  142. v2 = Variable()
  143. v3 = Variable(); v3.concretetype = lltype.Bool
  144. sp1 = SpaceOperation('foobar', [], None)
  145. sp2 = SpaceOperation('foobaz', [], None)
  146. block = Block([v1, v2])
  147. block.operations = [sp1, SpaceOperation('int_gt', [v1, v2], v3), sp2]
  148. block.exitswitch = v3
  149. block.exits = exits = [FakeLink(False), FakeLink(True)]
  150. res = Transformer().optimize_goto_if_not(block)
  151. assert res == True
  152. assert block.operations == [sp1, sp2]
  153. assert block.exitswitch == ('int_gt', v1, v2)
  154. assert block.exits == exits
  155. def test_optimize_goto_if_not__incoming():
  156. v1 = Variable(); v1.concretetype = lltype.Bool
  157. block = Block([v1])
  158. block.exitswitch = v1
  159. block.exits = [FakeLink(False), FakeLink(True)]
  160. assert not Transformer().optimize_goto_if_not(block)
  161. def test_optimize_goto_if_not__exit():
  162. # this case occurs in practice, e.g. with RPython code like:
  163. # return bool(p) and p.somefield > 0
  164. v1 = Variable()
  165. v2 = Variable()
  166. v3 = Variable(); v3.concretetype = lltype.Bool
  167. block = Block([v1, v2])
  168. block.operations = [SpaceOperation('int_gt', [v1, v2], v3)]
  169. block.exitswitch = v3
  170. block.exits = exits = [FakeLink(False), FakeLink(True)]
  171. block.exits[1].args = [v3]
  172. res = Transformer().optimize_goto_if_not(block)
  173. assert res == True
  174. assert block.operations == []
  175. assert block.exitswitch == ('int_gt', v1, v2)
  176. assert block.exits == exits
  177. assert exits[1].args == [const(True)]
  178. def test_optimize_goto_if_not__unknownop():
  179. v3 = Variable(); v3.concretetype = lltype.Bool
  180. block = Block([])
  181. block.operations = [SpaceOperation('foobar', [], v3)]
  182. block.exitswitch = v3
  183. block.exits = [FakeLink(False), FakeLink(True)]
  184. assert not Transformer().optimize_goto_if_not(block)
  185. def test_optimize_goto_if_not__ptr_eq():
  186. for opname in ['ptr_eq', 'ptr_ne']:
  187. v1 = Variable()
  188. v2 = Variable()
  189. v3 = Variable(); v3.concretetype = lltype.Bool
  190. block = Block([v1, v2])
  191. block.operations = [SpaceOperation(opname, [v1, v2], v3)]
  192. block.exitswitch = v3
  193. block.exits = exits = [FakeLink(False), FakeLink(True)]
  194. res = Transformer().optimize_goto_if_not(block)
  195. assert res == True
  196. assert block.operations == []
  197. assert block.exitswitch == (opname, v1, v2)
  198. assert block.exits == exits
  199. def test_optimize_goto_if_not__ptr_iszero():
  200. for opname in ['ptr_iszero', 'ptr_nonzero']:
  201. v1 = Variable()
  202. v3 = Variable(); v3.concretetype = lltype.Bool
  203. block = Block([v1])
  204. block.operations = [SpaceOperation(opname, [v1], v3)]
  205. block.exitswitch = v3
  206. block.exits = exits = [FakeLink(False), FakeLink(True)]
  207. res = Transformer().optimize_goto_if_not(block)
  208. assert res == True
  209. assert block.operations == []
  210. assert block.exitswitch == (opname, v1, '-live-before')
  211. assert block.exits == exits
  212. def test_symmetric():
  213. ops = {'int_add': 'int_add',
  214. 'int_or': 'int_or',
  215. 'int_gt': ('int_gt', 'int_lt'),
  216. 'uint_eq': 'int_eq',
  217. 'uint_le': ('uint_le', 'uint_ge'),
  218. 'char_ne': 'int_ne',
  219. 'char_lt': ('int_lt', 'int_gt'),
  220. 'uint_xor': 'int_xor',
  221. 'float_mul': 'float_mul',
  222. 'float_gt': ('float_gt', 'float_lt'),
  223. }
  224. v3 = varoftype(lltype.Signed)
  225. for v1 in [varoftype(lltype.Signed), const(42)]:
  226. for v2 in [varoftype(lltype.Signed), const(43)]:
  227. for name1, name2 in ops.items():
  228. op = SpaceOperation(name1, [v1, v2], v3)
  229. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  230. if isinstance(name2, str):
  231. name2 = name2, name2
  232. if isinstance(v1, Constant) and isinstance(v2, Variable):
  233. assert op1.args == [v2, v1]
  234. assert op1.result == v3
  235. assert op1.opname == name2[1]
  236. else:
  237. assert op1.args == [v1, v2]
  238. assert op1.result == v3
  239. assert op1.opname == name2[0]
  240. def test_symmetric_int_add_ovf():
  241. v3 = varoftype(lltype.Signed)
  242. for v1 in [varoftype(lltype.Signed), const(42)]:
  243. for v2 in [varoftype(lltype.Signed), const(43)]:
  244. op = SpaceOperation('int_add_nonneg_ovf', [v1, v2], v3)
  245. oplist = Transformer(FakeCPU()).rewrite_operation(op)
  246. op0, op1 = oplist
  247. assert op0.opname == 'int_add_ovf'
  248. if isinstance(v1, Constant) and isinstance(v2, Variable):
  249. assert op0.args == [v2, v1]
  250. assert op0.result == v3
  251. else:
  252. assert op0.args == [v1, v2]
  253. assert op0.result == v3
  254. assert op1.opname == '-live-'
  255. assert op1.args == []
  256. assert op1.result is None
  257. def test_calls():
  258. for RESTYPE, with_void, with_i, with_r, with_f in product(
  259. [lltype.Signed, rclass.OBJECTPTR, lltype.Float, lltype.Void],
  260. [False, True],
  261. [False, True],
  262. [False, True],
  263. [False, True],
  264. ):
  265. ARGS = []
  266. if with_void:
  267. ARGS += [lltype.Void, lltype.Void]
  268. if with_i:
  269. ARGS += [lltype.Signed, lltype.Char]
  270. if with_r:
  271. ARGS += [rclass.OBJECTPTR, lltype.Ptr(rstr.STR)]
  272. if with_f:
  273. ARGS += [lltype.Float, lltype.Float]
  274. random.shuffle(ARGS)
  275. if RESTYPE == lltype.Float:
  276. with_f = True
  277. if with_f:
  278. expectedkind = 'irf' # all kinds
  279. elif with_i:
  280. expectedkind = 'ir' # integers and references
  281. else:
  282. expectedkind = 'r' # only references
  283. yield residual_call_test, ARGS, RESTYPE, expectedkind
  284. yield direct_call_test, ARGS, RESTYPE, expectedkind
  285. yield indirect_residual_call_test, ARGS, RESTYPE, expectedkind
  286. yield indirect_regular_call_test, ARGS, RESTYPE, expectedkind
  287. def get_direct_call_op(argtypes, restype):
  288. FUNC = lltype.FuncType(argtypes, restype)
  289. fnptr = lltype.functionptr(FUNC, "g") # no graph
  290. c_fnptr = const(fnptr)
  291. vars = [varoftype(TYPE) for TYPE in argtypes]
  292. v_result = varoftype(restype)
  293. op = SpaceOperation('direct_call', [c_fnptr] + vars, v_result)
  294. return op
  295. def residual_call_test(argtypes, restype, expectedkind):
  296. op = get_direct_call_op(argtypes, restype)
  297. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  298. oplist = tr.rewrite_operation(op)
  299. op0, op1 = oplist
  300. reskind = getkind(restype)[0]
  301. assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind)
  302. assert op0.result == op.result
  303. assert op0.args[0] == op.args[0]
  304. assert op0.args[1] == 'calldescr'
  305. assert len(op0.args) == 2 + len(expectedkind)
  306. for sublist, kind1 in zip(op0.args[2:], expectedkind):
  307. assert sublist.kind.startswith(kind1)
  308. assert list(sublist) == [v for v in op.args[1:]
  309. if getkind(v.concretetype) == sublist.kind]
  310. for v in op.args[1:]:
  311. kind = getkind(v.concretetype)
  312. assert kind == 'void' or kind[0] in expectedkind
  313. assert op1.opname == '-live-'
  314. assert op1.args == []
  315. def direct_call_test(argtypes, restype, expectedkind):
  316. op = get_direct_call_op(argtypes, restype)
  317. tr = Transformer(FakeCPU(), FakeRegularCallControl())
  318. tr.graph = 'someinitialgraph'
  319. oplist = tr.rewrite_operation(op)
  320. op0, op1 = oplist
  321. reskind = getkind(restype)[0]
  322. assert op0.opname == 'inline_call_%s_%s' % (expectedkind, reskind)
  323. assert op0.result == op.result
  324. assert op0.args[0] == 'somejitcode'
  325. assert len(op0.args) == 1 + len(expectedkind)
  326. for sublist, kind1 in zip(op0.args[1:], expectedkind):
  327. assert sublist.kind.startswith(kind1)
  328. assert list(sublist) == [v for v in op.args[1:]
  329. if getkind(v.concretetype) == sublist.kind]
  330. for v in op.args[1:]:
  331. kind = getkind(v.concretetype)
  332. assert kind == 'void' or kind[0] in expectedkind
  333. assert op1.opname == '-live-'
  334. assert op1.args == []
  335. def indirect_residual_call_test(argtypes, restype, expectedkind):
  336. # an indirect call that is residual in all cases is very similar to
  337. # a residual direct call
  338. op = get_direct_call_op(argtypes, restype)
  339. op.opname = 'indirect_call'
  340. op.args[0] = varoftype(op.args[0].concretetype)
  341. op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void))
  342. tr = Transformer(FakeCPU(), FakeResidualIndirectCallControl())
  343. tr.graph = 'someinitialgraph'
  344. oplist = tr.rewrite_operation(op)
  345. op0, op1 = oplist
  346. reskind = getkind(restype)[0]
  347. assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind)
  348. assert op0.result == op.result
  349. assert op0.args[0] == op.args[0]
  350. assert op0.args[1] == 'calldescr'
  351. assert len(op0.args) == 2 + len(expectedkind)
  352. for sublist, kind1 in zip(op0.args[2:], expectedkind):
  353. assert sublist.kind.startswith(kind1)
  354. assert list(sublist) == [v for v in op.args[1:]
  355. if getkind(v.concretetype)==sublist.kind]
  356. for v in op.args[1:]:
  357. kind = getkind(v.concretetype)
  358. assert kind == 'void' or kind[0] in expectedkind
  359. assert op1.opname == '-live-'
  360. assert op1.args == []
  361. def indirect_regular_call_test(argtypes, restype, expectedkind):
  362. # a regular indirect call is preceded by a guard_value on the
  363. # function address, so that pyjitpl can know which jitcode to follow
  364. from pypy.jit.codewriter.flatten import IndirectCallTargets
  365. op = get_direct_call_op(argtypes, restype)
  366. op.opname = 'indirect_call'
  367. op.args[0] = varoftype(op.args[0].concretetype)
  368. op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void))
  369. tr = Transformer(FakeCPU(), FakeRegularIndirectCallControl())
  370. tr.graph = 'someinitialgraph'
  371. oplist = tr.rewrite_operation(op)
  372. op0gv, op1gv, op0, op1 = oplist
  373. assert op0gv.opname == '-live-'
  374. assert op0gv.args == []
  375. assert op1gv.opname == 'int_guard_value'
  376. assert op1gv.args == [op.args[0]]
  377. assert op1gv.result is None
  378. #
  379. reskind = getkind(restype)[0]
  380. assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind)
  381. assert op0.result == op.result
  382. assert op0.args[0] == op.args[0]
  383. assert op0.args[1] == 'calldescr'
  384. assert isinstance(op0.args[2], IndirectCallTargets)
  385. assert op0.args[2].lst == ['somejitcode1', 'somejitcode2']
  386. assert len(op0.args) == 3 + len(expectedkind)
  387. for sublist, kind1 in zip(op0.args[3:], expectedkind):
  388. assert sublist.kind.startswith(kind1)
  389. assert list(sublist) == [v for v in op.args[1:]
  390. if getkind(v.concretetype)==sublist.kind]
  391. for v in op.args[1:]:
  392. kind = getkind(v.concretetype)
  393. assert kind == 'void' or kind[0] in expectedkind
  394. # Note: we still expect a -live- here, even though canraise() returns
  395. # False, because this 'residual_call' will likely call further jitcodes
  396. # which can do e.g. guard_class or other stuff requiring anyway a -live-.
  397. assert op1.opname == '-live-'
  398. assert op1.args == []
  399. def test_getfield():
  400. # XXX a more compact encoding would be possible, something along
  401. # the lines of getfield_gc_r %r0, $offset, %r1
  402. # which would not need a Descr at all.
  403. S1 = lltype.Struct('S1')
  404. S2 = lltype.GcStruct('S2')
  405. S = lltype.GcStruct('S', ('int', lltype.Signed),
  406. ('ps1', lltype.Ptr(S1)),
  407. ('ps2', lltype.Ptr(S2)),
  408. ('flt', lltype.Float),
  409. ('boo', lltype.Bool),
  410. ('chr', lltype.Char),
  411. ('unc', lltype.UniChar))
  412. for name, suffix in [('int', 'i'),
  413. ('ps1', 'i'),
  414. ('ps2', 'r'),
  415. ('flt', 'f'),
  416. ('boo', 'i'),
  417. ('chr', 'i'),
  418. ('unc', 'i')]:
  419. v_parent = varoftype(lltype.Ptr(S))
  420. c_name = Constant(name, lltype.Void)
  421. v_result = varoftype(getattr(S, name))
  422. op = SpaceOperation('getfield', [v_parent, c_name], v_result)
  423. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  424. assert op1.opname == 'getfield_gc_' + suffix
  425. fielddescr = ('fielddescr', S, name)
  426. assert op1.args == [v_parent, fielddescr]
  427. assert op1.result == v_result
  428. def test_getfield_typeptr():
  429. v_parent = varoftype(rclass.OBJECTPTR)
  430. c_name = Constant('typeptr', lltype.Void)
  431. v_result = varoftype(rclass.OBJECT.typeptr)
  432. op = SpaceOperation('getfield', [v_parent, c_name], v_result)
  433. oplist = Transformer(FakeCPU()).rewrite_operation(op)
  434. op0, op1 = oplist
  435. assert op0.opname == '-live-'
  436. assert op0.args == []
  437. assert op1.opname == 'guard_class'
  438. assert op1.args == [v_parent]
  439. assert op1.result == v_result
  440. def test_setfield():
  441. # XXX a more compact encoding would be possible; see test_getfield()
  442. S1 = lltype.Struct('S1')
  443. S2 = lltype.GcStruct('S2')
  444. S = lltype.GcStruct('S', ('int', lltype.Signed),
  445. ('ps1', lltype.Ptr(S1)),
  446. ('ps2', lltype.Ptr(S2)),
  447. ('flt', lltype.Float),
  448. ('boo', lltype.Bool),
  449. ('chr', lltype.Char),
  450. ('unc', lltype.UniChar))
  451. for name, suffix in [('int', 'i'),
  452. ('ps1', 'i'),
  453. ('ps2', 'r'),
  454. ('flt', 'f'),
  455. ('boo', 'i'),
  456. ('chr', 'i'),
  457. ('unc', 'i')]:
  458. v_parent = varoftype(lltype.Ptr(S))
  459. c_name = Constant(name, lltype.Void)
  460. v_newvalue = varoftype(getattr(S, name))
  461. op = SpaceOperation('setfield', [v_parent, c_name, v_newvalue],
  462. varoftype(lltype.Void))
  463. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  464. assert op1.opname == 'setfield_gc_' + suffix
  465. fielddescr = ('fielddescr', S, name)
  466. assert op1.args == [v_parent, fielddescr, v_newvalue]
  467. assert op1.result is None
  468. def test_malloc_new():
  469. S = lltype.GcStruct('S')
  470. v = varoftype(lltype.Ptr(S))
  471. op = SpaceOperation('malloc', [Constant(S, lltype.Void),
  472. Constant({'flavor': 'gc'}, lltype.Void)], v)
  473. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  474. assert op1.opname == 'new'
  475. assert op1.args == [('sizedescr', S)]
  476. def test_malloc_new_with_vtable():
  477. vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  478. S = lltype.GcStruct('S', ('parent', rclass.OBJECT))
  479. heaptracker.set_testing_vtable_for_gcstruct(S, vtable, 'S')
  480. v = varoftype(lltype.Ptr(S))
  481. op = SpaceOperation('malloc', [Constant(S, lltype.Void),
  482. Constant({'flavor': 'gc'}, lltype.Void)], v)
  483. cpu = FakeCPU()
  484. op1 = Transformer(cpu).rewrite_operation(op)
  485. assert op1.opname == 'new_with_vtable'
  486. assert op1.args == [('sizedescr', S)]
  487. #assert heaptracker.descr2vtable(cpu, op1.args[0]) == vtable [type check]
  488. vtable_int = heaptracker.adr2int(llmemory.cast_ptr_to_adr(vtable))
  489. assert heaptracker.vtable2descr(cpu, vtable_int) == op1.args[0]
  490. def test_malloc_new_with_destructor():
  491. vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  492. S = lltype.GcStruct('S', ('parent', rclass.OBJECT), rtti=True)
  493. DESTRUCTOR = lltype.FuncType([lltype.Ptr(S)], lltype.Void)
  494. destructor = lltype.functionptr(DESTRUCTOR, 'destructor')
  495. lltype.attachRuntimeTypeInfo(S, destrptr=destructor)
  496. heaptracker.set_testing_vtable_for_gcstruct(S, vtable, 'S')
  497. v = varoftype(lltype.Ptr(S))
  498. op = SpaceOperation('malloc', [Constant(S, lltype.Void),
  499. Constant({'flavor': 'gc'}, lltype.Void)], v)
  500. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  501. oplist = tr.rewrite_operation(op)
  502. op0, op1 = oplist
  503. assert op0.opname == 'residual_call_r_r'
  504. assert op0.args[0].value == 'alloc_with_del' # pseudo-function as a str
  505. assert list(op0.args[2]) == []
  506. assert op1.opname == '-live-'
  507. assert op1.args == []
  508. def test_raw_malloc():
  509. S = rffi.CArray(lltype.Signed)
  510. v1 = varoftype(lltype.Signed)
  511. v = varoftype(lltype.Ptr(S))
  512. flags = Constant({'flavor': 'raw'}, lltype.Void)
  513. op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
  514. v1], v)
  515. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  516. op0, op1 = tr.rewrite_operation(op)
  517. assert op0.opname == 'residual_call_ir_i'
  518. assert op0.args[0].value == 'raw_malloc_varsize' # pseudo-function as a str
  519. assert op1.opname == '-live-'
  520. assert op1.args == []
  521. def test_raw_malloc_zero():
  522. S = rffi.CArray(lltype.Signed)
  523. v1 = varoftype(lltype.Signed)
  524. v = varoftype(lltype.Ptr(S))
  525. flags = Constant({'flavor': 'raw', 'zero': True}, lltype.Void)
  526. op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
  527. v1], v)
  528. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  529. op0, op1 = tr.rewrite_operation(op)
  530. assert op0.opname == 'residual_call_ir_i'
  531. assert op0.args[0].value == 'raw_malloc_varsize_zero' # pseudo-fn as a str
  532. assert op1.opname == '-live-'
  533. assert op1.args == []
  534. def test_raw_malloc_unsupported_flag():
  535. S = rffi.CArray(lltype.Signed)
  536. v1 = varoftype(lltype.Signed)
  537. v = varoftype(lltype.Ptr(S))
  538. flags = Constant({'flavor': 'raw', 'unsupported_flag': True}, lltype.Void)
  539. op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
  540. v1], v)
  541. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  542. py.test.raises(UnsupportedMallocFlags, tr.rewrite_operation, op)
  543. def test_raw_malloc_fixedsize():
  544. S = lltype.Struct('dummy', ('x', lltype.Signed))
  545. v = varoftype(lltype.Ptr(S))
  546. flags = Constant({'flavor': 'raw', 'zero': True}, lltype.Void)
  547. op = SpaceOperation('malloc', [Constant(S, lltype.Void), flags], v)
  548. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  549. op0, op1 = tr.rewrite_operation(op)
  550. assert op0.opname == 'residual_call_r_i'
  551. assert op0.args[0].value == 'raw_malloc_fixedsize_zero' #pseudo-fn as a str
  552. assert op1.opname == '-live-'
  553. assert op1.args == []
  554. def test_raw_free():
  555. S = lltype.Struct('dummy', ('x', lltype.Signed))
  556. for flag in [True, False]:
  557. flags = Constant({'flavor': 'raw', 'track_allocation': flag},
  558. lltype.Void)
  559. op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
  560. varoftype(lltype.Void))
  561. tr = Transformer(FakeCPU(), FakeResidualCallControl())
  562. op0, op1 = tr.rewrite_operation(op)
  563. assert op0.opname == 'residual_call_ir_v'
  564. if flag:
  565. pseudo_op_name = 'raw_free'
  566. else:
  567. pseudo_op_name = 'raw_free_no_track_allocation'
  568. assert op0.args[0].value == pseudo_op_name # pseudo-function as a str
  569. assert op1.opname == '-live-'
  570. def test_rename_on_links():
  571. v1 = Variable()
  572. v2 = Variable(); v2.concretetype = llmemory.Address
  573. v3 = Variable()
  574. block = Block([v1])
  575. block.operations = [SpaceOperation('cast_pointer', [v1], v2)]
  576. block2 = Block([v3])
  577. block.closeblock(Link([v2], block2))
  578. Transformer().optimize_block(block)
  579. assert block.inputargs == [v1]
  580. assert block.operations == []
  581. assert block.exits[0].target is block2
  582. assert block.exits[0].args == [v1]
  583. def test_int_eq():
  584. v1 = varoftype(lltype.Signed)
  585. v2 = varoftype(lltype.Signed)
  586. v3 = varoftype(lltype.Bool)
  587. c0 = const(0)
  588. #
  589. for opname, reducedname in [('int_eq', 'int_is_zero'),
  590. ('int_ne', 'int_is_true')]:
  591. op = SpaceOperation(opname, [v1, v2], v3)
  592. op1 = Transformer().rewrite_operation(op)
  593. assert op1.opname == opname
  594. assert op1.args == [v1, v2]
  595. #
  596. op = SpaceOperation(opname, [v1, c0], v3)
  597. op1 = Transformer().rewrite_operation(op)
  598. assert op1.opname == reducedname
  599. assert op1.args == [v1]
  600. #
  601. op = SpaceOperation(opname, [c0, v2], v3)
  602. op1 = Transformer().rewrite_operation(op)
  603. assert op1.opname == reducedname
  604. assert op1.args == [v2]
  605. def test_ptr_eq():
  606. v1 = varoftype(lltype.Ptr(rstr.STR))
  607. v2 = varoftype(lltype.Ptr(rstr.STR))
  608. v3 = varoftype(lltype.Bool)
  609. c0 = const(lltype.nullptr(rstr.STR))
  610. #
  611. for opname, reducedname in [('ptr_eq', 'ptr_iszero'),
  612. ('ptr_ne', 'ptr_nonzero')]:
  613. op = SpaceOperation(opname, [v1, v2], v3)
  614. op1 = Transformer().rewrite_operation(op)
  615. assert op1.opname == opname
  616. assert op1.args == [v1, v2]
  617. #
  618. op = SpaceOperation(opname, [v1, c0], v3)
  619. op1 = Transformer().rewrite_operation(op)
  620. assert op1.opname == reducedname
  621. assert op1.args == [v1]
  622. #
  623. op = SpaceOperation(opname, [c0, v2], v3)
  624. op1 = Transformer().rewrite_operation(op)
  625. assert op1.opname == reducedname
  626. assert op1.args == [v2]
  627. def test_instance_ptr_eq():
  628. v1 = varoftype(rclass.OBJECTPTR)
  629. v2 = varoftype(rclass.OBJECTPTR)
  630. v3 = varoftype(lltype.Bool)
  631. c0 = const(lltype.nullptr(rclass.OBJECT))
  632. for opname, newopname, reducedname in [
  633. ('ptr_eq', 'instance_ptr_eq', 'instance_ptr_iszero'),
  634. ('ptr_ne', 'instance_ptr_ne', 'instance_ptr_nonzero')
  635. ]:
  636. op = SpaceOperation(opname, [v1, v2], v3)
  637. op1 = Transformer().rewrite_operation(op)
  638. assert op1.opname == newopname
  639. assert op1.args == [v1, v2]
  640. op = SpaceOperation(opname, [v1, c0], v3)
  641. op1 = Transformer().rewrite_operation(op)
  642. assert op1.opname == reducedname
  643. assert op1.args == [v1]
  644. op = SpaceOperation(opname, [c0, v1], v3)
  645. op1 = Transformer().rewrite_operation(op)
  646. assert op1.opname == reducedname
  647. assert op1.args == [v1]
  648. def test_nongc_ptr_eq():
  649. v1 = varoftype(rclass.NONGCOBJECTPTR)
  650. v2 = varoftype(rclass.NONGCOBJECTPTR)
  651. v3 = varoftype(lltype.Bool)
  652. c0 = const(lltype.nullptr(rclass.NONGCOBJECT))
  653. #
  654. for opname, reducedname in [('ptr_eq', 'int_is_zero'),
  655. ('ptr_ne', 'int_is_true')]:
  656. op = SpaceOperation(opname, [v1, v2], v3)
  657. op1 = Transformer().rewrite_operation(op)
  658. assert op1.opname == opname.replace('ptr_', 'int_')
  659. assert op1.args == [v1, v2]
  660. #
  661. op = SpaceOperation(opname, [v1, c0], v3)
  662. op1 = Transformer().rewrite_operation(op)
  663. assert op1.opname == reducedname
  664. assert op1.args == [v1]
  665. #
  666. op = SpaceOperation(opname, [c0, v2], v3)
  667. op1 = Transformer().rewrite_operation(op)
  668. assert op1.opname == reducedname
  669. assert op1.args == [v2]
  670. #
  671. op = SpaceOperation('ptr_iszero', [v1], v3)
  672. op1 = Transformer().rewrite_operation(op)
  673. assert op1.opname == 'int_is_zero'
  674. assert op1.args == [v1]
  675. #
  676. op = SpaceOperation('ptr_nonzero', [v1], v3)
  677. op1 = Transformer().rewrite_operation(op)
  678. assert op1.opname == 'int_is_true'
  679. assert op1.args == [v1]
  680. def test_str_getinteriorarraysize():
  681. v = varoftype(lltype.Ptr(rstr.STR))
  682. v_result = varoftype(lltype.Signed)
  683. op = SpaceOperation('getinteriorarraysize',
  684. [v, Constant('chars', lltype.Void)],
  685. v_result)
  686. op1 = Transformer().rewrite_operation(op)
  687. assert op1.opname == 'strlen'
  688. assert op1.args == [v]
  689. assert op1.result == v_result
  690. def test_unicode_getinteriorarraysize():
  691. v = varoftype(lltype.Ptr(rstr.UNICODE))
  692. v_result = varoftype(lltype.Signed)
  693. op = SpaceOperation('getinteriorarraysize',
  694. [v, Constant('chars', lltype.Void)],
  695. v_result)
  696. op1 = Transformer().rewrite_operation(op)
  697. assert op1.opname == 'unicodelen'
  698. assert op1.args == [v]
  699. assert op1.result == v_result
  700. def test_str_getinteriorfield():
  701. v = varoftype(lltype.Ptr(rstr.STR))
  702. v_index = varoftype(lltype.Signed)
  703. v_result = varoftype(lltype.Char)
  704. op = SpaceOperation('getinteriorfield',
  705. [v, Constant('chars', lltype.Void), v_index],
  706. v_result)
  707. op1 = Transformer().rewrite_operation(op)
  708. assert op1.opname == 'strgetitem'
  709. assert op1.args == [v, v_index]
  710. assert op1.result == v_result
  711. def test_unicode_getinteriorfield():
  712. v = varoftype(lltype.Ptr(rstr.UNICODE))
  713. v_index = varoftype(lltype.Signed)
  714. v_result = varoftype(lltype.UniChar)
  715. op = SpaceOperation('getinteriorfield',
  716. [v, Constant('chars', lltype.Void), v_index],
  717. v_result)
  718. op1 = Transformer().rewrite_operation(op)
  719. assert op1.opname == 'unicodegetitem'
  720. assert op1.args == [v, v_index]
  721. assert op1.result == v_result
  722. def test_dict_getinteriorfield():
  723. DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
  724. ('k', lltype.Signed)))
  725. v = varoftype(lltype.Ptr(DICT))
  726. i = varoftype(lltype.Signed)
  727. v_result = varoftype(lltype.Signed)
  728. op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
  729. v_result)
  730. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  731. assert op1.opname == 'getinteriorfield_gc_i'
  732. assert op1.args == [v, i, ('interiorfielddescr', DICT, 'v')]
  733. op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
  734. Constant(None, lltype.Void))
  735. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  736. assert op1 is None
  737. def test_str_setinteriorfield():
  738. v = varoftype(lltype.Ptr(rstr.STR))
  739. v_index = varoftype(lltype.Signed)
  740. v_newchr = varoftype(lltype.Char)
  741. v_void = varoftype(lltype.Void)
  742. op = SpaceOperation('setinteriorfield',
  743. [v, Constant('chars', lltype.Void), v_index, v_newchr],
  744. v_void)
  745. op1 = Transformer().rewrite_operation(op)
  746. assert op1.opname == 'strsetitem'
  747. assert op1.args == [v, v_index, v_newchr]
  748. assert op1.result == v_void
  749. def test_unicode_setinteriorfield():
  750. v = varoftype(lltype.Ptr(rstr.UNICODE))
  751. v_index = varoftype(lltype.Signed)
  752. v_newchr = varoftype(lltype.UniChar)
  753. v_void = varoftype(lltype.Void)
  754. op = SpaceOperation('setinteriorfield',
  755. [v, Constant('chars', lltype.Void), v_index, v_newchr],
  756. v_void)
  757. op1 = Transformer().rewrite_operation(op)
  758. assert op1.opname == 'unicodesetitem'
  759. assert op1.args == [v, v_index, v_newchr]
  760. assert op1.result == v_void
  761. def test_dict_setinteriorfield():
  762. DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
  763. ('k', lltype.Signed)))
  764. v = varoftype(lltype.Ptr(DICT))
  765. i = varoftype(lltype.Signed)
  766. v_void = varoftype(lltype.Void)
  767. op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
  768. i],
  769. v_void)
  770. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  771. assert op1.opname == 'setinteriorfield_gc_i'
  772. assert op1.args == [v, i, i, ('interiorfielddescr', DICT, 'v')]
  773. op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
  774. v_void], v_void)
  775. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  776. assert not op1
  777. def test_promote_1():
  778. v1 = varoftype(lltype.Signed)
  779. v2 = varoftype(lltype.Signed)
  780. op = SpaceOperation('hint',
  781. [v1, Constant({'promote': True}, lltype.Void)],
  782. v2)
  783. oplist = Transformer().rewrite_operation(op)
  784. op0, op1, op2 = oplist
  785. assert op0.opname == '-live-'
  786. assert op0.args == []
  787. assert op1.opname == 'int_guard_value'
  788. assert op1.args == [v1]
  789. assert op1.result is None
  790. assert op2 is None
  791. def test_promote_2():
  792. v1 = varoftype(lltype.Signed)
  793. v2 = varoftype(lltype.Signed)
  794. op = SpaceOperation('hint',
  795. [v1, Constant({'promote': True}, lltype.Void)],
  796. v2)
  797. returnblock = Block([varoftype(lltype.Signed)])
  798. returnblock.operations = ()
  799. block = Block([v1])
  800. block.operations = [op]
  801. block.closeblock(Link([v2], returnblock))
  802. Transformer().optimize_block(block)
  803. assert len(block.operations) == 2
  804. assert block.operations[0].opname == '-live-'
  805. assert block.operations[0].args == []
  806. assert block.operations[1].opname == 'int_guard_value'
  807. assert block.operations[1].args == [v1]
  808. assert block.operations[1].result is None
  809. assert block.exits[0].args == [v1]
  810. def test_jit_merge_point_1():
  811. class FakeJitDriverSD:
  812. index = 42
  813. class jitdriver:
  814. active = True
  815. greens = ['green1', 'green2', 'voidgreen3']
  816. reds = ['red1', 'red2', 'voidred3']
  817. jd = FakeJitDriverSD()
  818. v1 = varoftype(lltype.Signed)
  819. v2 = varoftype(lltype.Signed)
  820. vvoid1 = varoftype(lltype.Void)
  821. v3 = varoftype(lltype.Signed)
  822. v4 = varoftype(lltype.Signed)
  823. vvoid2 = varoftype(lltype.Void)
  824. v5 = varoftype(lltype.Void)
  825. op = SpaceOperation('jit_marker',
  826. [Constant('jit_merge_point', lltype.Void),
  827. Constant(jd.jitdriver, lltype.Void),
  828. v1, v2, vvoid1, v3, v4, vvoid2], v5)
  829. tr = Transformer()
  830. tr.portal_jd = jd
  831. oplist = tr.rewrite_operation(op)
  832. assert len(oplist) == 7
  833. assert oplist[0].opname == '-live-'
  834. assert oplist[1].opname == 'int_guard_value'
  835. assert oplist[1].args == [v1]
  836. assert oplist[2].opname == '-live-'
  837. assert oplist[3].opname == 'int_guard_value'
  838. assert oplist[3].args == [v2]
  839. assert oplist[4].opname == '-live-'
  840. assert oplist[5].opname == 'jit_merge_point'
  841. assert oplist[5].args[0].value == 42
  842. assert list(oplist[5].args[1]) == [v1, v2]
  843. assert list(oplist[5].args[4]) == [v3, v4]
  844. assert oplist[6].opname == '-live-'
  845. def test_getfield_gc():
  846. S = lltype.GcStruct('S', ('x', lltype.Char))
  847. v1 = varoftype(lltype.Ptr(S))
  848. v2 = varoftype(lltype.Char)
  849. op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2)
  850. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  851. assert op1.opname == 'getfield_gc_i'
  852. assert op1.args == [v1, ('fielddescr', S, 'x')]
  853. assert op1.result == v2
  854. def test_getfield_gc_pure():
  855. S = lltype.GcStruct('S', ('x', lltype.Char),
  856. hints={'immutable': True})
  857. v1 = varoftype(lltype.Ptr(S))
  858. v2 = varoftype(lltype.Char)
  859. op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2)
  860. op1 = Transformer(FakeCPU()).rewrite_operation(op)
  861. assert op1.opname == 'getfield_gc_i_pure'
  862. assert op1.args == [v1, ('fielddescr', S, 'x')]
  863. assert op1.result == v2
  864. def test_getfield_gc_greenfield():
  865. class FakeCC:
  866. def get_vinfo(self, v):
  867. return None
  868. def could_be_green_field(self, S1, name1):
  869. assert S1 == S
  870. assert name1 == 'x'
  871. return True
  872. S = lltype.GcStruct('S', ('x', lltype.Char),
  873. hints={'immutable': True})
  874. v1 = varoftype(lltype.Ptr(S))
  875. v2 = varoftype(lltype.Char)
  876. op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2)
  877. op1 = Transformer(FakeCPU(), FakeCC()).rewrite_operation(op)
  878. assert op1.opname == 'getfield_gc_i_greenfield'
  879. assert op1.args == [v1, ('fielddescr', S, 'x')]
  880. assert op1.result == v2
  881. def test_int_abs():
  882. v1 = varoftype(lltype.Signed)
  883. v2 = varoftype(lltype.Signed)
  884. op = SpaceOperation('int_abs', [v1], v2)
  885. tr = Transformer(FakeCPU(), FakeRegularCallControl())
  886. tr.graph = "somemaingraph"
  887. oplist = tr.rewrite_operation(op)
  888. assert oplist[0].opname == 'inline_call_ir_i'
  889. assert oplist[0].args[0] == 'somejitcode'
  890. def test_str_newstr():
  891. c_STR = Constant(rstr.STR, lltype.Void)
  892. c_flavor = Constant({'flavor': 'gc'}, lltype.Void)
  893. v1 = varoftype(lltype.Signed)
  894. v2 = varoftype(lltype.Ptr(rstr.STR))
  895. op = SpaceOperation('malloc_varsize', [c_STR, c_flavor, v1], v2)
  896. op1 = Transformer().rewrite_operation(op)
  897. assert op1.opname == 'newstr'
  898. assert op1.args == [v1]
  899. assert op1.result == v2
  900. def test_str_concat():
  901. # test that the oopspec is present and correctly transformed
  902. PSTR = lltype.Ptr(rstr.STR)
  903. FUNC = lltype.FuncType([PSTR, PSTR], PSTR)
  904. func = lltype.functionptr(FUNC, 'll_strconcat',
  905. _callable=rstr.LLHelpers.ll_strconcat)
  906. v1 = varoftype(PSTR)
  907. v2 = varoftype(PSTR)
  908. v3 = varoftype(PSTR)
  909. op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
  910. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  911. op1 = tr.rewrite_operation(op)
  912. assert op1.opname == 'residual_call_r_r'
  913. assert op1.args[0].value == func
  914. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR_CONCAT
  915. assert op1.args[2] == ListOfKind('ref', [v1, v2])
  916. assert op1.result == v3
  917. def test_str_promote():
  918. PSTR = lltype.Ptr(rstr.STR)
  919. v1 = varoftype(PSTR)
  920. v2 = varoftype(PSTR)
  921. op = SpaceOperation('hint',
  922. [v1, Constant({'promote_string': True}, lltype.Void)],
  923. v2)
  924. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  925. op0, op1, _ = tr.rewrite_operation(op)
  926. assert op1.opname == 'str_guard_value'
  927. assert op1.args[0] == v1
  928. assert op1.args[2] == 'calldescr'
  929. assert op1.result == v2
  930. assert op0.opname == '-live-'
  931. def test_unicode_concat():
  932. # test that the oopspec is present and correctly transformed
  933. PSTR = lltype.Ptr(rstr.UNICODE)
  934. FUNC = lltype.FuncType([PSTR, PSTR], PSTR)
  935. func = lltype.functionptr(FUNC, 'll_strconcat',
  936. _callable=rstr.LLHelpers.ll_strconcat)
  937. v1 = varoftype(PSTR)
  938. v2 = varoftype(PSTR)
  939. v3 = varoftype(PSTR)
  940. op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
  941. cc = FakeBuiltinCallControl()
  942. tr = Transformer(FakeCPU(), cc)
  943. op1 = tr.rewrite_operation(op)
  944. assert op1.opname == 'residual_call_r_r'
  945. assert op1.args[0].value == func
  946. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_CONCAT
  947. assert op1.args[2] == ListOfKind('ref', [v1, v2])
  948. assert op1.result == v3
  949. #
  950. # check the callinfo_for_oopspec
  951. got = cc.callinfocollection.seen[0]
  952. assert got[0] == effectinfo.EffectInfo.OS_UNI_CONCAT
  953. assert got[1] == op1.args[1] # the calldescr
  954. assert heaptracker.int2adr(got[2]) == llmemory.cast_ptr_to_adr(func)
  955. def test_str_slice():
  956. # test that the oopspec is present and correctly transformed
  957. PSTR = lltype.Ptr(rstr.STR)
  958. INT = lltype.Signed
  959. FUNC = lltype.FuncType([PSTR, INT, INT], PSTR)
  960. func = lltype.functionptr(FUNC, '_ll_stringslice',
  961. _callable=rstr.LLHelpers._ll_stringslice)
  962. v1 = varoftype(PSTR)
  963. v2 = varoftype(INT)
  964. v3 = varoftype(INT)
  965. v4 = varoftype(PSTR)
  966. op = SpaceOperation('direct_call', [const(func), v1, v2, v3], v4)
  967. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  968. op1 = tr.rewrite_operation(op)
  969. assert op1.opname == 'residual_call_ir_r'
  970. assert op1.args[0].value == func
  971. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR_SLICE
  972. assert op1.args[2] == ListOfKind('int', [v2, v3])
  973. assert op1.args[3] == ListOfKind('ref', [v1])
  974. assert op1.result == v4
  975. def test_unicode_slice():
  976. # test that the oopspec is present and correctly transformed
  977. PUNICODE = lltype.Ptr(rstr.UNICODE)
  978. INT = lltype.Signed
  979. FUNC = lltype.FuncType([PUNICODE, INT, INT], PUNICODE)
  980. func = lltype.functionptr(FUNC, '_ll_stringslice',
  981. _callable=rstr.LLHelpers._ll_stringslice)
  982. v1 = varoftype(PUNICODE)
  983. v2 = varoftype(INT)
  984. v3 = varoftype(INT)
  985. v4 = varoftype(PUNICODE)
  986. op = SpaceOperation('direct_call', [const(func), v1, v2, v3], v4)
  987. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  988. op1 = tr.rewrite_operation(op)
  989. assert op1.opname == 'residual_call_ir_r'
  990. assert op1.args[0].value == func
  991. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_SLICE
  992. assert op1.args[2] == ListOfKind('int', [v2, v3])
  993. assert op1.args[3] == ListOfKind('ref', [v1])
  994. assert op1.result == v4
  995. def test_str2unicode():
  996. # test that the oopspec is present and correctly transformed
  997. PSTR = lltype.Ptr(rstr.STR)
  998. PUNICODE = lltype.Ptr(rstr.UNICODE)
  999. FUNC = lltype.FuncType([PSTR], PUNICODE)
  1000. func = lltype.functionptr(FUNC, 'll_str2unicode',
  1001. _callable=rstr.LLHelpers.ll_str2unicode)
  1002. v1 = varoftype(PSTR)
  1003. v2 = varoftype(PUNICODE)
  1004. op = SpaceOperation('direct_call', [const(func), v1], v2)
  1005. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  1006. op1 = tr.rewrite_operation(op)
  1007. assert op1.opname == 'residual_call_r_r'
  1008. assert op1.args[0].value == func
  1009. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR2UNICODE
  1010. assert op1.args[2] == ListOfKind('ref', [v1])
  1011. assert op1.result == v2
  1012. def test_unicode_eq_checknull_char():
  1013. # test that the oopspec is present and correctly transformed
  1014. PUNICODE = lltype.Ptr(rstr.UNICODE)
  1015. FUNC = lltype.FuncType([PUNICODE, PUNICODE], lltype.Bool)
  1016. func = lltype.functionptr(FUNC, 'll_streq',
  1017. _callable=rstr.LLHelpers.ll_streq)
  1018. v1 = varoftype(PUNICODE)
  1019. v2 = varoftype(PUNICODE)
  1020. v3 = varoftype(lltype.Bool)
  1021. op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
  1022. cc = FakeBuiltinCallControl()
  1023. tr = Transformer(FakeCPU(), cc)
  1024. op1 = tr.rewrite_operation(op)
  1025. assert op1.opname == 'residual_call_r_i'
  1026. assert op1.args[0].value == func
  1027. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_EQUAL
  1028. assert op1.args[2] == ListOfKind('ref', [v1, v2])
  1029. assert op1.result == v3
  1030. # test that the OS_UNIEQ_* functions are registered
  1031. cic = cc.callinfocollection
  1032. assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL)
  1033. assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR)
  1034. def test_list_ll_arraycopy():
  1035. from pypy.rlib.rgc import ll_arraycopy
  1036. LIST = lltype.GcArray(lltype.Signed)
  1037. PLIST = lltype.Ptr(LIST)
  1038. INT = lltype.Signed
  1039. FUNC = lltype.FuncType([PLIST]*2+[INT]*3, lltype.Void)
  1040. func = lltype.functionptr(FUNC, 'll_arraycopy', _callable=ll_arraycopy)
  1041. v1 = varoftype(PLIST)
  1042. v2 = varoftype(PLIST)
  1043. v3 = varoftype(INT)
  1044. v4 = varoftype(INT)
  1045. v5 = varoftype(INT)
  1046. v6 = varoftype(lltype.Void)
  1047. op = SpaceOperation('direct_call', [const(func), v1, v2, v3, v4, v5], v6)
  1048. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  1049. op1 = tr.rewrite_operation(op)
  1050. assert op1.opname == 'residual_call_ir_v'
  1051. assert op1.args[0].value == func
  1052. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_ARRAYCOPY
  1053. assert op1.args[2] == ListOfKind('int', [v3, v4, v5])
  1054. assert op1.args[3] == ListOfKind('ref', [v1, v2])
  1055. def test_math_sqrt():
  1056. # test that the oopspec is present and correctly transformed
  1057. FLOAT = lltype.Float
  1058. FUNC = lltype.FuncType([FLOAT], FLOAT)
  1059. func = lltype.functionptr(FUNC, 'll_math',
  1060. _callable=ll_math.sqrt_nonneg)
  1061. v1 = varoftype(FLOAT)
  1062. v2 = varoftype(FLOAT)
  1063. op = SpaceOperation('direct_call', [const(func), v1], v2)
  1064. tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
  1065. op1 = tr.rewrite_operation(op)
  1066. assert op1.opname == 'residual_call_irf_f'
  1067. assert op1.args[0].value == func
  1068. assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_MATH_SQRT
  1069. assert op1.args[2] == ListOfKind("int", [])
  1070. assert op1.args[3] == ListOfKind("ref", [])
  1071. assert op1.args[4] == ListOfKind('float', [v1])
  1072. assert op1.result == v2
  1073. def test_quasi_immutable():
  1074. from pypy.rpython.rclass import FieldListAccessor, IR_QUASIIMMUTABLE
  1075. accessor = FieldListAccessor()
  1076. accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE})
  1077. v2 = varoftype(lltype.Signed)
  1078. STRUCT = lltype.GcStruct('struct', ('inst_x', lltype.Signed),
  1079. ('mutate_x', rclass.OBJECTPTR),
  1080. hints={'immutable_fields': accessor})
  1081. for v_x in [const(lltype.malloc(STRUCT)), varoftype(lltype.Ptr(STRUCT))]:
  1082. op = SpaceOperation('getfield', [v_x, Constant('inst_x', lltype.Void)],
  1083. v2)
  1084. tr = Transformer(FakeCPU())
  1085. [_, op1, op2] = tr.rewrite_operation(op)
  1086. assert op1.opname == 'record_quasiimmut_field'
  1087. assert len(op1.args) == 3
  1088. assert op1.args[0] == v_x
  1089. assert op1.args[1] == ('fielddescr', STRUCT, 'inst_x')
  1090. assert op1.args[2] == ('fielddescr', STRUCT, 'mutate_x')
  1091. assert op1.result is None
  1092. assert op2.opname == 'getfield_gc_i'
  1093. assert len(op2.args) == 2
  1094. assert op2.args[0] == v_x
  1095. assert op2.args[1] == ('fielddescr', STRUCT, 'inst_x')
  1096. assert op2.result is op.result
  1097. def test_quasi_immutable_setfield():
  1098. from pypy.rpython.rclass import FieldListAccessor, IR_QUASIIMMUTABLE
  1099. accessor = FieldListAccessor()
  1100. accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE})
  1101. v1 = varoftype(lltype.Signed)
  1102. STRUCT = lltype.GcStruct('struct', ('inst_x', lltype.Signed),
  1103. ('mutate_x', rclass.OBJECTPTR),
  1104. hints={'immutable_fields': accessor})
  1105. for v_x in [const(lltype.malloc(STRUCT)), varoftype(lltype.Ptr(STRUCT))]:
  1106. op = SpaceOperation('jit_force_quasi_immutable',
  1107. [v_x, Constant('mutate_x', lltype.Void)],
  1108. varoftype(lltype.Void))
  1109. tr = Transformer(FakeCPU(), FakeRegularCallControl())
  1110. tr.graph = 'currentgraph'
  1111. op0, op1 = tr.rewrite_operation(op)
  1112. assert op0.opname == '-live-'
  1113. assert op1.opname == 'jit_force_quasi_immutable'
  1114. assert op1.args[0] == v_x
  1115. assert op1.args[1] == ('fielddescr', STRUCT, 'mutate_x')
  1116. def test_no_gcstruct_nesting_outside_of_OBJECT():
  1117. PARENT = lltype.GcStruct('parent')
  1118. STRUCT = lltype.GcStruct('struct', ('parent', PARENT),
  1119. ('x', lltype.Signed))
  1120. v_x = varoftype(lltype.Ptr(STRUCT))
  1121. op = SpaceOperation('getfield', [v_x, Constant('x', lltype.Void)],
  1122. varoftype(lltype.Signed))
  1123. tr = Transformer(None, None)
  1124. raises(NotImplementedError, tr.rewrite_operation, op)
  1125. def test_cast_opaque_ptr():
  1126. S = lltype.GcStruct("S", ("x", lltype.Signed))
  1127. v1 = varoftype(lltype.Ptr(S))
  1128. v2 = varoftype(lltype.Ptr(rclass.OBJECT))
  1129. op = SpaceOperation('cast_opaque_ptr', [v1], v2)
  1130. tr = Transformer()
  1131. [op1, op2] = tr.rewrite_operation(op)
  1132. assert op1.opname == 'mark_opaque_ptr'
  1133. assert op1.args == [v1]
  1134. assert op1.result is None
  1135. assert op2 is None
  1136. def test_unknown_operation():
  1137. op = SpaceOperation('foobar', [], varoftype(lltype.Void))
  1138. tr = Transformer()
  1139. try:
  1140. tr.rewrite_operation(op)
  1141. except Exception, e:
  1142. assert 'foobar' in str(e)