PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/jit/metainterp/optimizeopt/intbounds.py

https://bitbucket.org/pypy/pypy/
Python | 636 lines | 523 code | 74 blank | 39 comment | 125 complexity | fbb401457f035a109295f4ad28205a55 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. from rpython.jit.metainterp.history import ConstInt
  3. from rpython.jit.metainterp.optimize import InvalidLoop
  4. from rpython.jit.metainterp.optimizeopt.intutils import (IntBound,
  5. IntLowerBound, IntUpperBound, ConstIntBound)
  6. from rpython.jit.metainterp.optimizeopt.optimizer import (Optimization, CONST_1,
  7. CONST_0)
  8. from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
  9. from rpython.jit.metainterp.resoperation import rop, AbstractResOp
  10. from rpython.jit.metainterp.optimizeopt import vstring
  11. from rpython.jit.codewriter.effectinfo import EffectInfo
  12. from rpython.rlib.rarithmetic import intmask
  13. def get_integer_min(is_unsigned, byte_size):
  14. if is_unsigned:
  15. return 0
  16. else:
  17. return -(1 << ((byte_size << 3) - 1))
  18. def get_integer_max(is_unsigned, byte_size):
  19. if is_unsigned:
  20. return (1 << (byte_size << 3)) - 1
  21. else:
  22. return (1 << ((byte_size << 3) - 1)) - 1
  23. IS_64_BIT = sys.maxint > 2**32
  24. def next_pow2_m1(n):
  25. """Calculate next power of 2 greater than n minus one."""
  26. n |= n >> 1
  27. n |= n >> 2
  28. n |= n >> 4
  29. n |= n >> 8
  30. n |= n >> 16
  31. if IS_64_BIT:
  32. n |= n >> 32
  33. return n
  34. class OptIntBounds(Optimization):
  35. """Keeps track of the bounds placed on integers by guards and remove
  36. redundant guards"""
  37. def propagate_forward(self, op):
  38. dispatch_opt(self, op)
  39. def opt_default(self, op):
  40. assert not op.is_ovf()
  41. self.emit_operation(op)
  42. def propagate_bounds_backward(self, box):
  43. # FIXME: This takes care of the instruction where box is the reuslt
  44. # but the bounds produced by all instructions where box is
  45. # an argument might also be tighten
  46. b = self.getintbound(box)
  47. if b.has_lower and b.has_upper and b.lower == b.upper:
  48. self.make_constant_int(box, b.lower)
  49. if isinstance(box, AbstractResOp):
  50. dispatch_bounds_ops(self, box)
  51. def _optimize_guard_true_false_value(self, op):
  52. self.emit_operation(op)
  53. if op.getarg(0).type == 'i':
  54. self.propagate_bounds_backward(op.getarg(0))
  55. optimize_GUARD_TRUE = _optimize_guard_true_false_value
  56. optimize_GUARD_FALSE = _optimize_guard_true_false_value
  57. optimize_GUARD_VALUE = _optimize_guard_true_false_value
  58. def optimize_INT_OR_or_XOR(self, op):
  59. v1 = self.get_box_replacement(op.getarg(0))
  60. b1 = self.getintbound(v1)
  61. v2 = self.get_box_replacement(op.getarg(1))
  62. b2 = self.getintbound(v2)
  63. if v1 is v2:
  64. if op.getopnum() == rop.INT_OR:
  65. self.make_equal_to(op, v1)
  66. else:
  67. self.make_constant_int(op, 0)
  68. return
  69. self.emit_operation(op)
  70. if b1.known_ge(IntBound(0, 0)) and \
  71. b2.known_ge(IntBound(0, 0)):
  72. r = self.getintbound(op)
  73. mostsignificant = b1.upper | b2.upper
  74. r.intersect(IntBound(0, next_pow2_m1(mostsignificant)))
  75. optimize_INT_OR = optimize_INT_OR_or_XOR
  76. optimize_INT_XOR = optimize_INT_OR_or_XOR
  77. def optimize_INT_AND(self, op):
  78. b1 = self.getintbound(op.getarg(0))
  79. b2 = self.getintbound(op.getarg(1))
  80. self.emit_operation(op)
  81. r = self.getintbound(op)
  82. pos1 = b1.known_ge(IntBound(0, 0))
  83. pos2 = b2.known_ge(IntBound(0, 0))
  84. if pos1 or pos2:
  85. r.make_ge(IntBound(0, 0))
  86. if pos1:
  87. r.make_le(b1)
  88. if pos2:
  89. r.make_le(b2)
  90. def optimize_INT_SUB(self, op):
  91. self.emit_operation(op)
  92. b1 = self.getintbound(op.getarg(0))
  93. b2 = self.getintbound(op.getarg(1))
  94. b = b1.sub_bound(b2)
  95. if b.bounded():
  96. self.getintbound(op).intersect(b)
  97. def optimize_INT_ADD(self, op):
  98. arg1 = self.get_box_replacement(op.getarg(0))
  99. arg2 = self.get_box_replacement(op.getarg(1))
  100. if self.is_raw_ptr(arg1) or self.is_raw_ptr(arg2):
  101. self.emit_operation(op)
  102. return
  103. v1 = self.getintbound(arg1)
  104. v2 = self.getintbound(arg2)
  105. # Optimize for addition chains in code "b = a + 1; c = b + 1" by
  106. # detecting the int_add chain, and swapping with "b = a + 1;
  107. # c = a + 2". If b is not used elsewhere, the backend eliminates
  108. # it.
  109. # either v1 or v2 can be a constant, swap the arguments around if
  110. # v1 is the constant
  111. if v1.is_constant():
  112. arg1, arg2 = arg2, arg1
  113. v1, v2 = v2, v1
  114. # if both are constant, the pure optimization will deal with it
  115. if v2.is_constant() and not v1.is_constant():
  116. if not self.optimizer.is_inputarg(arg1):
  117. if arg1.getopnum() == rop.INT_ADD:
  118. prod_arg1 = arg1.getarg(0)
  119. prod_arg2 = arg1.getarg(1)
  120. prod_v1 = self.getintbound(prod_arg1)
  121. prod_v2 = self.getintbound(prod_arg2)
  122. # same thing here: prod_v1 or prod_v2 can be a
  123. # constant
  124. if prod_v1.is_constant():
  125. prod_arg1, prod_arg2 = prod_arg2, prod_arg1
  126. prod_v1, prod_v2 = prod_v2, prod_v1
  127. if prod_v2.is_constant():
  128. sum = intmask(arg2.getint() + prod_arg2.getint())
  129. arg1 = prod_arg1
  130. arg2 = ConstInt(sum)
  131. op = self.replace_op_with(op, rop.INT_ADD, args=[arg1, arg2])
  132. self.emit_operation(op)
  133. b1 = self.getintbound(op.getarg(0))
  134. b2 = self.getintbound(op.getarg(1))
  135. r = self.getintbound(op)
  136. b = b1.add_bound(b2)
  137. if b.bounded():
  138. r.intersect(b)
  139. def optimize_INT_MUL(self, op):
  140. b1 = self.getintbound(op.getarg(0))
  141. b2 = self.getintbound(op.getarg(1))
  142. self.emit_operation(op)
  143. r = self.getintbound(op)
  144. b = b1.mul_bound(b2)
  145. if b.bounded():
  146. r.intersect(b)
  147. def optimize_CALL_PURE_I(self, op):
  148. # dispatch based on 'oopspecindex' to a method that handles
  149. # specifically the given oopspec call.
  150. effectinfo = op.getdescr().get_extra_info()
  151. oopspecindex = effectinfo.oopspecindex
  152. if oopspecindex == EffectInfo.OS_INT_PY_DIV:
  153. self.opt_call_INT_PY_DIV(op)
  154. return
  155. elif oopspecindex == EffectInfo.OS_INT_PY_MOD:
  156. self.opt_call_INT_PY_MOD(op)
  157. return
  158. self.emit_operation(op)
  159. def opt_call_INT_PY_DIV(self, op):
  160. b1 = self.getintbound(op.getarg(1))
  161. b2 = self.getintbound(op.getarg(2))
  162. self.emit_operation(op)
  163. r = self.getintbound(op)
  164. r.intersect(b1.py_div_bound(b2))
  165. def opt_call_INT_PY_MOD(self, op):
  166. b1 = self.getintbound(op.getarg(1))
  167. b2 = self.getintbound(op.getarg(2))
  168. self.emit_operation(op)
  169. if b2.is_constant():
  170. val = b2.getint()
  171. r = self.getintbound(op)
  172. if val >= 0: # with Python's modulo: 0 <= (x % pos) < pos
  173. r.make_ge(IntBound(0, 0))
  174. r.make_lt(IntBound(val, val))
  175. else: # with Python's modulo: neg < (x % neg) <= 0
  176. r.make_gt(IntBound(val, val))
  177. r.make_le(IntBound(0, 0))
  178. def optimize_INT_LSHIFT(self, op):
  179. arg0 = self.get_box_replacement(op.getarg(0))
  180. b1 = self.getintbound(arg0)
  181. arg1 = self.get_box_replacement(op.getarg(1))
  182. b2 = self.getintbound(arg1)
  183. self.emit_operation(op)
  184. r = self.getintbound(op)
  185. b = b1.lshift_bound(b2)
  186. r.intersect(b)
  187. # intbound.lshift_bound checks for an overflow and if the
  188. # lshift can be proven not to overflow sets b.has_upper and
  189. # b.has_lower
  190. if b.has_lower and b.has_upper:
  191. # Synthesize the reverse op for optimize_default to reuse
  192. self.pure_from_args(rop.INT_RSHIFT,
  193. [op, arg1], arg0)
  194. def optimize_INT_RSHIFT(self, op):
  195. b1 = self.getintbound(op.getarg(0))
  196. b2 = self.getintbound(op.getarg(1))
  197. b = b1.rshift_bound(b2)
  198. if b.has_lower and b.has_upper and b.lower == b.upper:
  199. # constant result (likely 0, for rshifts that kill all bits)
  200. self.make_constant_int(op, b.lower)
  201. else:
  202. self.emit_operation(op)
  203. r = self.getintbound(op)
  204. r.intersect(b)
  205. def optimize_GUARD_NO_OVERFLOW(self, op):
  206. lastop = self.last_emitted_operation
  207. if lastop is not None:
  208. opnum = lastop.getopnum()
  209. args = lastop.getarglist()
  210. result = lastop
  211. # If the INT_xxx_OVF was replaced with INT_xxx or removed
  212. # completely, then we can kill the GUARD_NO_OVERFLOW.
  213. if (opnum != rop.INT_ADD_OVF and
  214. opnum != rop.INT_SUB_OVF and
  215. opnum != rop.INT_MUL_OVF):
  216. return
  217. # Else, synthesize the non overflowing op for optimize_default to
  218. # reuse, as well as the reverse op
  219. elif opnum == rop.INT_ADD_OVF:
  220. #self.pure(rop.INT_ADD, args[:], result)
  221. self.pure_from_args(rop.INT_SUB, [result, args[1]], args[0])
  222. self.pure_from_args(rop.INT_SUB, [result, args[0]], args[1])
  223. elif opnum == rop.INT_SUB_OVF:
  224. #self.pure(rop.INT_SUB, args[:], result)
  225. self.pure_from_args(rop.INT_ADD, [result, args[1]], args[0])
  226. self.pure_from_args(rop.INT_SUB, [args[0], result], args[1])
  227. #elif opnum == rop.INT_MUL_OVF:
  228. # self.pure(rop.INT_MUL, args[:], result)
  229. self.emit_operation(op)
  230. def optimize_GUARD_OVERFLOW(self, op):
  231. # If INT_xxx_OVF was replaced by INT_xxx, *but* we still see
  232. # GUARD_OVERFLOW, then the loop is invalid.
  233. lastop = self.last_emitted_operation
  234. if lastop is None:
  235. return # e.g. beginning of the loop
  236. opnum = lastop.getopnum()
  237. if opnum not in (rop.INT_ADD_OVF, rop.INT_SUB_OVF, rop.INT_MUL_OVF):
  238. raise InvalidLoop('An INT_xxx_OVF was proven not to overflow but' +
  239. 'guarded with GUARD_OVERFLOW')
  240. self.emit_operation(op)
  241. def optimize_INT_ADD_OVF(self, op):
  242. b1 = self.getintbound(op.getarg(0))
  243. b2 = self.getintbound(op.getarg(1))
  244. resbound = b1.add_bound(b2)
  245. if resbound.bounded():
  246. # Transform into INT_ADD. The following guard will be killed
  247. # by optimize_GUARD_NO_OVERFLOW; if we see instead an
  248. # optimize_GUARD_OVERFLOW, then InvalidLoop.
  249. op = self.replace_op_with(op, rop.INT_ADD)
  250. self.emit_operation(op) # emit the op
  251. r = self.getintbound(op)
  252. r.intersect(resbound)
  253. def optimize_INT_SUB_OVF(self, op):
  254. arg0 = self.get_box_replacement(op.getarg(0))
  255. arg1 = self.get_box_replacement(op.getarg(1))
  256. b0 = self.getintbound(arg0)
  257. b1 = self.getintbound(arg1)
  258. if arg0.same_box(arg1):
  259. self.make_constant_int(op, 0)
  260. return
  261. resbound = b0.sub_bound(b1)
  262. if resbound.bounded():
  263. op = self.replace_op_with(op, rop.INT_SUB)
  264. self.emit_operation(op) # emit the op
  265. r = self.getintbound(op)
  266. r.intersect(resbound)
  267. def optimize_INT_MUL_OVF(self, op):
  268. b1 = self.getintbound(op.getarg(0))
  269. b2 = self.getintbound(op.getarg(1))
  270. resbound = b1.mul_bound(b2)
  271. if resbound.bounded():
  272. op = self.replace_op_with(op, rop.INT_MUL)
  273. self.emit_operation(op)
  274. r = self.getintbound(op)
  275. r.intersect(resbound)
  276. def optimize_INT_LT(self, op):
  277. arg1 = self.get_box_replacement(op.getarg(0))
  278. arg2 = self.get_box_replacement(op.getarg(1))
  279. b1 = self.getintbound(arg1)
  280. b2 = self.getintbound(arg2)
  281. if b1.known_lt(b2):
  282. self.make_constant_int(op, 1)
  283. elif b1.known_ge(b2) or arg1 is arg2:
  284. self.make_constant_int(op, 0)
  285. else:
  286. self.emit_operation(op)
  287. def optimize_INT_GT(self, op):
  288. arg1 = self.get_box_replacement(op.getarg(0))
  289. arg2 = self.get_box_replacement(op.getarg(1))
  290. b1 = self.getintbound(arg1)
  291. b2 = self.getintbound(arg2)
  292. if b1.known_gt(b2):
  293. self.make_constant_int(op, 1)
  294. elif b1.known_le(b2) or arg1 is arg2:
  295. self.make_constant_int(op, 0)
  296. else:
  297. self.emit_operation(op)
  298. def optimize_INT_LE(self, op):
  299. arg1 = self.get_box_replacement(op.getarg(0))
  300. arg2 = self.get_box_replacement(op.getarg(1))
  301. b1 = self.getintbound(arg1)
  302. b2 = self.getintbound(arg2)
  303. if b1.known_le(b2) or arg1 is arg2:
  304. self.make_constant_int(op, 1)
  305. elif b1.known_gt(b2):
  306. self.make_constant_int(op, 0)
  307. else:
  308. self.emit_operation(op)
  309. def optimize_INT_GE(self, op):
  310. arg1 = self.get_box_replacement(op.getarg(0))
  311. arg2 = self.get_box_replacement(op.getarg(1))
  312. b1 = self.getintbound(arg1)
  313. b2 = self.getintbound(arg2)
  314. if b1.known_ge(b2) or arg1 is arg2:
  315. self.make_constant_int(op, 1)
  316. elif b1.known_lt(b2):
  317. self.make_constant_int(op, 0)
  318. else:
  319. self.emit_operation(op)
  320. def optimize_INT_EQ(self, op):
  321. arg0 = self.get_box_replacement(op.getarg(0))
  322. arg1 = self.get_box_replacement(op.getarg(1))
  323. b1 = self.getintbound(op.getarg(0))
  324. b2 = self.getintbound(op.getarg(1))
  325. if b1.known_gt(b2):
  326. self.make_constant_int(op, 0)
  327. elif b1.known_lt(b2):
  328. self.make_constant_int(op, 0)
  329. elif arg0.same_box(arg1):
  330. self.make_constant_int(op, 1)
  331. else:
  332. self.emit_operation(op)
  333. def optimize_INT_NE(self, op):
  334. arg0 = self.get_box_replacement(op.getarg(0))
  335. b1 = self.getintbound(arg0)
  336. arg1 = self.get_box_replacement(op.getarg(1))
  337. b2 = self.getintbound(arg1)
  338. if b1.known_gt(b2):
  339. self.make_constant_int(op, 1)
  340. elif b1.known_lt(b2):
  341. self.make_constant_int(op, 1)
  342. elif arg0 is arg1:
  343. self.make_constant_int(op, 0)
  344. else:
  345. self.emit_operation(op)
  346. def optimize_INT_FORCE_GE_ZERO(self, op):
  347. b = self.getintbound(op.getarg(0))
  348. if b.known_ge(IntBound(0, 0)):
  349. self.make_equal_to(op, op.getarg(0))
  350. else:
  351. self.emit_operation(op)
  352. def optimize_INT_SIGNEXT(self, op):
  353. b = self.getintbound(op.getarg(0))
  354. numbits = op.getarg(1).getint() * 8
  355. start = -(1 << (numbits - 1))
  356. stop = 1 << (numbits - 1)
  357. bounds = IntBound(start, stop - 1)
  358. if bounds.contains_bound(b):
  359. self.make_equal_to(op, op.getarg(0))
  360. else:
  361. self.emit_operation(op)
  362. bres = self.getintbound(op)
  363. bres.intersect(bounds)
  364. def optimize_ARRAYLEN_GC(self, op):
  365. array = self.ensure_ptr_info_arg0(op)
  366. self.emit_operation(op)
  367. self.optimizer.setintbound(op, array.getlenbound(None))
  368. def optimize_STRLEN(self, op):
  369. self.emit_operation(op)
  370. self.make_nonnull_str(op.getarg(0), vstring.mode_string)
  371. array = self.getptrinfo(op.getarg(0))
  372. self.optimizer.setintbound(op, array.getlenbound(vstring.mode_string))
  373. def optimize_UNICODELEN(self, op):
  374. self.emit_operation(op)
  375. self.make_nonnull_str(op.getarg(0), vstring.mode_unicode)
  376. array = self.getptrinfo(op.getarg(0))
  377. self.optimizer.setintbound(op, array.getlenbound(vstring.mode_unicode))
  378. def optimize_STRGETITEM(self, op):
  379. self.emit_operation(op)
  380. v1 = self.getintbound(op)
  381. v2 = self.getptrinfo(op.getarg(0))
  382. intbound = self.getintbound(op.getarg(1))
  383. if (intbound.has_lower and v2 is not None and
  384. v2.getlenbound(vstring.mode_string) is not None):
  385. lb = IntLowerBound(intbound.lower + 1)
  386. v2.getlenbound(vstring.mode_string).make_ge(lb)
  387. v1.make_ge(IntLowerBound(0))
  388. v1.make_lt(IntUpperBound(256))
  389. def optimize_GETFIELD_RAW_I(self, op):
  390. self.emit_operation(op)
  391. descr = op.getdescr()
  392. if descr.is_integer_bounded():
  393. b1 = self.getintbound(op)
  394. b1.make_ge(IntLowerBound(descr.get_integer_min()))
  395. b1.make_le(IntUpperBound(descr.get_integer_max()))
  396. optimize_GETFIELD_RAW_F = optimize_GETFIELD_RAW_I
  397. optimize_GETFIELD_RAW_R = optimize_GETFIELD_RAW_I
  398. optimize_GETFIELD_GC_I = optimize_GETFIELD_RAW_I
  399. optimize_GETFIELD_GC_R = optimize_GETFIELD_RAW_I
  400. optimize_GETFIELD_GC_F = optimize_GETFIELD_RAW_I
  401. optimize_GETINTERIORFIELD_GC_I = optimize_GETFIELD_RAW_I
  402. optimize_GETINTERIORFIELD_GC_R = optimize_GETFIELD_RAW_I
  403. optimize_GETINTERIORFIELD_GC_F = optimize_GETFIELD_RAW_I
  404. def optimize_GETARRAYITEM_RAW_I(self, op):
  405. self.emit_operation(op)
  406. descr = op.getdescr()
  407. if descr and descr.is_item_integer_bounded():
  408. intbound = self.getintbound(op)
  409. intbound.make_ge(IntLowerBound(descr.get_item_integer_min()))
  410. intbound.make_le(IntUpperBound(descr.get_item_integer_max()))
  411. optimize_GETARRAYITEM_RAW_F = optimize_GETARRAYITEM_RAW_I
  412. optimize_GETARRAYITEM_GC_I = optimize_GETARRAYITEM_RAW_I
  413. optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_RAW_I
  414. optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_RAW_I
  415. def optimize_UNICODEGETITEM(self, op):
  416. self.emit_operation(op)
  417. b1 = self.getintbound(op)
  418. b1.make_ge(IntLowerBound(0))
  419. v2 = self.getptrinfo(op.getarg(0))
  420. intbound = self.getintbound(op.getarg(1))
  421. if (intbound.has_lower and v2 is not None and
  422. v2.getlenbound(vstring.mode_unicode) is not None):
  423. lb = IntLowerBound(intbound.lower + 1)
  424. v2.getlenbound(vstring.mode_unicode).make_ge(lb)
  425. def make_int_lt(self, box1, box2):
  426. b1 = self.getintbound(box1)
  427. b2 = self.getintbound(box2)
  428. if b1.make_lt(b2):
  429. self.propagate_bounds_backward(box1)
  430. if b2.make_gt(b1):
  431. self.propagate_bounds_backward(box2)
  432. def make_int_le(self, box1, box2):
  433. b1 = self.getintbound(box1)
  434. b2 = self.getintbound(box2)
  435. if b1.make_le(b2):
  436. self.propagate_bounds_backward(box1)
  437. if b2.make_ge(b1):
  438. self.propagate_bounds_backward(box2)
  439. def make_int_gt(self, box1, box2):
  440. self.make_int_lt(box2, box1)
  441. def make_int_ge(self, box1, box2):
  442. self.make_int_le(box2, box1)
  443. def propagate_bounds_INT_LT(self, op):
  444. r = self.getintbound(op)
  445. if r.is_constant():
  446. if r.getint() == 1:
  447. self.make_int_lt(op.getarg(0), op.getarg(1))
  448. else:
  449. assert r.getint() == 0
  450. self.make_int_ge(op.getarg(0), op.getarg(1))
  451. def propagate_bounds_INT_GT(self, op):
  452. r = self.getintbound(op)
  453. if r.is_constant():
  454. if r.getint() == 1:
  455. self.make_int_gt(op.getarg(0), op.getarg(1))
  456. else:
  457. assert r.getint() == 0
  458. self.make_int_le(op.getarg(0), op.getarg(1))
  459. def propagate_bounds_INT_LE(self, op):
  460. r = self.getintbound(op)
  461. if r.is_constant():
  462. if r.getint() == 1:
  463. self.make_int_le(op.getarg(0), op.getarg(1))
  464. else:
  465. assert r.getint() == 0
  466. self.make_int_gt(op.getarg(0), op.getarg(1))
  467. def propagate_bounds_INT_GE(self, op):
  468. r = self.getintbound(op)
  469. if r.is_constant():
  470. if r.getint() == 1:
  471. self.make_int_ge(op.getarg(0), op.getarg(1))
  472. else:
  473. assert r.getint() == 0
  474. self.make_int_lt(op.getarg(0), op.getarg(1))
  475. def propagate_bounds_INT_EQ(self, op):
  476. r = self.getintbound(op)
  477. if r.is_constant():
  478. if r.equal(1):
  479. b1 = self.getintbound(op.getarg(0))
  480. b2 = self.getintbound(op.getarg(1))
  481. if b1.intersect(b2):
  482. self.propagate_bounds_backward(op.getarg(0))
  483. if b2.intersect(b1):
  484. self.propagate_bounds_backward(op.getarg(1))
  485. def propagate_bounds_INT_NE(self, op):
  486. r = self.getintbound(op)
  487. if r.is_constant():
  488. if r.equal(0):
  489. b1 = self.getintbound(op.getarg(0))
  490. b2 = self.getintbound(op.getarg(1))
  491. if b1.intersect(b2):
  492. self.propagate_bounds_backward(op.getarg(0))
  493. if b2.intersect(b1):
  494. self.propagate_bounds_backward(op.getarg(1))
  495. def _propagate_int_is_true_or_zero(self, op, valnonzero, valzero):
  496. if self.is_raw_ptr(op.getarg(0)):
  497. return
  498. r = self.getintbound(op)
  499. if r.is_constant():
  500. if r.getint() == valnonzero:
  501. b1 = self.getintbound(op.getarg(0))
  502. if b1.known_ge(IntBound(0, 0)):
  503. b1.make_gt(IntBound(0, 0))
  504. self.propagate_bounds_backward(op.getarg(0))
  505. elif r.getint() == valzero:
  506. b1 = self.getintbound(op.getarg(0))
  507. # XXX remove this hack maybe?
  508. # Clever hack, we can't use self.make_constant_int yet because
  509. # the args aren't in the values dictionary yet so it runs into
  510. # an assert, this is a clever way of expressing the same thing.
  511. b1.make_ge(IntBound(0, 0))
  512. b1.make_lt(IntBound(1, 1))
  513. self.propagate_bounds_backward(op.getarg(0))
  514. def propagate_bounds_INT_IS_TRUE(self, op):
  515. self._propagate_int_is_true_or_zero(op, 1, 0)
  516. def propagate_bounds_INT_IS_ZERO(self, op):
  517. self._propagate_int_is_true_or_zero(op, 0, 1)
  518. def propagate_bounds_INT_ADD(self, op):
  519. if self.is_raw_ptr(op.getarg(0)) or self.is_raw_ptr(op.getarg(1)):
  520. return
  521. b1 = self.getintbound(op.getarg(0))
  522. b2 = self.getintbound(op.getarg(1))
  523. r = self.getintbound(op)
  524. b = r.sub_bound(b2)
  525. if b1.intersect(b):
  526. self.propagate_bounds_backward(op.getarg(0))
  527. b = r.sub_bound(b1)
  528. if b2.intersect(b):
  529. self.propagate_bounds_backward(op.getarg(1))
  530. def propagate_bounds_INT_SUB(self, op):
  531. b1 = self.getintbound(op.getarg(0))
  532. b2 = self.getintbound(op.getarg(1))
  533. r = self.getintbound(op)
  534. b = r.add_bound(b2)
  535. if b1.intersect(b):
  536. self.propagate_bounds_backward(op.getarg(0))
  537. b = r.sub_bound(b1).mul(-1)
  538. if b2.intersect(b):
  539. self.propagate_bounds_backward(op.getarg(1))
  540. def propagate_bounds_INT_MUL(self, op):
  541. b1 = self.getintbound(op.getarg(0))
  542. b2 = self.getintbound(op.getarg(1))
  543. r = self.getintbound(op)
  544. b = r.py_div_bound(b2)
  545. if b1.intersect(b):
  546. self.propagate_bounds_backward(op.getarg(0))
  547. b = r.py_div_bound(b1)
  548. if b2.intersect(b):
  549. self.propagate_bounds_backward(op.getarg(1))
  550. def propagate_bounds_INT_LSHIFT(self, op):
  551. b1 = self.getintbound(op.getarg(0))
  552. b2 = self.getintbound(op.getarg(1))
  553. r = self.getintbound(op)
  554. b = r.rshift_bound(b2)
  555. if b1.intersect(b):
  556. self.propagate_bounds_backward(op.getarg(0))
  557. propagate_bounds_INT_ADD_OVF = propagate_bounds_INT_ADD
  558. propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB
  559. propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL
  560. dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_',
  561. default=OptIntBounds.opt_default)
  562. dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_')