Wrong optimization bug around bounds analysis of int_add
Nico Rittinghaus, my bachelor student and I found the following existing JIT test today, which passes, but is actually incorrect (see comments):
def test_bound_lt_add_before(self):
# removing the second guard is incorrect.
ops = """
[i0] # MAXINT-9
i2 = int_add(i0, 10) # == MININT (overflow)
i3 = int_lt(i2, 15) # == TRUE
guard_true(i3) []
i1 = int_lt(i0, 6) # == FALSE
guard_true(i1) [] # this guard can fail, must not be removed!
jump(i0)
"""
expected = """
[i0]
i2 = int_add(i0, 10)
i3 = int_lt(i2, 15)
guard_true(i3) []
jump(i0)
"""
self.optimize_loop(ops, expected)
Admittedly it's about int_add
, which is quite rarely used in PyPy and its semantics is probably under-specified. However, if you use __pypy__.intop.int_add
, you can still get programs that behave differently with and without the JIT:
cfbolz@drais:~/temp/miscompile$ cat x.py
import __pypy__
import sys
def wrong(x): # does exactly the thing same as the test
a = __pypy__.intop.int_add(x, 10)
if a < 15:
if x < 6:
return 0
return 1
return 2
def main():
res = 0
for i in list(range(-100000, 0)) + [sys.maxsize]:
res += wrong(i)
print(res)
main() # prints 1 without JIT, 0 with JIT