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

/rpython/jit/metainterp/optimizeopt/rewrite.py

https://bitbucket.org/pypy/pypy/
Python | 787 lines | 651 code | 74 blank | 62 comment | 195 complexity | 32ce9eb227d1ab097368fd4666081de9 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.jit.codewriter.effectinfo import EffectInfo
  2. from rpython.jit.codewriter import longlong
  3. from rpython.jit.metainterp import compile
  4. from rpython.jit.metainterp.history import (Const, ConstInt, make_hashable_int,
  5. ConstFloat)
  6. from rpython.jit.metainterp.optimize import InvalidLoop
  7. from rpython.jit.metainterp.optimizeopt.intutils import IntBound
  8. from rpython.jit.metainterp.optimizeopt.optimizer import (Optimization, REMOVED,
  9. CONST_0, CONST_1)
  10. from rpython.jit.metainterp.optimizeopt.info import INFO_NONNULL, INFO_NULL
  11. from rpython.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method
  12. from rpython.jit.metainterp.resoperation import rop, ResOperation, opclasses,\
  13. OpHelpers
  14. from rpython.rlib.rarithmetic import highest_bit
  15. from rpython.rtyper.lltypesystem import llmemory
  16. from rpython.rtyper import rclass
  17. import math
  18. class OptRewrite(Optimization):
  19. """Rewrite operations into equivalent, cheaper operations.
  20. This includes already executed operations and constants.
  21. """
  22. def __init__(self):
  23. self.loop_invariant_results = {}
  24. self.loop_invariant_producer = {}
  25. def setup(self):
  26. self.optimizer.optrewrite = self
  27. def produce_potential_short_preamble_ops(self, sb):
  28. for op in self.loop_invariant_producer.values():
  29. sb.add_loopinvariant_op(op)
  30. def propagate_forward(self, op):
  31. if opclasses[op.opnum].boolinverse != -1 or opclasses[op.opnum].boolreflex != -1:
  32. if self.find_rewritable_bool(op):
  33. return
  34. dispatch_opt(self, op)
  35. def try_boolinvers(self, op, targs):
  36. oldop = self.get_pure_result(targs)
  37. if oldop is not None:
  38. b = self.getintbound(oldop)
  39. if b.equal(1):
  40. self.make_constant(op, CONST_0)
  41. return True
  42. elif b.equal(0):
  43. self.make_constant(op, CONST_1)
  44. return True
  45. return False
  46. def find_rewritable_bool(self, op):
  47. oldopnum = op.boolinverse
  48. arg0 = op.getarg(0)
  49. arg1 = op.getarg(1)
  50. if oldopnum != -1:
  51. top = ResOperation(oldopnum, [arg0, arg1])
  52. if self.try_boolinvers(op, top):
  53. return True
  54. oldopnum = op.boolreflex # FIXME: add INT_ADD, INT_MUL
  55. if oldopnum != -1:
  56. top = ResOperation(oldopnum, [arg1, arg0])
  57. oldop = self.get_pure_result(top)
  58. if oldop is not None:
  59. self.optimizer.make_equal_to(op, oldop)
  60. return True
  61. if op.boolreflex == -1:
  62. return False
  63. oldopnum = opclasses[op.boolreflex].boolinverse
  64. if oldopnum != -1:
  65. top = ResOperation(oldopnum, [arg1, arg0])
  66. if self.try_boolinvers(op, top):
  67. return True
  68. return False
  69. def optimize_INT_AND(self, op):
  70. b1 = self.getintbound(op.getarg(0))
  71. b2 = self.getintbound(op.getarg(1))
  72. if b1.equal(0) or b2.equal(0):
  73. self.make_constant_int(op, 0)
  74. return
  75. elif b2.is_constant():
  76. val = b2.lower
  77. if val == -1 or b1.lower >= 0 \
  78. and b1.upper <= val & ~(val + 1):
  79. self.make_equal_to(op, op.getarg(0))
  80. return
  81. elif b1.is_constant():
  82. val = b1.lower
  83. if val == -1 or b2.lower >= 0 \
  84. and b2.upper <= val & ~(val + 1):
  85. self.make_equal_to(op, op.getarg(1))
  86. return
  87. self.emit_operation(op)
  88. def optimize_INT_OR(self, op):
  89. b1 = self.getintbound(op.getarg(0))
  90. b2 = self.getintbound(op.getarg(1))
  91. if b1.equal(0):
  92. self.make_equal_to(op, op.getarg(1))
  93. elif b2.equal(0):
  94. self.make_equal_to(op, op.getarg(0))
  95. else:
  96. self.emit_operation(op)
  97. def optimize_INT_SUB(self, op):
  98. arg1 = self.get_box_replacement(op.getarg(0))
  99. arg2 = self.get_box_replacement(op.getarg(1))
  100. b1 = self.getintbound(arg1)
  101. b2 = self.getintbound(arg2)
  102. if b2.equal(0):
  103. self.make_equal_to(op, arg1)
  104. elif b1.equal(0):
  105. op = self.replace_op_with(op, rop.INT_NEG, args=[arg2])
  106. self.emit_operation(op)
  107. elif arg1 == arg2:
  108. self.make_constant_int(op, 0)
  109. else:
  110. self.emit_operation(op)
  111. self.optimizer.pure_reverse(op)
  112. def optimize_INT_ADD(self, op):
  113. if self.is_raw_ptr(op.getarg(0)) or self.is_raw_ptr(op.getarg(1)):
  114. self.emit_operation(op)
  115. return
  116. arg1 = self.get_box_replacement(op.getarg(0))
  117. b1 = self.getintbound(arg1)
  118. arg2 = self.get_box_replacement(op.getarg(1))
  119. b2 = self.getintbound(arg2)
  120. # If one side of the op is 0 the result is the other side.
  121. if b1.equal(0):
  122. self.make_equal_to(op, arg2)
  123. elif b2.equal(0):
  124. self.make_equal_to(op, arg1)
  125. else:
  126. self.emit_operation(op)
  127. self.optimizer.pure_reverse(op)
  128. def optimize_INT_MUL(self, op):
  129. arg1 = self.get_box_replacement(op.getarg(0))
  130. b1 = self.getintbound(arg1)
  131. arg2 = self.get_box_replacement(op.getarg(1))
  132. b2 = self.getintbound(arg2)
  133. # If one side of the op is 1 the result is the other side.
  134. if b1.equal(1):
  135. self.make_equal_to(op, arg2)
  136. elif b2.equal(1):
  137. self.make_equal_to(op, arg1)
  138. elif b1.equal(0) or b2.equal(0):
  139. self.make_constant_int(op, 0)
  140. else:
  141. for lhs, rhs in [(arg1, arg2), (arg2, arg1)]:
  142. lh_info = self.getintbound(lhs)
  143. if lh_info.is_constant():
  144. x = lh_info.getint()
  145. # x & (x - 1) == 0 is a quick test for power of 2
  146. if x & (x - 1) == 0:
  147. new_rhs = ConstInt(highest_bit(lh_info.getint()))
  148. op = self.replace_op_with(op, rop.INT_LSHIFT, args=[rhs, new_rhs])
  149. break
  150. self.emit_operation(op)
  151. def _optimize_CALL_INT_UDIV(self, op):
  152. b2 = self.getintbound(op.getarg(2))
  153. if b2.is_constant() and b2.getint() == 1:
  154. self.make_equal_to(op, op.getarg(1))
  155. self.last_emitted_operation = REMOVED
  156. return True
  157. return False
  158. def optimize_INT_LSHIFT(self, op):
  159. b1 = self.getintbound(op.getarg(0))
  160. b2 = self.getintbound(op.getarg(1))
  161. if b2.is_constant() and b2.getint() == 0:
  162. self.make_equal_to(op, op.getarg(0))
  163. elif b1.is_constant() and b1.getint() == 0:
  164. self.make_constant_int(op, 0)
  165. else:
  166. self.emit_operation(op)
  167. def optimize_INT_RSHIFT(self, op):
  168. b1 = self.getintbound(op.getarg(0))
  169. b2 = self.getintbound(op.getarg(1))
  170. if b2.is_constant() and b2.getint() == 0:
  171. self.make_equal_to(op, op.getarg(0))
  172. elif b1.is_constant() and b1.getint() == 0:
  173. self.make_constant_int(op, 0)
  174. else:
  175. self.emit_operation(op)
  176. def optimize_INT_XOR(self, op):
  177. b1 = self.getintbound(op.getarg(0))
  178. b2 = self.getintbound(op.getarg(1))
  179. if b1.equal(0):
  180. self.make_equal_to(op, op.getarg(1))
  181. elif b2.equal(0):
  182. self.make_equal_to(op, op.getarg(0))
  183. else:
  184. self.emit_operation(op)
  185. def optimize_FLOAT_MUL(self, op):
  186. arg1 = op.getarg(0)
  187. arg2 = op.getarg(1)
  188. # Constant fold f0 * 1.0 and turn f0 * -1.0 into a FLOAT_NEG, these
  189. # work in all cases, including NaN and inf
  190. for lhs, rhs in [(arg1, arg2), (arg2, arg1)]:
  191. v1 = self.get_box_replacement(lhs)
  192. v2 = self.get_box_replacement(rhs)
  193. if v1.is_constant():
  194. if v1.getfloat() == 1.0:
  195. self.make_equal_to(op, v2)
  196. return
  197. elif v1.getfloat() == -1.0:
  198. newop = self.replace_op_with(op, rop.FLOAT_NEG, args=[rhs])
  199. self.emit_operation(newop)
  200. return
  201. self.emit_operation(op)
  202. self.optimizer.pure_reverse(op)
  203. def optimize_FLOAT_TRUEDIV(self, op):
  204. arg1 = op.getarg(0)
  205. arg2 = op.getarg(1)
  206. v2 = self.get_box_replacement(arg2)
  207. # replace "x / const" by "x * (1/const)" if possible
  208. newop = op
  209. if v2.is_constant():
  210. divisor = v2.getfloat()
  211. fraction = math.frexp(divisor)[0]
  212. # This optimization is valid for powers of two
  213. # but not for zeroes, some denormals and NaN:
  214. if fraction == 0.5 or fraction == -0.5:
  215. reciprocal = 1.0 / divisor
  216. rfraction = math.frexp(reciprocal)[0]
  217. if rfraction == 0.5 or rfraction == -0.5:
  218. c = ConstFloat(longlong.getfloatstorage(reciprocal))
  219. newop = self.replace_op_with(op, rop.FLOAT_MUL,
  220. args=[arg1, c])
  221. self.emit_operation(newop)
  222. def optimize_FLOAT_NEG(self, op):
  223. self.emit_operation(op)
  224. self.optimizer.pure_reverse(op)
  225. def optimize_guard(self, op, constbox, emit_operation=True):
  226. box = op.getarg(0)
  227. if box.type == 'i':
  228. intbound = self.getintbound(box)
  229. if intbound.is_constant():
  230. if not intbound.getint() == constbox.getint():
  231. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(
  232. op)
  233. raise InvalidLoop('A GUARD_{VALUE,TRUE,FALSE} (%s) '
  234. 'was proven to always fail' % r)
  235. return
  236. elif box.type == 'r':
  237. box = self.get_box_replacement(box)
  238. if box.is_constant():
  239. if not box.same_constant(constbox):
  240. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(
  241. op)
  242. raise InvalidLoop('A GUARD_VALUE (%s) '
  243. 'was proven to always fail' % r)
  244. return
  245. if emit_operation:
  246. self.emit_operation(op)
  247. self.make_constant(box, constbox)
  248. #if self.optimizer.optheap: XXX
  249. # self.optimizer.optheap.value_updated(value, self.getvalue(constbox))
  250. def optimize_GUARD_ISNULL(self, op):
  251. info = self.getptrinfo(op.getarg(0))
  252. if info is not None:
  253. if info.is_null():
  254. return
  255. elif info.is_nonnull():
  256. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
  257. raise InvalidLoop('A GUARD_ISNULL (%s) was proven to always '
  258. 'fail' % r)
  259. self.emit_operation(op)
  260. self.make_constant(op.getarg(0), self.optimizer.cpu.ts.CONST_NULL)
  261. def optimize_GUARD_IS_OBJECT(self, op):
  262. info = self.getptrinfo(op.getarg(0))
  263. if info and info.is_constant():
  264. if info.is_null():
  265. raise InvalidLoop("A GUARD_IS_OBJECT(NULL) found")
  266. c = self.get_box_replacement(op.getarg(0))
  267. if self.optimizer.cpu.check_is_object(c.getref_base()):
  268. return
  269. raise InvalidLoop("A GUARD_IS_OBJECT(not-an-object) found")
  270. if info is not None:
  271. if info.is_about_object():
  272. return
  273. if info.is_precise():
  274. raise InvalidLoop()
  275. self.emit_operation(op)
  276. def optimize_GUARD_GC_TYPE(self, op):
  277. info = self.getptrinfo(op.getarg(0))
  278. if info and info.is_constant():
  279. c = self.get_box_replacement(op.getarg(0))
  280. tid = self.optimizer.cpu.get_actual_typeid(c.getref_base())
  281. if tid != op.getarg(1).getint():
  282. raise InvalidLoop("wrong GC type ID found on a constant")
  283. return
  284. if info is not None and info.get_descr() is not None:
  285. if info.get_descr().get_type_id() != op.getarg(1).getint():
  286. raise InvalidLoop("wrong GC types passed around!")
  287. return
  288. self.emit_operation(op)
  289. def _check_subclass(self, vtable1, vtable2):
  290. # checks that vtable1 is a subclass of vtable2
  291. known_class = llmemory.cast_adr_to_ptr(
  292. llmemory.cast_int_to_adr(vtable1),
  293. rclass.CLASSTYPE)
  294. expected_class = llmemory.cast_adr_to_ptr(
  295. llmemory.cast_int_to_adr(vtable2),
  296. rclass.CLASSTYPE)
  297. if (expected_class.subclassrange_min
  298. <= known_class.subclassrange_min
  299. <= expected_class.subclassrange_max):
  300. return True
  301. return False
  302. def optimize_GUARD_SUBCLASS(self, op):
  303. info = self.getptrinfo(op.getarg(0))
  304. if info and info.is_constant():
  305. c = self.get_box_replacement(op.getarg(0))
  306. vtable = self.optimizer.cpu.ts.cls_of_box(c).getint()
  307. if self._check_subclass(vtable, op.getarg(1).getint()):
  308. return
  309. raise InvalidLoop("GUARD_SUBCLASS(const) proven to always fail")
  310. if info is not None and info.is_about_object():
  311. known_class = info.get_known_class(self.optimizer.cpu)
  312. if known_class:
  313. if self._check_subclass(known_class.getint(),
  314. op.getarg(1).getint()):
  315. return
  316. elif info.get_descr() is not None:
  317. if self._check_subclass(info.get_descr().get_vtable(),
  318. op.getarg(1).getint()):
  319. return
  320. self.emit_operation(op)
  321. def optimize_GUARD_NONNULL(self, op):
  322. opinfo = self.getptrinfo(op.getarg(0))
  323. if opinfo is not None:
  324. if opinfo.is_nonnull():
  325. return
  326. elif opinfo.is_null():
  327. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
  328. raise InvalidLoop('A GUARD_NONNULL (%s) was proven to always '
  329. 'fail' % r)
  330. self.emit_operation(op)
  331. self.make_nonnull(op.getarg(0))
  332. self.getptrinfo(op.getarg(0)).mark_last_guard(self.optimizer)
  333. def optimize_GUARD_VALUE(self, op):
  334. arg0 = op.getarg(0)
  335. if arg0.type == 'r':
  336. info = self.getptrinfo(arg0)
  337. if info:
  338. if info.is_virtual():
  339. raise InvalidLoop("promote of a virtual")
  340. old_guard_op = info.get_last_guard(self.optimizer)
  341. if old_guard_op is not None:
  342. op = self.replace_old_guard_with_guard_value(op, info,
  343. old_guard_op)
  344. elif arg0.type == 'f':
  345. arg0 = self.get_box_replacement(arg0)
  346. if arg0.is_constant():
  347. return
  348. constbox = op.getarg(1)
  349. assert isinstance(constbox, Const)
  350. self.optimize_guard(op, constbox)
  351. def replace_old_guard_with_guard_value(self, op, info, old_guard_op):
  352. # there already has been a guard_nonnull or guard_class or
  353. # guard_nonnull_class on this value, which is rather silly.
  354. # This function replaces the original guard with a
  355. # guard_value. Must be careful: doing so is unsafe if the
  356. # original guard checks for something inconsistent,
  357. # i.e. different than what it would give if the guard_value
  358. # passed (this is a rare case, but possible). If we get
  359. # inconsistent results in this way, then we must not do the
  360. # replacement, otherwise we'd put guard_value up there but all
  361. # intermediate ops might be executed by assuming something
  362. # different, from the old guard that is now removed...
  363. c_value = op.getarg(1)
  364. if not c_value.nonnull():
  365. raise InvalidLoop('A GUARD_VALUE(..., NULL) follows some other '
  366. 'guard that it is not NULL')
  367. previous_classbox = info.get_known_class(self.optimizer.cpu)
  368. if previous_classbox is not None:
  369. expected_classbox = self.optimizer.cpu.ts.cls_of_box(c_value)
  370. assert expected_classbox is not None
  371. if not previous_classbox.same_constant(
  372. expected_classbox):
  373. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
  374. raise InvalidLoop('A GUARD_VALUE (%s) was proven to '
  375. 'always fail' % r)
  376. descr = compile.ResumeGuardDescr()
  377. op = old_guard_op.copy_and_change(rop.GUARD_VALUE,
  378. args = [old_guard_op.getarg(0), op.getarg(1)],
  379. descr = descr)
  380. # Note: we give explicitly a new descr for 'op'; this is why the
  381. # old descr must not be ResumeAtPositionDescr (checked above).
  382. # Better-safe-than-sorry but it should never occur: we should
  383. # not put in short preambles guard_xxx and guard_value
  384. # on the same box.
  385. self.optimizer.replace_guard(op, info)
  386. # to be safe
  387. info.reset_last_guard_pos()
  388. return op
  389. def optimize_GUARD_TRUE(self, op):
  390. self.optimize_guard(op, CONST_1)
  391. def optimize_GUARD_FALSE(self, op):
  392. self.optimize_guard(op, CONST_0)
  393. def optimize_RECORD_EXACT_CLASS(self, op):
  394. opinfo = self.getptrinfo(op.getarg(0))
  395. expectedclassbox = op.getarg(1)
  396. assert isinstance(expectedclassbox, Const)
  397. if opinfo is not None:
  398. realclassbox = opinfo.get_known_class(self.optimizer.cpu)
  399. if realclassbox is not None:
  400. assert realclassbox.same_constant(expectedclassbox)
  401. return
  402. self.make_constant_class(op.getarg(0), expectedclassbox,
  403. update_last_guard=False)
  404. def optimize_GUARD_CLASS(self, op):
  405. expectedclassbox = op.getarg(1)
  406. info = self.ensure_ptr_info_arg0(op)
  407. assert isinstance(expectedclassbox, Const)
  408. realclassbox = info.get_known_class(self.optimizer.cpu)
  409. if realclassbox is not None:
  410. if realclassbox.same_constant(expectedclassbox):
  411. return
  412. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
  413. raise InvalidLoop('A GUARD_CLASS (%s) was proven to always fail'
  414. % r)
  415. old_guard_op = info.get_last_guard(self.optimizer)
  416. if old_guard_op and not isinstance(old_guard_op.getdescr(),
  417. compile.ResumeAtPositionDescr):
  418. # there already has been a guard_nonnull or guard_class or
  419. # guard_nonnull_class on this value.
  420. if old_guard_op.getopnum() == rop.GUARD_NONNULL:
  421. # it was a guard_nonnull, which we replace with a
  422. # guard_nonnull_class.
  423. descr = compile.ResumeGuardDescr()
  424. op = old_guard_op.copy_and_change (rop.GUARD_NONNULL_CLASS,
  425. args = [old_guard_op.getarg(0), op.getarg(1)],
  426. descr=descr)
  427. # Note: we give explicitly a new descr for 'op'; this is why the
  428. # old descr must not be ResumeAtPositionDescr (checked above).
  429. # Better-safe-than-sorry but it should never occur: we should
  430. # not put in short preambles guard_nonnull and guard_class
  431. # on the same box.
  432. self.optimizer.replace_guard(op, info)
  433. self.emit_operation(op)
  434. self.make_constant_class(op.getarg(0), expectedclassbox, False)
  435. return
  436. self.emit_operation(op)
  437. self.make_constant_class(op.getarg(0), expectedclassbox)
  438. def optimize_GUARD_NONNULL_CLASS(self, op):
  439. info = self.getptrinfo(op.getarg(0))
  440. if info and info.is_null():
  441. r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
  442. raise InvalidLoop('A GUARD_NONNULL_CLASS (%s) was proven to '
  443. 'always fail' % r)
  444. self.optimize_GUARD_CLASS(op)
  445. def optimize_CALL_LOOPINVARIANT_I(self, op):
  446. arg = op.getarg(0)
  447. # 'arg' must be a Const, because residual_call in codewriter
  448. # expects a compile-time constant
  449. assert isinstance(arg, Const)
  450. key = make_hashable_int(arg.getint())
  451. resvalue = self.loop_invariant_results.get(key, None)
  452. if resvalue is not None:
  453. resvalue = self.optimizer.force_op_from_preamble(resvalue)
  454. self.loop_invariant_results[key] = resvalue
  455. self.make_equal_to(op, resvalue)
  456. self.last_emitted_operation = REMOVED
  457. return
  458. # change the op to be a normal call, from the backend's point of view
  459. # there is no reason to have a separate operation for this
  460. newop = self.replace_op_with(op,
  461. OpHelpers.call_for_descr(op.getdescr()))
  462. self.emit_operation(newop)
  463. self.loop_invariant_producer[key] = self.optimizer.getlastop()
  464. self.loop_invariant_results[key] = op
  465. optimize_CALL_LOOPINVARIANT_R = optimize_CALL_LOOPINVARIANT_I
  466. optimize_CALL_LOOPINVARIANT_F = optimize_CALL_LOOPINVARIANT_I
  467. optimize_CALL_LOOPINVARIANT_N = optimize_CALL_LOOPINVARIANT_I
  468. def optimize_COND_CALL(self, op):
  469. arg = op.getarg(0)
  470. b = self.getintbound(arg)
  471. if b.is_constant():
  472. if b.getint() == 0:
  473. self.last_emitted_operation = REMOVED
  474. return
  475. opnum = OpHelpers.call_for_type(op.type)
  476. op = op.copy_and_change(opnum, args=op.getarglist()[1:])
  477. self.emit_operation(op)
  478. def _optimize_nullness(self, op, box, expect_nonnull):
  479. info = self.getnullness(box)
  480. if info == INFO_NONNULL:
  481. self.make_constant_int(op, expect_nonnull)
  482. elif info == INFO_NULL:
  483. self.make_constant_int(op, not expect_nonnull)
  484. else:
  485. self.emit_operation(op)
  486. def optimize_INT_IS_TRUE(self, op):
  487. if (not self.is_raw_ptr(op.getarg(0)) and
  488. self.getintbound(op.getarg(0)).is_bool()):
  489. self.make_equal_to(op, op.getarg(0))
  490. return
  491. self._optimize_nullness(op, op.getarg(0), True)
  492. def optimize_INT_IS_ZERO(self, op):
  493. self._optimize_nullness(op, op.getarg(0), False)
  494. def _optimize_oois_ooisnot(self, op, expect_isnot, instance):
  495. arg0 = self.get_box_replacement(op.getarg(0))
  496. arg1 = self.get_box_replacement(op.getarg(1))
  497. info0 = self.getptrinfo(arg0)
  498. info1 = self.getptrinfo(arg1)
  499. if info0 and info0.is_virtual():
  500. if info1 and info1.is_virtual():
  501. intres = (info0 is info1) ^ expect_isnot
  502. self.make_constant_int(op, intres)
  503. else:
  504. self.make_constant_int(op, expect_isnot)
  505. elif info1 and info1.is_virtual():
  506. self.make_constant_int(op, expect_isnot)
  507. elif info1 and info1.is_null():
  508. self._optimize_nullness(op, op.getarg(0), expect_isnot)
  509. elif info0 and info0.is_null():
  510. self._optimize_nullness(op, op.getarg(1), expect_isnot)
  511. elif arg0 is arg1:
  512. self.make_constant_int(op, not expect_isnot)
  513. else:
  514. if instance:
  515. if info0 is None:
  516. cls0 = None
  517. else:
  518. cls0 = info0.get_known_class(self.optimizer.cpu)
  519. if cls0 is not None:
  520. if info1 is None:
  521. cls1 = None
  522. else:
  523. cls1 = info1.get_known_class(self.optimizer.cpu)
  524. if cls1 is not None and not cls0.same_constant(cls1):
  525. # cannot be the same object, as we know that their
  526. # class is different
  527. self.make_constant_int(op, expect_isnot)
  528. return
  529. self.emit_operation(op)
  530. def optimize_PTR_EQ(self, op):
  531. self._optimize_oois_ooisnot(op, False, False)
  532. def optimize_PTR_NE(self, op):
  533. self._optimize_oois_ooisnot(op, True, False)
  534. def optimize_INSTANCE_PTR_EQ(self, op):
  535. self._optimize_oois_ooisnot(op, False, True)
  536. def optimize_INSTANCE_PTR_NE(self, op):
  537. self._optimize_oois_ooisnot(op, True, True)
  538. def optimize_CALL_N(self, op):
  539. # dispatch based on 'oopspecindex' to a method that handles
  540. # specifically the given oopspec call. For non-oopspec calls,
  541. # oopspecindex is just zero.
  542. effectinfo = op.getdescr().get_extra_info()
  543. oopspecindex = effectinfo.oopspecindex
  544. if oopspecindex == EffectInfo.OS_ARRAYCOPY:
  545. if self._optimize_CALL_ARRAYCOPY(op):
  546. return
  547. self.emit_operation(op)
  548. def _optimize_CALL_ARRAYCOPY(self, op):
  549. length = self.get_constant_box(op.getarg(5))
  550. if length and length.getint() == 0:
  551. return True # 0-length arraycopy
  552. source_info = self.getptrinfo(op.getarg(1))
  553. dest_info = self.getptrinfo(op.getarg(2))
  554. source_start_box = self.get_constant_box(op.getarg(3))
  555. dest_start_box = self.get_constant_box(op.getarg(4))
  556. extrainfo = op.getdescr().get_extra_info()
  557. if (source_start_box and dest_start_box
  558. and length and ((dest_info and dest_info.is_virtual()) or
  559. length.getint() <= 8) and
  560. ((source_info and source_info.is_virtual()) or length.getint() <= 8)
  561. and extrainfo.single_write_descr_array is not None): #<-sanity check
  562. source_start = source_start_box.getint()
  563. dest_start = dest_start_box.getint()
  564. arraydescr = extrainfo.single_write_descr_array
  565. if arraydescr.is_array_of_structs():
  566. return False # not supported right now
  567. # XXX fish fish fish
  568. for index in range(length.getint()):
  569. if source_info and source_info.is_virtual():
  570. val = source_info.getitem(arraydescr, index + source_start)
  571. else:
  572. opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
  573. newop = ResOperation(opnum,
  574. [op.getarg(1),
  575. ConstInt(index + source_start)],
  576. descr=arraydescr)
  577. self.optimizer.send_extra_operation(newop)
  578. val = newop
  579. if val is None:
  580. continue
  581. if dest_info and dest_info.is_virtual():
  582. dest_info.setitem(arraydescr, index + dest_start,
  583. self.get_box_replacement(op.getarg(2)),
  584. val)
  585. else:
  586. newop = ResOperation(rop.SETARRAYITEM_GC,
  587. [op.getarg(2),
  588. ConstInt(index + dest_start),
  589. val],
  590. descr=arraydescr)
  591. self.emit_operation(newop)
  592. return True
  593. return False
  594. def optimize_CALL_PURE_I(self, op):
  595. # this removes a CALL_PURE with all constant arguments.
  596. # Note that it's also done in pure.py. For now we need both...
  597. result = self._can_optimize_call_pure(op)
  598. if result is not None:
  599. self.make_constant(op, result)
  600. self.last_emitted_operation = REMOVED
  601. return
  602. # dispatch based on 'oopspecindex' to a method that handles
  603. # specifically the given oopspec call.
  604. effectinfo = op.getdescr().get_extra_info()
  605. oopspecindex = effectinfo.oopspecindex
  606. if oopspecindex == EffectInfo.OS_INT_UDIV:
  607. if self._optimize_CALL_INT_UDIV(op):
  608. return
  609. elif oopspecindex == EffectInfo.OS_INT_PY_DIV:
  610. if self._optimize_CALL_INT_PY_DIV(op):
  611. return
  612. elif oopspecindex == EffectInfo.OS_INT_PY_MOD:
  613. if self._optimize_CALL_INT_PY_MOD(op):
  614. return
  615. self.emit_operation(op)
  616. optimize_CALL_PURE_R = optimize_CALL_PURE_I
  617. optimize_CALL_PURE_F = optimize_CALL_PURE_I
  618. optimize_CALL_PURE_N = optimize_CALL_PURE_I
  619. def optimize_GUARD_NO_EXCEPTION(self, op):
  620. if self.last_emitted_operation is REMOVED:
  621. # it was a CALL_PURE or a CALL_LOOPINVARIANT that was killed;
  622. # so we also kill the following GUARD_NO_EXCEPTION
  623. return
  624. self.emit_operation(op)
  625. def optimize_GUARD_FUTURE_CONDITION(self, op):
  626. self.optimizer.notice_guard_future_condition(op)
  627. def _optimize_CALL_INT_PY_DIV(self, op):
  628. arg1 = op.getarg(1)
  629. b1 = self.getintbound(arg1)
  630. arg2 = op.getarg(2)
  631. b2 = self.getintbound(arg2)
  632. if b1.is_constant() and b1.getint() == 0:
  633. self.make_constant_int(op, 0)
  634. self.last_emitted_operation = REMOVED
  635. return True
  636. # This is Python's integer division: 'x // (2**shift)' can always
  637. # be replaced with 'x >> shift', even for negative values of x
  638. if not b2.is_constant():
  639. return False
  640. val = b2.getint()
  641. if val <= 0:
  642. return False
  643. if val == 1:
  644. self.make_equal_to(op, arg1)
  645. self.last_emitted_operation = REMOVED
  646. return True
  647. elif val & (val - 1) == 0: # val == 2**shift
  648. from rpython.jit.metainterp.history import DONT_CHANGE
  649. op = self.replace_op_with(op, rop.INT_RSHIFT,
  650. args=[arg1, ConstInt(highest_bit(val))],
  651. descr=DONT_CHANGE) # <- xxx rename? means "kill"
  652. self.optimizer.send_extra_operation(op)
  653. return True
  654. else:
  655. from rpython.jit.metainterp.optimizeopt import intdiv
  656. known_nonneg = b1.known_ge(IntBound(0, 0))
  657. operations = intdiv.division_operations(arg1, val, known_nonneg)
  658. newop = None
  659. for newop in operations:
  660. self.optimizer.send_extra_operation(newop)
  661. self.make_equal_to(op, newop)
  662. return True
  663. def _optimize_CALL_INT_PY_MOD(self, op):
  664. arg1 = op.getarg(1)
  665. b1 = self.getintbound(arg1)
  666. arg2 = op.getarg(2)
  667. b2 = self.getintbound(arg2)
  668. if b1.is_constant() and b1.getint() == 0:
  669. self.make_constant_int(op, 0)
  670. self.last_emitted_operation = REMOVED
  671. return True
  672. # This is Python's integer division: 'x // (2**shift)' can always
  673. # be replaced with 'x >> shift', even for negative values of x
  674. if not b2.is_constant():
  675. return False
  676. val = b2.getint()
  677. if val <= 0:
  678. return False
  679. if val == 1:
  680. self.make_constant_int(op, 0)
  681. self.last_emitted_operation = REMOVED
  682. return True
  683. elif val & (val - 1) == 0: # val == 2**shift
  684. from rpython.jit.metainterp.history import DONT_CHANGE
  685. # x % power-of-two ==> x & (power-of-two - 1)
  686. # with Python's modulo, this is valid even if 'x' is negative.
  687. op = self.replace_op_with(op, rop.INT_AND,
  688. args=[arg1, ConstInt(val - 1)],
  689. descr=DONT_CHANGE) # <- xxx rename? means "kill"
  690. self.optimizer.send_extra_operation(op)
  691. return True
  692. else:
  693. from rpython.jit.metainterp.optimizeopt import intdiv
  694. known_nonneg = b1.known_ge(IntBound(0, 0))
  695. operations = intdiv.modulo_operations(arg1, val, known_nonneg)
  696. newop = None
  697. for newop in operations:
  698. self.optimizer.send_extra_operation(newop)
  699. self.make_equal_to(op, newop)
  700. return True
  701. def optimize_CAST_PTR_TO_INT(self, op):
  702. self.optimizer.pure_reverse(op)
  703. self.emit_operation(op)
  704. def optimize_CAST_INT_TO_PTR(self, op):
  705. self.optimizer.pure_reverse(op)
  706. self.emit_operation(op)
  707. def optimize_SAME_AS_I(self, op):
  708. self.make_equal_to(op, op.getarg(0))
  709. optimize_SAME_AS_R = optimize_SAME_AS_I
  710. optimize_SAME_AS_F = optimize_SAME_AS_I
  711. dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
  712. default=OptRewrite.emit_operation)
  713. optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')