Jit and the copy module causes miscompilation
See the following test code:
import copy def eva(board, w): height = len(board) - 1 width = len(board[0]) eb = copy.copy(list(reversed(board[0:height]))) ch = [0]*width for c in range(width): # Works if I add the assert!!! #assert height == 20 h = height-1 while h > 0: if eb[h][c] != 0: break h -= 1 ch[c] = h + 1 return max(ch) board = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [4, 0, 0, 1, 1, 0, 0, 0, 0, 0], [4, 4, 4, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] for x in range(50): print(eva(list(board), [1.0, 1.0, 5.0, 2.0, 1.0, 1.0, 1.0]))
When running it with pypy it correctly prints 3 for about 40 loops. Then the JIT runs and after that it prints 2 instead. Python ofc prints the right answer 3 all the time. pypy3 version 3.5.3 and python3 3.7.0.
Comments (5)
-
-
With this function, I get the
debug_print
emitting a value30002
instead of30020
. In the produced assembler there is "i1 = int_mul(c, 10000)" followed by "int_add_ovf(i1, 2)", i.e. the JIT front-end mistakenly thinksheight
should be the constant 2 here...def eva(board, w): height = len(board) - 1 width = len(board[0]) eb = (list(reversed(board[0:height]))) ch = [0]*width assert height == 20 for c in range(width): # Works if I add the assert!!! #assert height == 20 debug_print(c*10000+height) h = height-1 while h > 0: if eb[h][c] != 0: break h -= 1 print '===================================', h+1 ch[c] = h + 1 assert height == 20 print return ch#max(ch)
-
Even simpler example:
from __pypy__ import debug_print def eva(height): for c in range(10): debug_print(">>>>>>>>>>>", height-1) h = height while h > 0: h -= 1 while True: eva(5)
Dumps a mixture of 0 and 4 instead of all 4, depending on the magic threshold values. Try
pypy --jit threshold=15
. -
@Armin Rigo this is fixed, isn't it?
-
- changed status to resolved
Yes, it's fixed. It now produces a small number of extra guards, which we might want to try to remove at some point....
- Log in to comment
Thanks a lot for hunting that down! This looks like a serious problem. I've simplified the program a little bit further, this fails too:
(If I disable unrolling, the program passes. That may be unrelated though, since a lot of random changes make the program "work", eg indeed adding the assert)