py: Fix bug in optimised for .. range.
Don't store final, failing value to the loop variable. This fix also makes for .. range a bit more efficient, as it uses less store/load pairs for the loop variable.
This commit is contained in:
parent
8cd72bdf92
commit
3ff2d03891
23
py/compile.c
23
py/compile.c
@ -1534,35 +1534,41 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
|
||||
// TODO preload end and step onto stack if they are not constants
|
||||
// TODO check if step is negative and do opposite test
|
||||
// Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
|
||||
// And, if the loop never runs, the loop variable should never be assigned
|
||||
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
|
||||
int top_label = comp_next_label(comp);
|
||||
int entry_label = comp_next_label(comp);
|
||||
|
||||
// compile: var = start
|
||||
// compile: start, duplicated on stack
|
||||
compile_node(comp, pn_start);
|
||||
c_assign(comp, pn_var, ASSIGN_STORE);
|
||||
EMIT(dup_top);
|
||||
|
||||
EMIT_ARG(jump, entry_label);
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
|
||||
// at this point we actually have 1 less element on the stack
|
||||
EMIT_ARG(set_stack_size, EMIT(get_stack_size) - 1);
|
||||
|
||||
// store next value to var
|
||||
c_assign(comp, pn_var, ASSIGN_STORE);
|
||||
|
||||
// compile body
|
||||
compile_node(comp, pn_body);
|
||||
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
|
||||
// compile: var += step
|
||||
c_assign(comp, pn_var, ASSIGN_AUG_LOAD);
|
||||
// compile: var + step, duplicated on stack
|
||||
compile_node(comp, pn_var);
|
||||
compile_node(comp, pn_step);
|
||||
EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD);
|
||||
c_assign(comp, pn_var, ASSIGN_AUG_STORE);
|
||||
EMIT(dup_top);
|
||||
|
||||
EMIT_ARG(label_assign, entry_label);
|
||||
|
||||
// compile: if var <cond> end: goto top
|
||||
compile_node(comp, pn_var);
|
||||
compile_node(comp, pn_end);
|
||||
assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step));
|
||||
if (MP_PARSE_NODE_LEAF_SMALL_INT(pn_step) >= 0) {
|
||||
@ -1572,6 +1578,9 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
|
||||
}
|
||||
EMIT_ARG(pop_jump_if_true, top_label);
|
||||
|
||||
// discard final value of var that failed the loop condition
|
||||
EMIT(pop_top);
|
||||
|
||||
// break/continue apply to outer loop (if any) in the else block
|
||||
END_BREAK_CONTINUE_BLOCK
|
||||
|
||||
|
8
tests/basics/for2.py
Normal file
8
tests/basics/for2.py
Normal file
@ -0,0 +1,8 @@
|
||||
i = 'init'
|
||||
for i in range(0):
|
||||
pass
|
||||
print(i) # should not have been modified
|
||||
|
||||
for i in range(10):
|
||||
pass
|
||||
print(i) # should be last successful value of loop
|
159
tests/misc/features.py
Normal file
159
tests/misc/features.py
Normal file
@ -0,0 +1,159 @@
|
||||
# mad.py
|
||||
# Alf Clement 27-Mar-2014
|
||||
#
|
||||
zero=0
|
||||
three=3
|
||||
print("1")
|
||||
print("2")
|
||||
print(three)
|
||||
print("{}".format(4))
|
||||
five=25/5
|
||||
print(int(five))
|
||||
j=0
|
||||
for i in range(4):
|
||||
j += i
|
||||
print(j)
|
||||
print(3+4)
|
||||
try:
|
||||
a=4/zero
|
||||
except:
|
||||
print(8)
|
||||
print("xxxxxxxxx".count("x"))
|
||||
def ten():
|
||||
return 10
|
||||
print(ten())
|
||||
a=[]
|
||||
for i in range(13):
|
||||
a.append(i)
|
||||
print(a[11])
|
||||
print(a[-1])
|
||||
str="0123456789"
|
||||
print(str[1]+str[3])
|
||||
def p(s):
|
||||
print(s)
|
||||
p("14")
|
||||
p(15)
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a=16
|
||||
def print(self):
|
||||
print(self.a)
|
||||
def set(self,b):
|
||||
self.a=b
|
||||
a=A()
|
||||
a.print()
|
||||
a.set(17)
|
||||
a.print()
|
||||
b=A()
|
||||
b.set(a.a + 1)
|
||||
b.print()
|
||||
for i in range(20):
|
||||
pass
|
||||
print(i)
|
||||
if 20 > 30:
|
||||
a="1"
|
||||
else:
|
||||
a="2"
|
||||
if 0 < 4:
|
||||
print(a+"0")
|
||||
else:
|
||||
print(a+"1")
|
||||
a=[20,21,22,23,24]
|
||||
for i in a:
|
||||
if i < 21:
|
||||
continue
|
||||
if i > 21:
|
||||
break
|
||||
print(i)
|
||||
b=[a,a,a]
|
||||
print(b[1][2])
|
||||
print(161//7)
|
||||
a=24
|
||||
while True:
|
||||
try:
|
||||
def gcheck():
|
||||
global a
|
||||
print(a)
|
||||
gcheck()
|
||||
class c25():
|
||||
x=25
|
||||
x=c25()
|
||||
print(x.x)
|
||||
raise
|
||||
except:
|
||||
print(26)
|
||||
print(27+zero)
|
||||
break
|
||||
print(28)
|
||||
k=29
|
||||
def f():
|
||||
global k
|
||||
k = yield k
|
||||
print(next(f()))
|
||||
while True:
|
||||
k+= 1
|
||||
if k < 30:
|
||||
continue
|
||||
break
|
||||
print(k)
|
||||
for i in [1,2,3]:
|
||||
class A():
|
||||
def __init__(self, c):
|
||||
self.a = i+10*c
|
||||
b = A(3)
|
||||
print(b.a)
|
||||
print(34)
|
||||
p=0
|
||||
for i in range(35, -1, -1):
|
||||
print(i)
|
||||
p = p + 1
|
||||
if p > 0:
|
||||
break
|
||||
p=36
|
||||
while p == 36:
|
||||
print(p)
|
||||
p=37
|
||||
print(p)
|
||||
for i in [38]:
|
||||
print(i)
|
||||
print(int(exec("def foo(): return 38") == None)+foo())
|
||||
d = {}
|
||||
exec("def bar(): return 40", d)
|
||||
print(d["bar"]())
|
||||
def fib2(n):
|
||||
result = []
|
||||
a, b = 0, 1
|
||||
while a < n:
|
||||
result.append(a)
|
||||
a, b = b, a+b
|
||||
return result
|
||||
print(fib2(100)[-2]-14)
|
||||
Answer={}
|
||||
Answer["ForAll"]=42
|
||||
print(Answer["ForAll"])
|
||||
i = 43
|
||||
def f(i=i):
|
||||
print(i)
|
||||
i = 44
|
||||
f()
|
||||
print(i)
|
||||
while True:
|
||||
try:
|
||||
if None != True:
|
||||
print(45)
|
||||
break
|
||||
else:
|
||||
print(0)
|
||||
except:
|
||||
print(0)
|
||||
print(46)
|
||||
print(46+1)
|
||||
def u(p):
|
||||
if p > 3:
|
||||
return 3*p
|
||||
else:
|
||||
return u(2*p)-3*u(p)
|
||||
print(u(16))
|
||||
def u49():
|
||||
return 49
|
||||
print(u49())
|
Loading…
Reference in New Issue
Block a user