PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/metainterp/optimizeopt/optimizer.py

https://bitbucket.org/pypy/pypy/
Python | 907 lines | 774 code | 98 blank | 35 comment | 158 complexity | 23270f74e9e035ccaa77f7760b00d201 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.jit.metainterp import jitprof, resume, compile
  2. from rpython.jit.metainterp.executor import execute_nonspec_const
  3. from rpython.jit.metainterp.history import Const, ConstInt, ConstPtr
  4. from rpython.jit.metainterp.optimizeopt.intutils import IntBound,\
  5. ConstIntBound, MININT, MAXINT, IntUnbounded
  6. from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
  7. from rpython.jit.metainterp.resoperation import rop, AbstractResOp, GuardResOp,\
  8. OpHelpers
  9. from rpython.jit.metainterp.optimizeopt import info
  10. from rpython.jit.metainterp.optimize import InvalidLoop
  11. from rpython.jit.metainterp.typesystem import llhelper
  12. from rpython.rlib.objectmodel import specialize, we_are_translated
  13. from rpython.rlib.debug import debug_print
  14. from rpython.jit.metainterp.optimize import SpeculativeError
  15. CONST_0 = ConstInt(0)
  16. CONST_1 = ConstInt(1)
  17. CONST_ZERO_FLOAT = Const._new(0.0)
  18. llhelper.CONST_NULLREF = llhelper.CONST_NULL
  19. REMOVED = AbstractResOp()
  20. class LoopInfo(object):
  21. label_op = None
  22. class BasicLoopInfo(LoopInfo):
  23. def __init__(self, inputargs, quasi_immutable_deps, jump_op):
  24. self.inputargs = inputargs
  25. self.jump_op = jump_op
  26. self.quasi_immutable_deps = quasi_immutable_deps
  27. self.extra_same_as = []
  28. def final(self):
  29. return True
  30. def post_loop_compilation(self, loop, jitdriver_sd, metainterp, jitcell_token):
  31. pass
  32. class Optimization(object):
  33. next_optimization = None
  34. potential_extra_ops = None
  35. def __init__(self):
  36. pass # make rpython happy
  37. def send_extra_operation(self, op):
  38. self.optimizer.send_extra_operation(op)
  39. def propagate_forward(self, op):
  40. raise NotImplementedError
  41. def emit_operation(self, op):
  42. self.last_emitted_operation = op
  43. self.next_optimization.propagate_forward(op)
  44. def getintbound(self, op):
  45. assert op.type == 'i'
  46. op = self.get_box_replacement(op)
  47. if isinstance(op, ConstInt):
  48. return ConstIntBound(op.getint())
  49. fw = op.get_forwarded()
  50. if fw is not None:
  51. if isinstance(fw, IntBound):
  52. return fw
  53. # rare case: fw might be a RawBufferPtrInfo
  54. return IntUnbounded()
  55. assert op.type == 'i'
  56. intbound = IntBound(MININT, MAXINT)
  57. op.set_forwarded(intbound)
  58. return intbound
  59. def setintbound(self, op, bound):
  60. assert op.type == 'i'
  61. op = self.get_box_replacement(op)
  62. if op.is_constant():
  63. return
  64. cur = op.get_forwarded()
  65. if cur is not None:
  66. if isinstance(cur, IntBound):
  67. cur.intersect(bound)
  68. else:
  69. op.set_forwarded(bound)
  70. def getnullness(self, op):
  71. if op.type == 'r' or self.is_raw_ptr(op):
  72. ptrinfo = self.getptrinfo(op)
  73. if ptrinfo is None:
  74. return info.INFO_UNKNOWN
  75. return ptrinfo.getnullness()
  76. elif op.type == 'i':
  77. return self.getintbound(op).getnullness()
  78. assert False
  79. def make_constant_class(self, op, class_const, update_last_guard=True):
  80. op = self.get_box_replacement(op)
  81. opinfo = op.get_forwarded()
  82. if isinstance(opinfo, info.InstancePtrInfo):
  83. opinfo._known_class = class_const
  84. else:
  85. if opinfo is not None:
  86. last_guard_pos = opinfo.get_last_guard_pos()
  87. else:
  88. last_guard_pos = -1
  89. opinfo = info.InstancePtrInfo(None, class_const)
  90. opinfo.last_guard_pos = last_guard_pos
  91. op.set_forwarded(opinfo)
  92. if update_last_guard:
  93. opinfo.mark_last_guard(self.optimizer)
  94. return opinfo
  95. def getptrinfo(self, op, is_object=False):
  96. if op.type == 'i':
  97. return self.getrawptrinfo(op)
  98. elif op.type == 'f':
  99. return None
  100. assert op.type == 'r'
  101. op = self.get_box_replacement(op)
  102. assert op.type == 'r'
  103. if isinstance(op, ConstPtr):
  104. return info.ConstPtrInfo(op)
  105. fw = op.get_forwarded()
  106. if fw is not None:
  107. assert isinstance(fw, info.PtrInfo)
  108. return fw
  109. return None
  110. def is_raw_ptr(self, op):
  111. fw = self.get_box_replacement(op).get_forwarded()
  112. if isinstance(fw, info.AbstractRawPtrInfo):
  113. return True
  114. return False
  115. def getrawptrinfo(self, op, create=False, is_object=False):
  116. assert op.type == 'i'
  117. op = self.get_box_replacement(op)
  118. assert op.type == 'i'
  119. if isinstance(op, ConstInt):
  120. return info.ConstPtrInfo(op)
  121. fw = op.get_forwarded()
  122. if isinstance(fw, IntBound) and not create:
  123. return None
  124. if fw is not None:
  125. if isinstance(fw, info.AbstractRawPtrInfo):
  126. return fw
  127. fw = info.RawStructPtrInfo()
  128. op.set_forwarded(fw)
  129. assert isinstance(fw, info.AbstractRawPtrInfo)
  130. return fw
  131. return None
  132. def get_box_replacement(self, op):
  133. return self.optimizer.get_box_replacement(op)
  134. def getlastop(self):
  135. return self.optimizer.getlastop()
  136. def force_box(self, op, optforce=None):
  137. return self.optimizer.force_box(op, optforce)
  138. def replace_op_with(self, op, newopnum, args=None, descr=None):
  139. return self.optimizer.replace_op_with(op, newopnum, args, descr)
  140. def ensure_ptr_info_arg0(self, op):
  141. return self.optimizer.ensure_ptr_info_arg0(op)
  142. def make_constant(self, box, constbox):
  143. return self.optimizer.make_constant(box, constbox)
  144. def make_constant_int(self, box, intconst):
  145. return self.optimizer.make_constant_int(box, intconst)
  146. def make_equal_to(self, box, value):
  147. return self.optimizer.make_equal_to(box, value)
  148. def make_nonnull(self, op):
  149. return self.optimizer.make_nonnull(op)
  150. def make_nonnull_str(self, op, mode):
  151. return self.optimizer.make_nonnull_str(op, mode)
  152. def get_constant_box(self, box):
  153. return self.optimizer.get_constant_box(box)
  154. def new_box(self, fieldofs):
  155. return self.optimizer.new_box(fieldofs)
  156. def new_const(self, fieldofs):
  157. return self.optimizer.new_const(fieldofs)
  158. def new_box_item(self, arraydescr):
  159. return self.optimizer.new_box_item(arraydescr)
  160. def new_const_item(self, arraydescr):
  161. return self.optimizer.new_const_item(arraydescr)
  162. def pure(self, opnum, result):
  163. if self.optimizer.optpure:
  164. self.optimizer.optpure.pure(opnum, result)
  165. def pure_from_args(self, opnum, args, op, descr=None):
  166. if self.optimizer.optpure:
  167. self.optimizer.optpure.pure_from_args(opnum, args, op, descr)
  168. def has_pure_result(self, opnum, args, descr):
  169. if self.optimizer.optpure:
  170. return self.optimizer.optpure.has_pure_result(opnum, args, descr)
  171. return False
  172. def get_pure_result(self, key):
  173. if self.optimizer.optpure:
  174. return self.optimizer.optpure.get_pure_result(key)
  175. return None
  176. def setup(self):
  177. pass
  178. # Called after last operation has been propagated to flush out any posponed ops
  179. def flush(self):
  180. pass
  181. def produce_potential_short_preamble_ops(self, potential_ops):
  182. pass
  183. def forget_numberings(self):
  184. self.optimizer.forget_numberings()
  185. def _can_optimize_call_pure(self, op):
  186. arg_consts = []
  187. for i in range(op.numargs()):
  188. arg = op.getarg(i)
  189. const = self.optimizer.get_constant_box(arg)
  190. if const is None:
  191. return None
  192. arg_consts.append(const)
  193. else:
  194. # all constant arguments: check if we already know the result
  195. try:
  196. return self.optimizer.call_pure_results[arg_consts]
  197. except KeyError:
  198. return None
  199. class Optimizer(Optimization):
  200. def __init__(self, metainterp_sd, jitdriver_sd, optimizations=None):
  201. self.metainterp_sd = metainterp_sd
  202. self.jitdriver_sd = jitdriver_sd
  203. self.cpu = metainterp_sd.cpu
  204. self.interned_refs = self.cpu.ts.new_ref_dict()
  205. self.interned_ints = {}
  206. self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd)
  207. self.pendingfields = None # set temporarily to a list, normally by
  208. # heap.py, as we're about to generate a guard
  209. self.quasi_immutable_deps = None
  210. self.replaces_guard = {}
  211. self._newoperations = []
  212. self.optimizer = self
  213. self.optpure = None
  214. self.optheap = None
  215. self.optrewrite = None
  216. self.optearlyforce = None
  217. self.optunroll = None
  218. self._last_guard_op = None
  219. self.set_optimizations(optimizations)
  220. self.setup()
  221. def init_inparg_dict_from(self, lst):
  222. self.inparg_dict = {}
  223. for box in lst:
  224. self.inparg_dict[box] = None
  225. def set_optimizations(self, optimizations):
  226. if optimizations:
  227. self.first_optimization = optimizations[0]
  228. for i in range(1, len(optimizations)):
  229. optimizations[i - 1].next_optimization = optimizations[i]
  230. optimizations[-1].next_optimization = self
  231. for o in optimizations:
  232. o.optimizer = self
  233. o.last_emitted_operation = None
  234. o.setup()
  235. else:
  236. optimizations = []
  237. self.first_optimization = self
  238. self.optimizations = optimizations
  239. def force_op_from_preamble(self, op):
  240. return op
  241. def notice_guard_future_condition(self, op):
  242. self.patchguardop = op
  243. def replace_guard(self, op, value):
  244. assert isinstance(value, info.NonNullPtrInfo)
  245. if value.last_guard_pos == -1:
  246. return
  247. self.replaces_guard[op] = value.last_guard_pos
  248. def force_box_for_end_of_preamble(self, box):
  249. if box.type == 'r':
  250. info = self.getptrinfo(box)
  251. if info is not None and info.is_virtual():
  252. rec = {}
  253. return info.force_at_the_end_of_preamble(box,
  254. self.optearlyforce, rec)
  255. return box
  256. if box.type == 'i':
  257. info = self.getrawptrinfo(box)
  258. if info is not None:
  259. return info.force_at_the_end_of_preamble(box,
  260. self.optearlyforce, None)
  261. return box
  262. def flush(self):
  263. for o in self.optimizations:
  264. o.flush()
  265. def produce_potential_short_preamble_ops(self, sb):
  266. for opt in self.optimizations:
  267. opt.produce_potential_short_preamble_ops(sb)
  268. def forget_numberings(self):
  269. self.metainterp_sd.profiler.count(jitprof.Counters.OPT_FORCINGS)
  270. self.resumedata_memo.forget_numberings()
  271. def getinfo(self, op):
  272. if op.type == 'r':
  273. return self.getptrinfo(op)
  274. elif op.type == 'i':
  275. if self.is_raw_ptr(op):
  276. return self.getptrinfo(op)
  277. return self.getintbound(op)
  278. elif op.type == 'f':
  279. if self.get_box_replacement(op).is_constant():
  280. return info.FloatConstInfo(self.get_box_replacement(op))
  281. def get_box_replacement(self, op):
  282. if op is None:
  283. return op
  284. return op.get_box_replacement()
  285. def force_box(self, op, optforce=None):
  286. op = self.get_box_replacement(op)
  287. if optforce is None:
  288. optforce = self
  289. info = op.get_forwarded()
  290. if self.optunroll and self.optunroll.potential_extra_ops:
  291. # XXX hack
  292. try:
  293. preamble_op = self.optunroll.potential_extra_ops.pop(op)
  294. except KeyError:
  295. pass
  296. else:
  297. sb = self.optunroll.short_preamble_producer
  298. sb.add_preamble_op(preamble_op)
  299. if info is not None:
  300. if op.type == 'i' and info.is_constant():
  301. return ConstInt(info.getint())
  302. return info.force_box(op, optforce)
  303. return op
  304. def is_inputarg(self, op):
  305. return True
  306. return op in self.inparg_dict
  307. def get_constant_box(self, box):
  308. box = self.get_box_replacement(box)
  309. if isinstance(box, Const):
  310. return box
  311. if (box.type == 'i' and box.get_forwarded() and
  312. box.get_forwarded().is_constant()):
  313. return ConstInt(box.get_forwarded().getint())
  314. return None
  315. #self.ensure_imported(value)
  316. def get_newoperations(self):
  317. self.flush()
  318. return self._newoperations
  319. def clear_newoperations(self):
  320. self._newoperations = []
  321. def make_equal_to(self, op, newop):
  322. op = self.get_box_replacement(op)
  323. if op is newop:
  324. return
  325. opinfo = op.get_forwarded()
  326. if opinfo is not None:
  327. assert isinstance(opinfo, info.AbstractInfo)
  328. op.set_forwarded(newop)
  329. if not isinstance(newop, Const):
  330. newop.set_forwarded(opinfo)
  331. else:
  332. op.set_forwarded(newop)
  333. def replace_op_with(self, op, newopnum, args=None, descr=None):
  334. newop = op.copy_and_change(newopnum, args, descr)
  335. if newop.type != 'v':
  336. op = self.get_box_replacement(op)
  337. opinfo = op.get_forwarded()
  338. if opinfo is not None:
  339. newop.set_forwarded(opinfo)
  340. op.set_forwarded(newop)
  341. return newop
  342. def make_constant(self, box, constbox):
  343. assert isinstance(constbox, Const)
  344. box = self.get_box_replacement(box)
  345. # safety-check: if the constant is outside the bounds for the
  346. # box, then it is an invalid loop
  347. if (box.get_forwarded() is not None and
  348. isinstance(constbox, ConstInt) and
  349. not isinstance(box.get_forwarded(), info.AbstractRawPtrInfo)):
  350. if not box.get_forwarded().contains(constbox.getint()):
  351. raise InvalidLoop("a box is turned into constant that is "
  352. "outside the range allowed for that box")
  353. if box.is_constant():
  354. return
  355. if box.type == 'r' and box.get_forwarded() is not None:
  356. opinfo = box.get_forwarded()
  357. opinfo.copy_fields_to_const(self.getptrinfo(constbox), self.optheap)
  358. box.set_forwarded(constbox)
  359. def make_constant_int(self, box, intvalue):
  360. self.make_constant(box, ConstInt(intvalue))
  361. def make_nonnull(self, op):
  362. op = self.get_box_replacement(op)
  363. if op.is_constant():
  364. return
  365. if op.type == 'i':
  366. # raw pointers
  367. return
  368. opinfo = op.get_forwarded()
  369. if opinfo is not None:
  370. assert opinfo.is_nonnull()
  371. return
  372. op.set_forwarded(info.NonNullPtrInfo())
  373. def make_nonnull_str(self, op, mode):
  374. from rpython.jit.metainterp.optimizeopt import vstring
  375. op = self.get_box_replacement(op)
  376. if op.is_constant():
  377. return
  378. opinfo = op.get_forwarded()
  379. if isinstance(opinfo, vstring.StrPtrInfo):
  380. return
  381. op.set_forwarded(vstring.StrPtrInfo(mode))
  382. def ensure_ptr_info_arg0(self, op):
  383. from rpython.jit.metainterp.optimizeopt import vstring
  384. arg0 = self.get_box_replacement(op.getarg(0))
  385. if arg0.is_constant():
  386. return info.ConstPtrInfo(arg0)
  387. opinfo = arg0.get_forwarded()
  388. if isinstance(opinfo, info.AbstractVirtualPtrInfo):
  389. return opinfo
  390. elif opinfo is not None:
  391. last_guard_pos = opinfo.get_last_guard_pos()
  392. else:
  393. last_guard_pos = -1
  394. assert opinfo is None or opinfo.__class__ is info.NonNullPtrInfo
  395. opnum = op.opnum
  396. if (rop.is_getfield(opnum) or opnum == rop.SETFIELD_GC or
  397. opnum == rop.QUASIIMMUT_FIELD):
  398. descr = op.getdescr()
  399. parent_descr = descr.get_parent_descr()
  400. if parent_descr.is_object():
  401. opinfo = info.InstancePtrInfo(parent_descr)
  402. else:
  403. opinfo = info.StructPtrInfo(parent_descr)
  404. opinfo.init_fields(parent_descr, descr.get_index())
  405. elif (rop.is_getarrayitem(opnum) or opnum == rop.SETARRAYITEM_GC or
  406. opnum == rop.ARRAYLEN_GC):
  407. opinfo = info.ArrayPtrInfo(op.getdescr())
  408. elif opnum in (rop.GUARD_CLASS, rop.GUARD_NONNULL_CLASS):
  409. opinfo = info.InstancePtrInfo()
  410. elif opnum in (rop.STRLEN,):
  411. opinfo = vstring.StrPtrInfo(vstring.mode_string)
  412. elif opnum in (rop.UNICODELEN,):
  413. opinfo = vstring.StrPtrInfo(vstring.mode_unicode)
  414. else:
  415. assert False, "operations %s unsupported" % op
  416. assert isinstance(opinfo, info.NonNullPtrInfo)
  417. opinfo.last_guard_pos = last_guard_pos
  418. arg0.set_forwarded(opinfo)
  419. return opinfo
  420. def new_const(self, fieldofs):
  421. if fieldofs.is_pointer_field():
  422. return self.cpu.ts.CONST_NULL
  423. elif fieldofs.is_float_field():
  424. return CONST_ZERO_FLOAT
  425. else:
  426. return CONST_0
  427. def new_const_item(self, arraydescr):
  428. if arraydescr.is_array_of_pointers():
  429. return self.cpu.ts.CONST_NULL
  430. elif arraydescr.is_array_of_floats():
  431. return CONST_ZERO_FLOAT
  432. else:
  433. return CONST_0
  434. def propagate_all_forward(self, trace, call_pure_results=None, flush=True):
  435. self.trace = trace
  436. deadranges = trace.get_dead_ranges()
  437. self.call_pure_results = call_pure_results
  438. last_op = None
  439. i = 0
  440. while not trace.done():
  441. self._really_emitted_operation = None
  442. op = trace.next()
  443. if op.getopnum() in (rop.FINISH, rop.JUMP):
  444. last_op = op
  445. break
  446. self.first_optimization.propagate_forward(op)
  447. trace.kill_cache_at(deadranges[i + trace.start_index])
  448. if op.type != 'v':
  449. i += 1
  450. # accumulate counters
  451. if flush:
  452. self.flush()
  453. if last_op:
  454. self.first_optimization.propagate_forward(last_op)
  455. self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
  456. return (BasicLoopInfo(trace.inputargs, self.quasi_immutable_deps, last_op),
  457. self._newoperations)
  458. def _clean_optimization_info(self, lst):
  459. for op in lst:
  460. if op.get_forwarded() is not None:
  461. op.set_forwarded(None)
  462. def send_extra_operation(self, op):
  463. self.first_optimization.propagate_forward(op)
  464. def propagate_forward(self, op):
  465. dispatch_opt(self, op)
  466. def emit_operation(self, op):
  467. if rop.returns_bool_result(op.opnum):
  468. self.getintbound(op).make_bool()
  469. self._emit_operation(op)
  470. op = self.get_box_replacement(op)
  471. if op.type == 'i':
  472. opinfo = op.get_forwarded()
  473. if opinfo is not None:
  474. assert isinstance(opinfo, IntBound)
  475. if opinfo.is_constant():
  476. op.set_forwarded(ConstInt(opinfo.getint()))
  477. @specialize.argtype(0)
  478. def _emit_operation(self, op):
  479. assert not rop.is_call_pure(op.getopnum())
  480. orig_op = op
  481. op = self.get_box_replacement(op)
  482. if op.is_constant():
  483. return # can happen e.g. if we postpone the operation that becomes
  484. # constant
  485. # XXX kill, requires thinking
  486. #op = self.replace_op_with(op, op.opnum)
  487. for i in range(op.numargs()):
  488. arg = self.force_box(op.getarg(i))
  489. op.setarg(i, arg)
  490. self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS)
  491. if rop.is_guard(op.opnum):
  492. assert isinstance(op, GuardResOp)
  493. self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
  494. pendingfields = self.pendingfields
  495. self.pendingfields = None
  496. if self.replaces_guard and orig_op in self.replaces_guard:
  497. self.replace_guard_op(self.replaces_guard[orig_op], op)
  498. del self.replaces_guard[orig_op]
  499. return
  500. else:
  501. op = self.emit_guard_operation(op, pendingfields)
  502. elif op.can_raise():
  503. self.exception_might_have_happened = True
  504. opnum = op.opnum
  505. if ((rop.has_no_side_effect(opnum) or rop.is_guard(opnum) or
  506. rop.is_jit_debug(opnum) or
  507. rop.is_ovf(opnum)) and not self.is_call_pure_pure_canraise(op)):
  508. pass
  509. else:
  510. self._last_guard_op = None
  511. self._really_emitted_operation = op
  512. self._newoperations.append(op)
  513. def emit_guard_operation(self, op, pendingfields):
  514. guard_op = op # self.replace_op_with(op, op.getopnum())
  515. opnum = guard_op.getopnum()
  516. # If guard_(no)_exception is merged with another previous guard, then
  517. # it *should* be in "some_call;guard_not_forced;guard_(no)_exception".
  518. # The guard_(no)_exception can also occur at different places,
  519. # but these should not be preceeded immediately by another guard.
  520. # Sadly, asserting this seems to fail in rare cases. So instead,
  521. # we simply give up sharing.
  522. if (opnum in (rop.GUARD_NO_EXCEPTION, rop.GUARD_EXCEPTION) and
  523. self._last_guard_op is not None and
  524. self._last_guard_op.getopnum() != rop.GUARD_NOT_FORCED):
  525. self._last_guard_op = None
  526. #
  527. if (self._last_guard_op and guard_op.getdescr() is None):
  528. self.metainterp_sd.profiler.count_ops(opnum,
  529. jitprof.Counters.OPT_GUARDS_SHARED)
  530. op = self._copy_resume_data_from(guard_op,
  531. self._last_guard_op)
  532. else:
  533. op = self.store_final_boxes_in_guard(guard_op, pendingfields)
  534. self._last_guard_op = op
  535. # for unrolling
  536. for farg in op.getfailargs():
  537. if farg:
  538. self.force_box(farg)
  539. if op.getopnum() == rop.GUARD_EXCEPTION:
  540. self._last_guard_op = None
  541. return op
  542. def potentially_change_ovf_op_to_no_ovf(self, op):
  543. # if last emitted operations was int_xxx_ovf and we are not emitting
  544. # a guard_no_overflow change to int_add
  545. if op.getopnum() != rop.GUARD_NO_OVERFLOW:
  546. return
  547. if not self._newoperations:
  548. # got optimized otherwise
  549. return
  550. op = self._newoperations[-1]
  551. if not op.is_ovf():
  552. return
  553. newop = self.replace_op_with_no_ovf(op)
  554. self._newoperations[-1] = newop
  555. def replace_op_with_no_ovf(self, op):
  556. if op.getopnum() == rop.INT_MUL_OVF:
  557. return self.replace_op_with(op, rop.INT_MUL)
  558. elif op.getopnum() == rop.INT_ADD_OVF:
  559. return self.replace_op_with(op, rop.INT_ADD)
  560. elif op.getopnum() == rop.INT_SUB_OVF:
  561. return self.replace_op_with(op, rop.INT_SUB)
  562. else:
  563. assert False
  564. def _copy_resume_data_from(self, guard_op, last_guard_op):
  565. descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self, True)
  566. last_descr = last_guard_op.getdescr()
  567. assert isinstance(last_descr, compile.ResumeGuardDescr)
  568. if isinstance(descr, compile.ResumeGuardCopiedDescr):
  569. descr.prev = last_descr
  570. else:
  571. descr.copy_all_attributes_from(last_descr)
  572. guard_op.setdescr(descr)
  573. guard_op.setfailargs(last_guard_op.getfailargs())
  574. descr.store_hash(self.metainterp_sd)
  575. assert isinstance(guard_op, GuardResOp)
  576. if guard_op.getopnum() == rop.GUARD_VALUE:
  577. guard_op = self._maybe_replace_guard_value(guard_op, descr)
  578. return guard_op
  579. def getlastop(self):
  580. return self._really_emitted_operation
  581. def is_call_pure_pure_canraise(self, op):
  582. if not rop.is_call_pure(op.getopnum()):
  583. return False
  584. effectinfo = op.getdescr().get_extra_info()
  585. if effectinfo.check_can_raise(ignore_memoryerror=True):
  586. return True
  587. return False
  588. def replace_guard_op(self, old_op_pos, new_op):
  589. old_op = self._newoperations[old_op_pos]
  590. assert old_op.is_guard()
  591. old_descr = old_op.getdescr()
  592. new_descr = new_op.getdescr()
  593. new_descr.copy_all_attributes_from(old_descr)
  594. self._newoperations[old_op_pos] = new_op
  595. def store_final_boxes_in_guard(self, op, pendingfields):
  596. assert pendingfields is not None
  597. if op.getdescr() is not None:
  598. descr = op.getdescr()
  599. assert isinstance(descr, compile.ResumeGuardDescr)
  600. else:
  601. descr = compile.invent_fail_descr_for_op(op.getopnum(), self)
  602. op.setdescr(descr)
  603. assert isinstance(descr, compile.ResumeGuardDescr)
  604. assert isinstance(op, GuardResOp)
  605. modifier = resume.ResumeDataVirtualAdder(self, descr, op, self.trace,
  606. self.resumedata_memo)
  607. try:
  608. newboxes = modifier.finish(self, pendingfields)
  609. if (newboxes is not None and
  610. len(newboxes) > self.metainterp_sd.options.failargs_limit):
  611. raise resume.TagOverflow
  612. except resume.TagOverflow:
  613. raise compile.giveup()
  614. # check no duplicates
  615. #if not we_are_translated():
  616. seen = {}
  617. for box in newboxes:
  618. if box is not None:
  619. assert box not in seen
  620. seen[box] = None
  621. descr.store_final_boxes(op, newboxes, self.metainterp_sd)
  622. #
  623. if op.getopnum() == rop.GUARD_VALUE:
  624. op = self._maybe_replace_guard_value(op, descr)
  625. return op
  626. def _maybe_replace_guard_value(self, op, descr):
  627. if op.getarg(0).type == 'i':
  628. b = self.getintbound(op.getarg(0))
  629. if b.is_bool():
  630. # Hack: turn guard_value(bool) into guard_true/guard_false.
  631. # This is done after the operation is emitted to let
  632. # store_final_boxes_in_guard set the guard_opnum field of
  633. # the descr to the original rop.GUARD_VALUE.
  634. constvalue = op.getarg(1).getint()
  635. if constvalue == 0:
  636. opnum = rop.GUARD_FALSE
  637. elif constvalue == 1:
  638. opnum = rop.GUARD_TRUE
  639. else:
  640. raise AssertionError("uh?")
  641. newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr)
  642. return newop
  643. return op
  644. def optimize_default(self, op):
  645. self.emit_operation(op)
  646. def constant_fold(self, op):
  647. self.protect_speculative_operation(op)
  648. argboxes = [self.get_constant_box(op.getarg(i))
  649. for i in range(op.numargs())]
  650. return execute_nonspec_const(self.cpu, None,
  651. op.getopnum(), argboxes,
  652. op.getdescr(), op.type)
  653. def protect_speculative_operation(self, op):
  654. """When constant-folding a pure operation that reads memory from
  655. a gcref, make sure that the gcref is non-null and of a valid type.
  656. Otherwise, raise SpeculativeError. This should only occur when
  657. unrolling and optimizing the unrolled loop. Note that if
  658. cpu.supports_guard_gc_type is false, we can't really do this
  659. check at all, but then we don't unroll in that case.
  660. """
  661. opnum = op.getopnum()
  662. cpu = self.cpu
  663. if OpHelpers.is_pure_getfield(opnum, op.getdescr()):
  664. fielddescr = op.getdescr()
  665. ref = self.get_constant_box(op.getarg(0)).getref_base()
  666. cpu.protect_speculative_field(ref, fielddescr)
  667. return
  668. elif (opnum == rop.GETARRAYITEM_GC_PURE_I or
  669. opnum == rop.GETARRAYITEM_GC_PURE_R or
  670. opnum == rop.GETARRAYITEM_GC_PURE_F or
  671. opnum == rop.ARRAYLEN_GC):
  672. arraydescr = op.getdescr()
  673. array = self.get_constant_box(op.getarg(0)).getref_base()
  674. cpu.protect_speculative_array(array, arraydescr)
  675. if opnum == rop.ARRAYLEN_GC:
  676. return
  677. arraylength = cpu.bh_arraylen_gc(array, arraydescr)
  678. elif (opnum == rop.STRGETITEM or
  679. opnum == rop.STRLEN):
  680. string = self.get_constant_box(op.getarg(0)).getref_base()
  681. cpu.protect_speculative_string(string)
  682. if opnum == rop.STRLEN:
  683. return
  684. arraylength = cpu.bh_strlen(string)
  685. elif (opnum == rop.UNICODEGETITEM or
  686. opnum == rop.UNICODELEN):
  687. unicode = self.get_constant_box(op.getarg(0)).getref_base()
  688. cpu.protect_speculative_unicode(unicode)
  689. if opnum == rop.UNICODELEN:
  690. return
  691. arraylength = cpu.bh_unicodelen(unicode)
  692. else:
  693. return
  694. index = self.get_constant_box(op.getarg(1)).getint()
  695. if not (0 <= index < arraylength):
  696. raise SpeculativeError
  697. def is_virtual(self, op):
  698. if op.type == 'r':
  699. opinfo = self.getptrinfo(op)
  700. return opinfo is not None and opinfo.is_virtual()
  701. if op.type == 'i':
  702. opinfo = self.getrawptrinfo(op)
  703. return opinfo is not None and opinfo.is_virtual()
  704. return False
  705. def pure_reverse(self, op):
  706. import sys
  707. if self.optpure is None:
  708. return
  709. optpure = self.optpure
  710. if op.getopnum() == rop.INT_ADD:
  711. arg0 = op.getarg(0)
  712. arg1 = op.getarg(1)
  713. optpure.pure_from_args(rop.INT_ADD, [arg1, arg0], op)
  714. # Synthesize the reverse op for optimize_default to reuse
  715. optpure.pure_from_args(rop.INT_SUB, [op, arg1], arg0)
  716. optpure.pure_from_args(rop.INT_SUB, [op, arg0], arg1)
  717. if isinstance(arg0, ConstInt):
  718. # invert the constant
  719. i0 = arg0.getint()
  720. if i0 == -sys.maxint - 1:
  721. return
  722. inv_arg0 = ConstInt(-i0)
  723. elif isinstance(arg1, ConstInt):
  724. # commutative
  725. i0 = arg1.getint()
  726. if i0 == -sys.maxint - 1:
  727. return
  728. inv_arg0 = ConstInt(-i0)
  729. arg1 = arg0
  730. else:
  731. return
  732. optpure.pure_from_args(rop.INT_SUB, [arg1, inv_arg0], op)
  733. optpure.pure_from_args(rop.INT_SUB, [arg1, op], inv_arg0)
  734. optpure.pure_from_args(rop.INT_ADD, [op, inv_arg0], arg1)
  735. optpure.pure_from_args(rop.INT_ADD, [inv_arg0, op], arg1)
  736. elif op.getopnum() == rop.INT_SUB:
  737. arg0 = op.getarg(0)
  738. arg1 = op.getarg(1)
  739. optpure.pure_from_args(rop.INT_ADD, [op, arg1], arg0)
  740. optpure.pure_from_args(rop.INT_SUB, [arg0, op], arg1)
  741. if isinstance(arg1, ConstInt):
  742. # invert the constant
  743. i1 = arg1.getint()
  744. if i1 == -sys.maxint - 1:
  745. return
  746. inv_arg1 = ConstInt(-i1)
  747. optpure.pure_from_args(rop.INT_ADD, [arg0, inv_arg1], op)
  748. optpure.pure_from_args(rop.INT_ADD, [inv_arg1, arg0], op)
  749. optpure.pure_from_args(rop.INT_SUB, [op, inv_arg1], arg0)
  750. optpure.pure_from_args(rop.INT_SUB, [op, arg0], inv_arg1)
  751. elif op.getopnum() == rop.FLOAT_MUL:
  752. optpure.pure_from_args(rop.FLOAT_MUL,
  753. [op.getarg(1), op.getarg(0)], op)
  754. elif op.getopnum() == rop.FLOAT_NEG:
  755. optpure.pure_from_args(rop.FLOAT_NEG, [op], op.getarg(0))
  756. elif op.getopnum() == rop.CAST_INT_TO_PTR:
  757. optpure.pure_from_args(rop.CAST_PTR_TO_INT, [op], op.getarg(0))
  758. elif op.getopnum() == rop.CAST_PTR_TO_INT:
  759. optpure.pure_from_args(rop.CAST_INT_TO_PTR, [op], op.getarg(0))
  760. #def optimize_GUARD_NO_OVERFLOW(self, op):
  761. # # otherwise the default optimizer will clear fields, which is unwanted
  762. # # in this case
  763. # self.emit_operation(op)
  764. # FIXME: Is this still needed?
  765. def optimize_DEBUG_MERGE_POINT(self, op):
  766. self.emit_operation(op)
  767. def optimize_JIT_DEBUG(self, op):
  768. self.emit_operation(op)
  769. def optimize_STRGETITEM(self, op):
  770. indexb = self.getintbound(op.getarg(1))
  771. if indexb.is_constant():
  772. pass
  773. #raise Exception("implement me")
  774. #arrayvalue = self.getvalue(op.getarg(0))
  775. #arrayvalue.make_len_gt(MODE_STR, op.getdescr(), indexvalue.box.getint())
  776. self.optimize_default(op)
  777. def optimize_UNICODEGETITEM(self, op):
  778. indexb = self.getintbound(op.getarg(1))
  779. if indexb.is_constant():
  780. #arrayvalue = self.getvalue(op.getarg(0))
  781. #arrayvalue.make_len_gt(MODE_UNICODE, op.getdescr(), indexvalue.box.getint())
  782. pass
  783. self.optimize_default(op)
  784. # These are typically removed already by OptRewrite, but it can be
  785. # dissabled and unrolling emits some SAME_AS ops to setup the
  786. # optimizier state. These needs to always be optimized out.
  787. def optimize_SAME_AS_I(self, op):
  788. self.make_equal_to(op, op.getarg(0))
  789. optimize_SAME_AS_R = optimize_SAME_AS_I
  790. optimize_SAME_AS_F = optimize_SAME_AS_I
  791. dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_',
  792. default=Optimizer.optimize_default)