PageRenderTime 50ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/codewriter/test/test_jtransform.py

https://bitbucket.org/pypy/pypy/
Python | 1410 lines | 1280 code | 95 blank | 35 comment | 71 complexity | 63551adc0e725aac181ad79b91ddf275 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file