PageRenderTime 67ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/jit/codewriter/jtransform.py

https://bitbucket.org/pypy/pypy/
Python | 1489 lines | 1427 code | 29 blank | 33 comment | 46 complexity | e09e371286aa89e80140a582f16ed54b 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. from pypy.jit.codewriter import support, heaptracker, longlong
  3. from pypy.jit.codewriter.effectinfo import EffectInfo
  4. from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
  5. from pypy.jit.codewriter.policy import log
  6. from pypy.jit.metainterp import quasiimmut
  7. from pypy.jit.metainterp.history import getkind
  8. from pypy.jit.metainterp.typesystem import deref, arrayItem
  9. from pypy.jit.metainterp.blackhole import BlackholeInterpreter
  10. from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception
  11. from pypy.rlib import objectmodel
  12. from pypy.rlib.jit import _we_are_jitted
  13. from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rffi
  14. from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
  15. from pypy.translator.simplify import get_funcobj
  16. from pypy.translator.unsimplify import varoftype
  17. class UnsupportedMallocFlags(Exception):
  18. pass
  19. def transform_graph(graph, cpu=None, callcontrol=None, portal_jd=None):
  20. """Transform a control flow graph to make it suitable for
  21. being flattened in a JitCode.
  22. """
  23. t = Transformer(cpu, callcontrol, portal_jd)
  24. t.transform(graph)
  25. def integer_bounds(size, unsigned):
  26. if unsigned:
  27. return 0, 1 << (8 * size)
  28. else:
  29. return -(1 << (8 * size - 1)), 1 << (8 * size - 1)
  30. class Transformer(object):
  31. vable_array_vars = None
  32. def __init__(self, cpu=None, callcontrol=None, portal_jd=None):
  33. self.cpu = cpu
  34. self.callcontrol = callcontrol
  35. self.portal_jd = portal_jd # non-None only for the portal graph(s)
  36. def transform(self, graph):
  37. self.graph = graph
  38. for block in list(graph.iterblocks()):
  39. self.optimize_block(block)
  40. def optimize_block(self, block):
  41. if block.operations == ():
  42. return
  43. self.vable_array_vars = {}
  44. self.vable_flags = {}
  45. renamings = {}
  46. renamings_constants = {} # subset of 'renamings', {Var:Const} only
  47. newoperations = []
  48. #
  49. def do_rename(var, var_or_const):
  50. if var.concretetype is lltype.Void:
  51. renamings[var] = Constant(None, lltype.Void)
  52. return
  53. renamings[var] = var_or_const
  54. if isinstance(var_or_const, Constant):
  55. value = var_or_const.value
  56. value = lltype._cast_whatever(var.concretetype, value)
  57. renamings_constants[var] = Constant(value, var.concretetype)
  58. #
  59. for op in block.operations:
  60. if renamings_constants:
  61. op = self._do_renaming(renamings_constants, op)
  62. oplist = self.rewrite_operation(op)
  63. #
  64. count_before_last_operation = len(newoperations)
  65. if not isinstance(oplist, list):
  66. oplist = [oplist]
  67. for op1 in oplist:
  68. if isinstance(op1, SpaceOperation):
  69. newoperations.append(self._do_renaming(renamings, op1))
  70. elif op1 is None:
  71. # rewrite_operation() returns None to mean "has no real
  72. # effect, the result should just be renamed to args[0]"
  73. if op.result is not None:
  74. do_rename(op.result, renamings.get(op.args[0],
  75. op.args[0]))
  76. elif isinstance(op1, Constant):
  77. do_rename(op.result, op1)
  78. else:
  79. raise TypeError(repr(op1))
  80. #
  81. if block.exitswitch == c_last_exception:
  82. if len(newoperations) == count_before_last_operation:
  83. self._killed_exception_raising_operation(block)
  84. block.operations = newoperations
  85. block.exitswitch = renamings.get(block.exitswitch, block.exitswitch)
  86. self.follow_constant_exit(block)
  87. self.optimize_goto_if_not(block)
  88. for link in block.exits:
  89. self._check_no_vable_array(link.args)
  90. self._do_renaming_on_link(renamings, link)
  91. def _do_renaming(self, rename, op):
  92. op = SpaceOperation(op.opname, op.args[:], op.result)
  93. for i, v in enumerate(op.args):
  94. if isinstance(v, Variable):
  95. if v in rename:
  96. op.args[i] = rename[v]
  97. elif isinstance(v, ListOfKind):
  98. newlst = []
  99. for x in v:
  100. if x in rename:
  101. x = rename[x]
  102. newlst.append(x)
  103. op.args[i] = ListOfKind(v.kind, newlst)
  104. return op
  105. def _check_no_vable_array(self, list):
  106. if not self.vable_array_vars:
  107. return
  108. for v in list:
  109. if v in self.vable_array_vars:
  110. raise AssertionError(
  111. "A virtualizable array is passed around; it should\n"
  112. "only be used immediately after being read. Note\n"
  113. "that a possible cause is indexing with an index not\n"
  114. "known non-negative, or catching IndexError, or\n"
  115. "not inlining at all (for tests: use listops=True).\n"
  116. "Occurred in: %r" % self.graph)
  117. # extra explanation: with the way things are organized in
  118. # rpython/rlist.py, the ll_getitem becomes a function call
  119. # that is typically meant to be inlined by the JIT, but
  120. # this does not work with vable arrays because
  121. # jtransform.py expects the getfield and the getarrayitem
  122. # to be in the same basic block. It works a bit as a hack
  123. # for simple cases where we performed the backendopt
  124. # inlining before (even with a very low threshold, because
  125. # there is _always_inline_ on the relevant functions).
  126. def _do_renaming_on_link(self, rename, link):
  127. for i, v in enumerate(link.args):
  128. if isinstance(v, Variable):
  129. if v in rename:
  130. link.args[i] = rename[v]
  131. def _killed_exception_raising_operation(self, block):
  132. assert block.exits[0].exitcase is None
  133. block.exits = block.exits[:1]
  134. block.exitswitch = None
  135. # ----------
  136. def follow_constant_exit(self, block):
  137. v = block.exitswitch
  138. if isinstance(v, Constant) and v != c_last_exception:
  139. llvalue = v.value
  140. for link in block.exits:
  141. if link.llexitcase == llvalue:
  142. break
  143. else:
  144. assert link.exitcase == 'default'
  145. block.exitswitch = None
  146. link.exitcase = link.llexitcase = None
  147. block.recloseblock(link)
  148. def optimize_goto_if_not(self, block):
  149. """Replace code like 'v = int_gt(x,y); exitswitch = v'
  150. with just 'exitswitch = ('int_gt',x,y)'."""
  151. if len(block.exits) != 2:
  152. return False
  153. v = block.exitswitch
  154. if (v == c_last_exception or isinstance(v, tuple)
  155. or v.concretetype != lltype.Bool):
  156. return False
  157. for op in block.operations[::-1]:
  158. if v in op.args:
  159. return False # variable is also used in cur block
  160. if v is op.result:
  161. if op.opname not in ('int_lt', 'int_le', 'int_eq', 'int_ne',
  162. 'int_gt', 'int_ge',
  163. 'int_is_zero', 'int_is_true',
  164. 'ptr_eq', 'ptr_ne',
  165. 'ptr_iszero', 'ptr_nonzero'):
  166. return False # not a supported operation
  167. # ok! optimize this case
  168. block.operations.remove(op)
  169. block.exitswitch = (op.opname,) + tuple(op.args)
  170. if op.opname in ('ptr_iszero', 'ptr_nonzero'):
  171. block.exitswitch += ('-live-before',)
  172. # if the variable escape to the next block along a link,
  173. # replace it with a constant, because we know its value
  174. for link in block.exits:
  175. while v in link.args:
  176. index = link.args.index(v)
  177. link.args[index] = Constant(link.llexitcase,
  178. lltype.Bool)
  179. return True
  180. return False
  181. # ----------
  182. def rewrite_operation(self, op):
  183. try:
  184. rewrite = _rewrite_ops[op.opname]
  185. except KeyError:
  186. raise Exception("the JIT doesn't support the operation %r"
  187. " in %r" % (op, getattr(self, 'graph', '?')))
  188. return rewrite(self, op)
  189. def rewrite_op_same_as(self, op):
  190. if op.args[0] in self.vable_array_vars:
  191. self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
  192. def rewrite_op_cast_pointer(self, op):
  193. newop = self.rewrite_op_same_as(op)
  194. assert newop is None
  195. return
  196. # disabled for now
  197. if (self._is_rclass_instance(op.args[0]) and
  198. self._is_rclass_instance(op.result)):
  199. FROM = op.args[0].concretetype.TO
  200. TO = op.result.concretetype.TO
  201. if lltype._castdepth(TO, FROM) > 0:
  202. vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, TO)
  203. const_vtable = Constant(vtable, lltype.typeOf(vtable))
  204. return [None, # hack, do the right renaming from op.args[0] to op.result
  205. SpaceOperation("record_known_class", [op.args[0], const_vtable], None)]
  206. def rewrite_op_jit_record_known_class(self, op):
  207. return SpaceOperation("record_known_class", [op.args[0], op.args[1]], None)
  208. def rewrite_op_cast_bool_to_int(self, op): pass
  209. def rewrite_op_cast_bool_to_uint(self, op): pass
  210. def rewrite_op_cast_char_to_int(self, op): pass
  211. def rewrite_op_cast_unichar_to_int(self, op): pass
  212. def rewrite_op_cast_int_to_char(self, op): pass
  213. def rewrite_op_cast_int_to_unichar(self, op): pass
  214. def rewrite_op_cast_int_to_uint(self, op): pass
  215. def rewrite_op_cast_uint_to_int(self, op): pass
  216. def _rewrite_symmetric(self, op):
  217. """Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating
  218. too many variants of the bytecode."""
  219. if (isinstance(op.args[0], Constant) and
  220. isinstance(op.args[1], Variable)):
  221. reversename = {'int_lt': 'int_gt',
  222. 'int_le': 'int_ge',
  223. 'int_gt': 'int_lt',
  224. 'int_ge': 'int_le',
  225. 'uint_lt': 'uint_gt',
  226. 'uint_le': 'uint_ge',
  227. 'uint_gt': 'uint_lt',
  228. 'uint_ge': 'uint_le',
  229. 'float_lt': 'float_gt',
  230. 'float_le': 'float_ge',
  231. 'float_gt': 'float_lt',
  232. 'float_ge': 'float_le',
  233. }.get(op.opname, op.opname)
  234. return SpaceOperation(reversename,
  235. [op.args[1], op.args[0]] + op.args[2:],
  236. op.result)
  237. else:
  238. return op
  239. rewrite_op_int_add = _rewrite_symmetric
  240. rewrite_op_int_mul = _rewrite_symmetric
  241. rewrite_op_int_and = _rewrite_symmetric
  242. rewrite_op_int_or = _rewrite_symmetric
  243. rewrite_op_int_xor = _rewrite_symmetric
  244. rewrite_op_int_lt = _rewrite_symmetric
  245. rewrite_op_int_le = _rewrite_symmetric
  246. rewrite_op_int_gt = _rewrite_symmetric
  247. rewrite_op_int_ge = _rewrite_symmetric
  248. rewrite_op_uint_lt = _rewrite_symmetric
  249. rewrite_op_uint_le = _rewrite_symmetric
  250. rewrite_op_uint_gt = _rewrite_symmetric
  251. rewrite_op_uint_ge = _rewrite_symmetric
  252. rewrite_op_float_add = _rewrite_symmetric
  253. rewrite_op_float_mul = _rewrite_symmetric
  254. rewrite_op_float_lt = _rewrite_symmetric
  255. rewrite_op_float_le = _rewrite_symmetric
  256. rewrite_op_float_gt = _rewrite_symmetric
  257. rewrite_op_float_ge = _rewrite_symmetric
  258. def rewrite_op_int_add_ovf(self, op):
  259. op0 = self._rewrite_symmetric(op)
  260. op1 = SpaceOperation('-live-', [], None)
  261. return [op0, op1]
  262. rewrite_op_int_mul_ovf = rewrite_op_int_add_ovf
  263. def rewrite_op_int_sub_ovf(self, op):
  264. op1 = SpaceOperation('-live-', [], None)
  265. return [op, op1]
  266. # ----------
  267. # Various kinds of calls
  268. def rewrite_op_direct_call(self, op):
  269. kind = self.callcontrol.guess_call_kind(op)
  270. return getattr(self, 'handle_%s_call' % kind)(op)
  271. def rewrite_op_indirect_call(self, op):
  272. kind = self.callcontrol.guess_call_kind(op)
  273. return getattr(self, 'handle_%s_indirect_call' % kind)(op)
  274. def rewrite_call(self, op, namebase, initialargs, args=None):
  275. """Turn 'i0 = direct_call(fn, i1, i2, ref1, ref2)'
  276. into 'i0 = xxx_call_ir_i(fn, descr, [i1,i2], [ref1,ref2])'.
  277. The name is one of '{residual,direct}_call_{r,ir,irf}_{i,r,f,v}'."""
  278. if args is None:
  279. args = op.args[1:]
  280. self._check_no_vable_array(args)
  281. lst_i, lst_r, lst_f = self.make_three_lists(args)
  282. reskind = getkind(op.result.concretetype)[0]
  283. if lst_f or reskind == 'f': kinds = 'irf'
  284. elif lst_i: kinds = 'ir'
  285. else: kinds = 'r'
  286. sublists = []
  287. if 'i' in kinds: sublists.append(lst_i)
  288. if 'r' in kinds: sublists.append(lst_r)
  289. if 'f' in kinds: sublists.append(lst_f)
  290. return SpaceOperation('%s_%s_%s' % (namebase, kinds, reskind),
  291. initialargs + sublists, op.result)
  292. def make_three_lists(self, vars):
  293. args_i = []
  294. args_r = []
  295. args_f = []
  296. for v in vars:
  297. self.add_in_correct_list(v, args_i, args_r, args_f)
  298. return [ListOfKind('int', args_i),
  299. ListOfKind('ref', args_r),
  300. ListOfKind('float', args_f)]
  301. def add_in_correct_list(self, v, lst_i, lst_r, lst_f):
  302. kind = getkind(v.concretetype)
  303. if kind == 'void': return
  304. elif kind == 'int': lst = lst_i
  305. elif kind == 'ref': lst = lst_r
  306. elif kind == 'float': lst = lst_f
  307. else: raise AssertionError(kind)
  308. lst.append(v)
  309. def handle_residual_call(self, op, extraargs=[], may_call_jitcodes=False):
  310. """A direct_call turns into the operation 'residual_call_xxx' if it
  311. is calling a function that we don't want to JIT. The initial args
  312. of 'residual_call_xxx' are the function to call, and its calldescr."""
  313. calldescr = self.callcontrol.getcalldescr(op)
  314. op1 = self.rewrite_call(op, 'residual_call',
  315. [op.args[0], calldescr] + extraargs)
  316. if may_call_jitcodes or self.callcontrol.calldescr_canraise(calldescr):
  317. op1 = [op1, SpaceOperation('-live-', [], None)]
  318. return op1
  319. def handle_regular_call(self, op):
  320. """A direct_call turns into the operation 'inline_call_xxx' if it
  321. is calling a function that we want to JIT. The initial arg of
  322. 'inline_call_xxx' is the JitCode of the called function."""
  323. [targetgraph] = self.callcontrol.graphs_from(op)
  324. jitcode = self.callcontrol.get_jitcode(targetgraph,
  325. called_from=self.graph)
  326. op0 = self.rewrite_call(op, 'inline_call', [jitcode])
  327. op1 = SpaceOperation('-live-', [], None)
  328. return [op0, op1]
  329. def handle_builtin_call(self, op):
  330. oopspec_name, args = support.decode_builtin_call(op)
  331. # dispatch to various implementations depending on the oopspec_name
  332. if oopspec_name.startswith('list.') or oopspec_name == 'newlist':
  333. prepare = self._handle_list_call
  334. elif oopspec_name.startswith('stroruni.'):
  335. prepare = self._handle_stroruni_call
  336. elif oopspec_name == 'str.str2unicode':
  337. prepare = self._handle_str2unicode_call
  338. elif oopspec_name.startswith('virtual_ref'):
  339. prepare = self._handle_virtual_ref_call
  340. elif oopspec_name.startswith('jit.'):
  341. prepare = self._handle_jit_call
  342. elif oopspec_name.startswith('libffi_'):
  343. prepare = self._handle_libffi_call
  344. elif oopspec_name.startswith('math.sqrt'):
  345. prepare = self._handle_math_sqrt_call
  346. else:
  347. prepare = self.prepare_builtin_call
  348. try:
  349. op1 = prepare(op, oopspec_name, args)
  350. except NotSupported:
  351. op1 = op
  352. # If the resulting op1 is still a direct_call, turn it into a
  353. # residual_call.
  354. if isinstance(op1, SpaceOperation) and op1.opname == 'direct_call':
  355. op1 = self.handle_residual_call(op1)
  356. return op1
  357. def handle_recursive_call(self, op):
  358. jitdriver_sd = self.callcontrol.jitdriver_sd_from_portal_runner_ptr(
  359. op.args[0].value)
  360. assert jitdriver_sd is not None
  361. ops = self.promote_greens(op.args[1:], jitdriver_sd.jitdriver)
  362. num_green_args = len(jitdriver_sd.jitdriver.greens)
  363. args = ([Constant(jitdriver_sd.index, lltype.Signed)] +
  364. self.make_three_lists(op.args[1:1+num_green_args]) +
  365. self.make_three_lists(op.args[1+num_green_args:]))
  366. kind = getkind(op.result.concretetype)[0]
  367. op0 = SpaceOperation('recursive_call_%s' % kind, args, op.result)
  368. op1 = SpaceOperation('-live-', [], None)
  369. return ops + [op0, op1]
  370. handle_residual_indirect_call = handle_residual_call
  371. def handle_regular_indirect_call(self, op):
  372. """An indirect call where at least one target has a JitCode."""
  373. lst = []
  374. for targetgraph in self.callcontrol.graphs_from(op):
  375. jitcode = self.callcontrol.get_jitcode(targetgraph,
  376. called_from=self.graph)
  377. lst.append(jitcode)
  378. op0 = SpaceOperation('-live-', [], None)
  379. op1 = SpaceOperation('int_guard_value', [op.args[0]], None)
  380. op2 = self.handle_residual_call(op, [IndirectCallTargets(lst)], True)
  381. result = [op0, op1]
  382. if isinstance(op2, list):
  383. result += op2
  384. else:
  385. result.append(op2)
  386. return result
  387. def prepare_builtin_call(self, op, oopspec_name, args,
  388. extra=None, extrakey=None):
  389. argtypes = [v.concretetype for v in args]
  390. resulttype = op.result.concretetype
  391. c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
  392. oopspec_name, argtypes,
  393. resulttype, extra, extrakey)
  394. return SpaceOperation('direct_call', [c_func] + args, op.result)
  395. def _do_builtin_call(self, op, oopspec_name=None, args=None,
  396. extra=None, extrakey=None):
  397. if oopspec_name is None: oopspec_name = op.opname
  398. if args is None: args = op.args
  399. op1 = self.prepare_builtin_call(op, oopspec_name, args,
  400. extra, extrakey)
  401. return self.rewrite_op_direct_call(op1)
  402. # XXX some of the following functions should not become residual calls
  403. # but be really compiled
  404. rewrite_op_int_floordiv_ovf_zer = _do_builtin_call
  405. rewrite_op_int_floordiv_ovf = _do_builtin_call
  406. rewrite_op_int_floordiv_zer = _do_builtin_call
  407. rewrite_op_int_mod_ovf_zer = _do_builtin_call
  408. rewrite_op_int_mod_ovf = _do_builtin_call
  409. rewrite_op_int_mod_zer = _do_builtin_call
  410. rewrite_op_int_lshift_ovf = _do_builtin_call
  411. rewrite_op_int_abs = _do_builtin_call
  412. rewrite_op_llong_abs = _do_builtin_call
  413. rewrite_op_llong_floordiv = _do_builtin_call
  414. rewrite_op_llong_floordiv_zer = _do_builtin_call
  415. rewrite_op_llong_mod = _do_builtin_call
  416. rewrite_op_llong_mod_zer = _do_builtin_call
  417. rewrite_op_ullong_floordiv = _do_builtin_call
  418. rewrite_op_ullong_floordiv_zer = _do_builtin_call
  419. rewrite_op_ullong_mod = _do_builtin_call
  420. rewrite_op_ullong_mod_zer = _do_builtin_call
  421. rewrite_op_gc_identityhash = _do_builtin_call
  422. rewrite_op_gc_id = _do_builtin_call
  423. rewrite_op_uint_mod = _do_builtin_call
  424. rewrite_op_cast_float_to_uint = _do_builtin_call
  425. rewrite_op_cast_uint_to_float = _do_builtin_call
  426. # ----------
  427. # getfield/setfield/mallocs etc.
  428. def rewrite_op_hint(self, op):
  429. hints = op.args[1].value
  430. if hints.get('promote') and op.args[0].concretetype is not lltype.Void:
  431. assert op.args[0].concretetype != lltype.Ptr(rstr.STR)
  432. kind = getkind(op.args[0].concretetype)
  433. op0 = SpaceOperation('-live-', [], None)
  434. op1 = SpaceOperation('%s_guard_value' % kind, [op.args[0]], None)
  435. # the special return value None forces op.result to be considered
  436. # equal to op.args[0]
  437. return [op0, op1, None]
  438. if (hints.get('promote_string') and
  439. op.args[0].concretetype is not lltype.Void):
  440. S = lltype.Ptr(rstr.STR)
  441. assert op.args[0].concretetype == S
  442. self._register_extra_helper(EffectInfo.OS_STREQ_NONNULL,
  443. "str.eq_nonnull",
  444. [S, S],
  445. lltype.Signed,
  446. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  447. descr, p = self.callcontrol.callinfocollection.callinfo_for_oopspec(
  448. EffectInfo.OS_STREQ_NONNULL)
  449. # XXX this is fairly ugly way of creating a constant,
  450. # however, callinfocollection has no better interface
  451. c = Constant(p.adr.ptr, lltype.typeOf(p.adr.ptr))
  452. op1 = SpaceOperation('str_guard_value', [op.args[0], c, descr],
  453. op.result)
  454. return [SpaceOperation('-live-', [], None), op1, None]
  455. else:
  456. log.WARNING('ignoring hint %r at %r' % (hints, self.graph))
  457. def _rewrite_raw_malloc(self, op, name, args):
  458. d = op.args[1].value.copy()
  459. d.pop('flavor')
  460. add_memory_pressure = d.pop('add_memory_pressure', False)
  461. zero = d.pop('zero', False)
  462. track_allocation = d.pop('track_allocation', True)
  463. if d:
  464. raise UnsupportedMallocFlags(d)
  465. TYPE = op.args[0].value
  466. if zero:
  467. name += '_zero'
  468. if add_memory_pressure:
  469. name += '_add_memory_pressure'
  470. if not track_allocation:
  471. name += '_no_track_allocation'
  472. return self._do_builtin_call(op, name, args,
  473. extra = (TYPE,),
  474. extrakey = TYPE)
  475. def rewrite_op_malloc_varsize(self, op):
  476. if op.args[1].value['flavor'] == 'raw':
  477. return self._rewrite_raw_malloc(op, 'raw_malloc_varsize',
  478. [op.args[2]])
  479. if op.args[0].value == rstr.STR:
  480. return SpaceOperation('newstr', [op.args[2]], op.result)
  481. elif op.args[0].value == rstr.UNICODE:
  482. return SpaceOperation('newunicode', [op.args[2]], op.result)
  483. else:
  484. # XXX only strings or simple arrays for now
  485. ARRAY = op.args[0].value
  486. arraydescr = self.cpu.arraydescrof(ARRAY)
  487. return SpaceOperation('new_array', [arraydescr, op.args[2]],
  488. op.result)
  489. def rewrite_op_free(self, op):
  490. d = op.args[1].value.copy()
  491. assert d['flavor'] == 'raw'
  492. d.pop('flavor')
  493. track_allocation = d.pop('track_allocation', True)
  494. if d:
  495. raise UnsupportedMallocFlags(d)
  496. STRUCT = op.args[0].concretetype.TO
  497. name = 'raw_free'
  498. if not track_allocation:
  499. name += '_no_track_allocation'
  500. return self._do_builtin_call(op, name, [op.args[0]],
  501. extra = (STRUCT,), extrakey = STRUCT)
  502. def rewrite_op_getarrayitem(self, op):
  503. ARRAY = op.args[0].concretetype.TO
  504. if self._array_of_voids(ARRAY):
  505. return []
  506. if op.args[0] in self.vable_array_vars: # for virtualizables
  507. vars = self.vable_array_vars[op.args[0]]
  508. (v_base, arrayfielddescr, arraydescr) = vars
  509. kind = getkind(op.result.concretetype)
  510. return [SpaceOperation('-live-', [], None),
  511. SpaceOperation('getarrayitem_vable_%s' % kind[0],
  512. [v_base, arrayfielddescr, arraydescr,
  513. op.args[1]], op.result)]
  514. # normal case follows
  515. arraydescr = self.cpu.arraydescrof(ARRAY)
  516. kind = getkind(op.result.concretetype)
  517. return SpaceOperation('getarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
  518. [op.args[0], arraydescr, op.args[1]],
  519. op.result)
  520. def rewrite_op_setarrayitem(self, op):
  521. ARRAY = op.args[0].concretetype.TO
  522. if self._array_of_voids(ARRAY):
  523. return []
  524. if op.args[0] in self.vable_array_vars: # for virtualizables
  525. vars = self.vable_array_vars[op.args[0]]
  526. (v_base, arrayfielddescr, arraydescr) = vars
  527. kind = getkind(op.args[2].concretetype)
  528. return [SpaceOperation('-live-', [], None),
  529. SpaceOperation('setarrayitem_vable_%s' % kind[0],
  530. [v_base, arrayfielddescr, arraydescr,
  531. op.args[1], op.args[2]], None)]
  532. arraydescr = self.cpu.arraydescrof(ARRAY)
  533. kind = getkind(op.args[2].concretetype)
  534. return SpaceOperation('setarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
  535. [op.args[0], arraydescr, op.args[1], op.args[2]],
  536. None)
  537. def rewrite_op_getarraysize(self, op):
  538. ARRAY = op.args[0].concretetype.TO
  539. assert ARRAY._gckind == 'gc'
  540. if op.args[0] in self.vable_array_vars: # for virtualizables
  541. vars = self.vable_array_vars[op.args[0]]
  542. (v_base, arrayfielddescr, arraydescr) = vars
  543. return [SpaceOperation('-live-', [], None),
  544. SpaceOperation('arraylen_vable',
  545. [v_base, arrayfielddescr, arraydescr],
  546. op.result)]
  547. # normal case follows
  548. arraydescr = self.cpu.arraydescrof(ARRAY)
  549. return SpaceOperation('arraylen_gc', [op.args[0], arraydescr],
  550. op.result)
  551. def _array_of_voids(self, ARRAY):
  552. #if isinstance(ARRAY, ootype.Array):
  553. # return ARRAY.ITEM == ootype.Void
  554. #else:
  555. return ARRAY.OF == lltype.Void
  556. def rewrite_op_getfield(self, op):
  557. if self.is_typeptr_getset(op):
  558. return self.handle_getfield_typeptr(op)
  559. # turn the flow graph 'getfield' operation into our own version
  560. [v_inst, c_fieldname] = op.args
  561. RESULT = op.result.concretetype
  562. if RESULT is lltype.Void:
  563. return
  564. # check for virtualizable
  565. try:
  566. if self.is_virtualizable_getset(op):
  567. descr = self.get_virtualizable_field_descr(op)
  568. kind = getkind(RESULT)[0]
  569. return [SpaceOperation('-live-', [], None),
  570. SpaceOperation('getfield_vable_%s' % kind,
  571. [v_inst, descr], op.result)]
  572. except VirtualizableArrayField, e:
  573. # xxx hack hack hack
  574. vinfo = e.args[1]
  575. arrayindex = vinfo.array_field_counter[op.args[1].value]
  576. arrayfielddescr = vinfo.array_field_descrs[arrayindex]
  577. arraydescr = vinfo.array_descrs[arrayindex]
  578. self.vable_array_vars[op.result] = (op.args[0],
  579. arrayfielddescr,
  580. arraydescr)
  581. return []
  582. # check for _immutable_fields_ hints
  583. immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value)
  584. if immut:
  585. if (self.callcontrol is not None and
  586. self.callcontrol.could_be_green_field(v_inst.concretetype.TO,
  587. c_fieldname.value)):
  588. pure = '_greenfield'
  589. else:
  590. pure = '_pure'
  591. else:
  592. pure = ''
  593. self.check_field_access(v_inst.concretetype.TO)
  594. argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
  595. descr = self.cpu.fielddescrof(v_inst.concretetype.TO,
  596. c_fieldname.value)
  597. kind = getkind(RESULT)[0]
  598. op1 = SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure),
  599. [v_inst, descr], op.result)
  600. #
  601. if immut in (IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY):
  602. descr1 = self.cpu.fielddescrof(
  603. v_inst.concretetype.TO,
  604. quasiimmut.get_mutate_field_name(c_fieldname.value))
  605. op1 = [SpaceOperation('-live-', [], None),
  606. SpaceOperation('record_quasiimmut_field',
  607. [v_inst, descr, descr1], None),
  608. op1]
  609. return op1
  610. def rewrite_op_setfield(self, op):
  611. if self.is_typeptr_getset(op):
  612. # ignore the operation completely -- instead, it's done by 'new'
  613. return
  614. # turn the flow graph 'setfield' operation into our own version
  615. [v_inst, c_fieldname, v_value] = op.args
  616. RESULT = v_value.concretetype
  617. if RESULT is lltype.Void:
  618. return
  619. # check for virtualizable
  620. if self.is_virtualizable_getset(op):
  621. descr = self.get_virtualizable_field_descr(op)
  622. kind = getkind(RESULT)[0]
  623. return [SpaceOperation('-live-', [], None),
  624. SpaceOperation('setfield_vable_%s' % kind,
  625. [v_inst, descr, v_value], None)]
  626. self.check_field_access(v_inst.concretetype.TO)
  627. argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
  628. descr = self.cpu.fielddescrof(v_inst.concretetype.TO,
  629. c_fieldname.value)
  630. kind = getkind(RESULT)[0]
  631. return SpaceOperation('setfield_%s_%s' % (argname, kind),
  632. [v_inst, descr, v_value],
  633. None)
  634. def is_typeptr_getset(self, op):
  635. return (op.args[1].value == 'typeptr' and
  636. op.args[0].concretetype.TO._hints.get('typeptr'))
  637. def check_field_access(self, STRUCT):
  638. # check against a GcStruct with a nested GcStruct as a first argument
  639. # but which is not an object at all; see metainterp/test/test_loop,
  640. # test_regular_pointers_in_short_preamble.
  641. if not isinstance(STRUCT, lltype.GcStruct):
  642. return
  643. if STRUCT._first_struct() == (None, None):
  644. return
  645. PARENT = STRUCT
  646. while not PARENT._hints.get('typeptr'):
  647. _, PARENT = PARENT._first_struct()
  648. if PARENT is None:
  649. raise NotImplementedError("%r is a GcStruct using nesting but "
  650. "not inheriting from object" %
  651. (STRUCT,))
  652. def get_vinfo(self, v_virtualizable):
  653. if self.callcontrol is None: # for tests
  654. return None
  655. return self.callcontrol.get_vinfo(v_virtualizable.concretetype)
  656. def is_virtualizable_getset(self, op):
  657. # every access of an object of exactly the type VTYPEPTR is
  658. # likely to be a virtualizable access, but we still have to
  659. # check it in pyjitpl.py.
  660. vinfo = self.get_vinfo(op.args[0])
  661. if vinfo is None:
  662. return False
  663. res = False
  664. if op.args[1].value in vinfo.static_field_to_extra_box:
  665. res = True
  666. if op.args[1].value in vinfo.array_fields:
  667. res = VirtualizableArrayField(self.graph, vinfo)
  668. if res:
  669. flags = self.vable_flags[op.args[0]]
  670. if 'fresh_virtualizable' in flags:
  671. return False
  672. if isinstance(res, Exception):
  673. raise res
  674. return res
  675. def get_virtualizable_field_descr(self, op):
  676. fieldname = op.args[1].value
  677. vinfo = self.get_vinfo(op.args[0])
  678. index = vinfo.static_field_to_extra_box[fieldname]
  679. return vinfo.static_field_descrs[index]
  680. def handle_getfield_typeptr(self, op):
  681. if isinstance(op.args[0], Constant):
  682. cls = op.args[0].value.typeptr
  683. return Constant(cls, concretetype=rclass.CLASSTYPE)
  684. op0 = SpaceOperation('-live-', [], None)
  685. op1 = SpaceOperation('guard_class', [op.args[0]], op.result)
  686. return [op0, op1]
  687. def rewrite_op_malloc(self, op):
  688. if op.args[1].value['flavor'] == 'raw':
  689. return self._rewrite_raw_malloc(op, 'raw_malloc_fixedsize', [])
  690. #
  691. assert op.args[1].value == {'flavor': 'gc'}
  692. STRUCT = op.args[0].value
  693. vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, STRUCT)
  694. if vtable:
  695. # do we have a __del__?
  696. try:
  697. rtti = lltype.getRuntimeTypeInfo(STRUCT)
  698. except ValueError:
  699. pass
  700. else:
  701. if hasattr(rtti._obj, 'destructor_funcptr'):
  702. RESULT = lltype.Ptr(STRUCT)
  703. assert RESULT == op.result.concretetype
  704. return self._do_builtin_call(op, 'alloc_with_del', [],
  705. extra = (RESULT, vtable),
  706. extrakey = STRUCT)
  707. heaptracker.register_known_gctype(self.cpu, vtable, STRUCT)
  708. opname = 'new_with_vtable'
  709. else:
  710. opname = 'new'
  711. sizedescr = self.cpu.sizeof(STRUCT)
  712. return SpaceOperation(opname, [sizedescr], op.result)
  713. def rewrite_op_getinteriorarraysize(self, op):
  714. # only supports strings and unicodes
  715. assert len(op.args) == 2
  716. assert op.args[1].value == 'chars'
  717. optype = op.args[0].concretetype
  718. if optype == lltype.Ptr(rstr.STR):
  719. opname = "strlen"
  720. else:
  721. assert optype == lltype.Ptr(rstr.UNICODE)
  722. opname = "unicodelen"
  723. return SpaceOperation(opname, [op.args[0]], op.result)
  724. def rewrite_op_getinteriorfield(self, op):
  725. assert len(op.args) == 3
  726. optype = op.args[0].concretetype
  727. if optype == lltype.Ptr(rstr.STR):
  728. opname = "strgetitem"
  729. return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
  730. elif optype == lltype.Ptr(rstr.UNICODE):
  731. opname = "unicodegetitem"
  732. return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
  733. else:
  734. v_inst, v_index, c_field = op.args
  735. if op.result.concretetype is lltype.Void:
  736. return
  737. # only GcArray of Struct supported
  738. assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
  739. STRUCT = v_inst.concretetype.TO.OF
  740. assert isinstance(STRUCT, lltype.Struct)
  741. descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
  742. c_field.value)
  743. args = [v_inst, v_index, descr]
  744. kind = getkind(op.result.concretetype)[0]
  745. return SpaceOperation('getinteriorfield_gc_%s' % kind, args,
  746. op.result)
  747. def rewrite_op_setinteriorfield(self, op):
  748. assert len(op.args) == 4
  749. optype = op.args[0].concretetype
  750. if optype == lltype.Ptr(rstr.STR):
  751. opname = "strsetitem"
  752. return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
  753. op.result)
  754. elif optype == lltype.Ptr(rstr.UNICODE):
  755. opname = "unicodesetitem"
  756. return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
  757. op.result)
  758. else:
  759. v_inst, v_index, c_field, v_value = op.args
  760. if v_value.concretetype is lltype.Void:
  761. return
  762. # only GcArray of Struct supported
  763. assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
  764. STRUCT = v_inst.concretetype.TO.OF
  765. assert isinstance(STRUCT, lltype.Struct)
  766. descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
  767. c_field.value)
  768. kind = getkind(v_value.concretetype)[0]
  769. args = [v_inst, v_index, v_value, descr]
  770. return SpaceOperation('setinteriorfield_gc_%s' % kind, args,
  771. op.result)
  772. def _rewrite_equality(self, op, opname):
  773. arg0, arg1 = op.args
  774. if isinstance(arg0, Constant) and not arg0.value:
  775. return SpaceOperation(opname, [arg1], op.result)
  776. elif isinstance(arg1, Constant) and not arg1.value:
  777. return SpaceOperation(opname, [arg0], op.result)
  778. else:
  779. return self._rewrite_symmetric(op)
  780. def _is_gc(self, v):
  781. return getattr(getattr(v.concretetype, "TO", None), "_gckind", "?") == 'gc'
  782. def _is_rclass_instance(self, v):
  783. return lltype._castdepth(v.concretetype.TO, rclass.OBJECT) >= 0
  784. def _rewrite_cmp_ptrs(self, op):
  785. if self._is_gc(op.args[0]):
  786. return op
  787. else:
  788. opname = {'ptr_eq': 'int_eq',
  789. 'ptr_ne': 'int_ne',
  790. 'ptr_iszero': 'int_is_zero',
  791. 'ptr_nonzero': 'int_is_true'}[op.opname]
  792. return SpaceOperation(opname, op.args, op.result)
  793. def rewrite_op_int_eq(self, op):
  794. return self._rewrite_equality(op, 'int_is_zero')
  795. def rewrite_op_int_ne(self, op):
  796. return self._rewrite_equality(op, 'int_is_true')
  797. def rewrite_op_ptr_eq(self, op):
  798. prefix = ''
  799. if self._is_rclass_instance(op.args[0]):
  800. assert self._is_rclass_instance(op.args[1])
  801. op = SpaceOperation('instance_ptr_eq', op.args, op.result)
  802. prefix = 'instance_'
  803. op1 = self._rewrite_equality(op, prefix + 'ptr_iszero')
  804. return self._rewrite_cmp_ptrs(op1)
  805. def rewrite_op_ptr_ne(self, op):
  806. prefix = ''
  807. if self._is_rclass_instance(op.args[0]):
  808. assert self._is_rclass_instance(op.args[1])
  809. op = SpaceOperation('instance_ptr_ne', op.args, op.result)
  810. prefix = 'instance_'
  811. op1 = self._rewrite_equality(op, prefix + 'ptr_nonzero')
  812. return self._rewrite_cmp_ptrs(op1)
  813. rewrite_op_ptr_iszero = _rewrite_cmp_ptrs
  814. rewrite_op_ptr_nonzero = _rewrite_cmp_ptrs
  815. def rewrite_op_cast_ptr_to_int(self, op):
  816. if self._is_gc(op.args[0]):
  817. return op
  818. def rewrite_op_cast_opaque_ptr(self, op):
  819. # None causes the result of this op to get aliased to op.args[0]
  820. return [SpaceOperation('mark_opaque_ptr', op.args, None), None]
  821. def rewrite_op_force_cast(self, op):
  822. v_arg = op.args[0]
  823. v_result = op.result
  824. assert not self._is_gc(v_arg)
  825. if v_arg.concretetype == v_result.concretetype:
  826. return
  827. float_arg = v_arg.concretetype in [lltype.Float, lltype.SingleFloat]
  828. float_res = v_result.concretetype in [lltype.Float, lltype.SingleFloat]
  829. if not float_arg and not float_res:
  830. # some int -> some int cast
  831. return self._int_to_int_cast(v_arg, v_result)
  832. elif float_arg and float_res:
  833. # some float -> some float cast
  834. return self._float_to_float_cast(v_arg, v_result)
  835. elif not float_arg and float_res:
  836. # some int -> some float
  837. ops = []
  838. v2 = varoftype(lltype.Float)
  839. sizesign = rffi.size_and_sign(v_arg.concretetype)
  840. if sizesign <= rffi.size_and_sign(lltype.Signed):
  841. # cast from a type that fits in an int: either the size is
  842. # smaller, or it is equal and it is not unsigned
  843. v1 = varoftype(lltype.Signed)
  844. oplist = self.rewrite_operation(
  845. SpaceOperation('force_cast', [v_arg], v1)
  846. )
  847. if oplist:
  848. ops.extend(oplist)
  849. else:
  850. v1 = v_arg
  851. op = self.rewrite_operation(
  852. SpaceOperation('cast_int_to_float', [v1], v2)
  853. )
  854. ops.append(op)
  855. else:
  856. if sizesign == rffi.size_and_sign(lltype.Unsigned):
  857. opname = 'cast_uint_to_float'
  858. elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
  859. opname = 'cast_longlong_to_float'
  860. elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
  861. opname = 'cast_ulonglong_to_float'
  862. else:
  863. raise AssertionError('cast_x_to_float: %r' % (sizesign,))
  864. ops1 = self.rewrite_operation(
  865. SpaceOperation(opname, [v_arg], v2)
  866. )
  867. if not isinstance(ops1, list): ops1 = [ops1]
  868. ops.extend(ops1)
  869. op2 = self.rewrite_operation(
  870. SpaceOperation('force_cast', [v2], v_result)
  871. )
  872. if op2:
  873. ops.append(op2)
  874. else:
  875. ops[-1].result = v_result
  876. return ops
  877. elif float_arg and not float_res:
  878. # some float -> some int
  879. ops = []
  880. v1 = varoftype(lltype.Float)
  881. op1 = self.rewrite_operation(
  882. SpaceOperation('force_cast', [v_arg], v1)
  883. )
  884. if op1:
  885. ops.append(op1)
  886. else:
  887. v1 = v_arg
  888. sizesign = rffi.size_and_sign(v_result.concretetype)
  889. if sizesign <= rffi.size_and_sign(lltype.Signed):
  890. # cast to a type that fits in an int: either the size is
  891. # smaller, or it is equal and it is not unsigned
  892. v2 = varoftype(lltype.Signed)
  893. op = self.rewrite_operation(
  894. SpaceOperation('cast_float_to_int', [v1], v2)
  895. )
  896. ops.append(op)
  897. oplist = self.rewrite_operation(
  898. SpaceOperation('force_cast', [v2], v_result)
  899. )
  900. if oplist:
  901. ops.extend(oplist)
  902. else:
  903. op.result = v_result
  904. else:
  905. if sizesign == rffi.size_and_sign(lltype.Unsigned):
  906. opname = 'cast_float_to_uint'
  907. elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
  908. opname = 'cast_float_to_longlong'
  909. elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
  910. opname = 'cast_float_to_ulonglong'
  911. else:
  912. raise AssertionError('cast_float_to_x: %r' % (sizesign,))
  913. ops1 = self.rewrite_operation(
  914. SpaceOperation(opname, [v1], v_result)
  915. )
  916. if not isinstance(ops1, list): ops1 = [ops1]
  917. ops.extend(ops1)
  918. return ops
  919. else:
  920. assert False
  921. def _int_to_int_cast(self, v_arg, v_result):
  922. longlong_arg = longlong.is_longlong(v_arg.concretetype)
  923. longlong_res = longlong.is_longlong(v_result.concretetype)
  924. size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype)
  925. size2, unsigned2 = rffi.size_and_sign(v_result.concretetype)
  926. if longlong_arg and longlong_res:
  927. return
  928. elif longlong_arg:
  929. v = varoftype(lltype.Signed)
  930. op1 = self.rewrite_operation(
  931. SpaceOperation('truncate_longlong_to_int', [v_arg], v)
  932. )
  933. op2 = SpaceOperation('force_cast', [v], v_result)
  934. oplist = self.rewrite_operation(op2)
  935. if not oplist:
  936. op1.result = v_result
  937. oplist = []
  938. return [op1] + oplist
  939. elif longlong_res:
  940. if unsigned1:
  941. INTERMEDIATE = lltype.Unsigned
  942. else:
  943. INTERMEDIATE = lltype.Signed
  944. v = varoftype(INTERMEDIATE)
  945. op1 = SpaceOperation('force_cast', [v_arg], v)
  946. oplist = self.rewrite_operation(op1)
  947. if not oplist:
  948. v = v_arg
  949. oplist = []
  950. if unsigned1:
  951. if unsigned2:
  952. opname = 'cast_uint_to_ulonglong'
  953. else:
  954. opname = 'cast_uint_to_longlong'
  955. else:
  956. if unsigned2:
  957. opname = 'cast_int_to_ulonglong'
  958. else:
  959. opname = 'cast_int_to_longlong'
  960. op2 = self.rewrite_operation(
  961. SpaceOperation(opname, [v], v_result)
  962. )
  963. return oplist + [op2]
  964. # We've now, ostensibly, dealt with the longlongs, everything should be
  965. # a Signed or smaller
  966. assert size1 <= rffi.sizeof(lltype.Signed)
  967. assert size2 <= rffi.sizeof(lltype.Signed)
  968. # the target type is LONG or ULONG
  969. if size2 == rffi.sizeof(lltype.Signed):
  970. return
  971. min1, max1 = integer_bounds(size1, unsigned1)
  972. min2, max2 = integer_bounds(size2, unsigned2)
  973. # the target type includes the source range
  974. if min2 <= min1 <= max1 <= max2:
  975. return
  976. result = []
  977. if min2:
  978. c_min2 = Constant(min2, lltype.Signed)
  979. v2 = varoftype(lltype.Signed)
  980. result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
  981. else:
  982. v2 = v_arg
  983. c_mask = Constant(int((1 << (8 * size2)) - 1), lltype.Signed)
  984. if min2:
  985. v3 = varoftype(lltype.Signed)
  986. else:
  987. v3 = v_result
  988. result.append(SpaceOperation('int_and', [v2, c_mask], v3))
  989. if min2:
  990. result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
  991. return result
  992. def _float_to_float_cast(self, v_arg, v_result):
  993. if v_arg.concretetype == lltype.SingleFloat:
  994. assert v_result.concretetype == lltype.Float, "cast %s -> %s" % (
  995. v_arg.concretetype, v_result.concretetype)
  996. return SpaceOperation('cast_singlefloat_to_float', [v_arg],
  997. v_result)
  998. if v_result.concretetype == lltype.SingleFloat:
  999. assert v_arg.concretetype == lltype.Float, "cast %s -> %s" % (
  1000. v_arg.concretetype, v_result.concretetype)
  1001. return SpaceOperation('cast_float_to_singlefloat', [v_arg],
  1002. v_result)
  1003. def rewrite_op_direct_ptradd(self, op):
  1004. # xxx otherwise, not implemented:
  1005. assert op.args[0].concretetype == rffi.CCHARP
  1006. #
  1007. return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result)
  1008. # ----------
  1009. # Long longs, for 32-bit only. Supported operations are left unmodified,
  1010. # and unsupported ones are turned into a call to a function from
  1011. # jit.codewriter.support.
  1012. for _op, _oopspec in [('llong_invert', 'INVERT'),
  1013. ('llong_lt', 'LT'),
  1014. ('llong_le', 'LE'),
  1015. ('llong_eq', 'EQ'),
  1016. ('llong_ne', 'NE'),
  1017. ('llong_gt', 'GT'),
  1018. ('llong_ge', 'GE'),
  1019. ('llong_add', 'ADD'),
  1020. ('llong_sub', 'SUB'),
  1021. ('llong_mul', 'MUL'),
  1022. ('llong_and', 'AND'),
  1023. ('llong_or', 'OR'),
  1024. ('llong_xor', 'XOR'),
  1025. ('llong_lshift', 'LSHIFT'),
  1026. ('llong_rshift', 'RSHIFT'),
  1027. ('cast_int_to_longlong', 'FROM_INT'),
  1028. ('truncate_longlong_to_int', 'TO_INT'),
  1029. ('cast_float_to_longlong', 'FROM_FLOAT'),
  1030. ('cast_longlong_to_float', 'TO_FLOAT'),
  1031. ('cast_uint_to_longlong', 'FROM_UINT'),
  1032. ]:
  1033. exec py.code.Source('''
  1034. def rewrite_op_%s(self, op):
  1035. args = op.args
  1036. op1 = self.prepare_builtin_call(op, "llong_%s", args)
  1037. op2 = self._handle_oopspec_call(op1, args,
  1038. EffectInfo.OS_LLONG_%s,
  1039. EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
  1040. if %r == "TO_INT":
  1041. assert op2.result.concretetype == lltype.Signed
  1042. return op2
  1043. ''' % (_op, _oopspec.lower(), _oopspec, _oopspec)).compile()
  1044. for _op, _oopspec in [('cast_int_to_ulonglong', 'FROM_INT'),
  1045. ('cast_uint_to_ulonglong', 'FROM_UINT'),
  1046. ('cast_float_to_ulonglong', 'FROM_FLOAT'),
  1047. ('cast_ulonglong_to_float', 'U_TO_FLOAT'),
  1048. ('ullong_invert', 'INVERT'),
  1049. ('ullong_lt', 'ULT'),
  1050. ('ullong_le', 'ULE'),
  1051. ('ullong…

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