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 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) {
|
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
|
START_BREAK_CONTINUE_BLOCK
|
||||||
|
|
||||||
int top_label = comp_next_label(comp);
|
int top_label = comp_next_label(comp);
|
||||||
int entry_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);
|
compile_node(comp, pn_start);
|
||||||
c_assign(comp, pn_var, ASSIGN_STORE);
|
EMIT(dup_top);
|
||||||
|
|
||||||
EMIT_ARG(jump, entry_label);
|
EMIT_ARG(jump, entry_label);
|
||||||
EMIT_ARG(label_assign, top_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 body
|
||||||
compile_node(comp, pn_body);
|
compile_node(comp, pn_body);
|
||||||
|
|
||||||
EMIT_ARG(label_assign, continue_label);
|
EMIT_ARG(label_assign, continue_label);
|
||||||
|
|
||||||
// compile: var += step
|
// compile: var + step, duplicated on stack
|
||||||
c_assign(comp, pn_var, ASSIGN_AUG_LOAD);
|
compile_node(comp, pn_var);
|
||||||
compile_node(comp, pn_step);
|
compile_node(comp, pn_step);
|
||||||
EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD);
|
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);
|
EMIT_ARG(label_assign, entry_label);
|
||||||
|
|
||||||
// compile: if var <cond> end: goto top
|
// compile: if var <cond> end: goto top
|
||||||
compile_node(comp, pn_var);
|
|
||||||
compile_node(comp, pn_end);
|
compile_node(comp, pn_end);
|
||||||
assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step));
|
assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step));
|
||||||
if (MP_PARSE_NODE_LEAF_SMALL_INT(pn_step) >= 0) {
|
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);
|
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
|
// break/continue apply to outer loop (if any) in the else block
|
||||||
END_BREAK_CONTINUE_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