compile_for_stmt_optimised_range(): Properly handle negative & unknown steps.
If step is not constant, in first approximation, we can't apply optimization, (well, we could, but need a special case for this).
This commit is contained in:
parent
bab5cfb34f
commit
899c69f94c
27
py/compile.c
27
py/compile.c
|
@ -1460,10 +1460,14 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
|
||||||
|
|
||||||
EMIT(label_assign, continue_label);
|
EMIT(label_assign, continue_label);
|
||||||
|
|
||||||
// compile: if var < end: goto top
|
// compile: if var <cond> end: goto top
|
||||||
compile_node(comp, pn_var);
|
compile_node(comp, pn_var);
|
||||||
compile_node(comp, pn_end);
|
compile_node(comp, pn_end);
|
||||||
EMIT(compare_op, RT_COMPARE_OP_LESS);
|
if (MP_PARSE_NODE_LEAF_ARG(pn_step) >= 0) {
|
||||||
|
EMIT(compare_op, RT_COMPARE_OP_LESS);
|
||||||
|
} else {
|
||||||
|
EMIT(compare_op, RT_COMPARE_OP_MORE);
|
||||||
|
}
|
||||||
EMIT(pop_jump_if_true, top_label);
|
EMIT(pop_jump_if_true, top_label);
|
||||||
|
|
||||||
// break/continue apply to outer loop (if any) in the else block
|
// break/continue apply to outer loop (if any) in the else block
|
||||||
|
@ -1482,14 +1486,19 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||||
// for viper it will be much, much faster
|
// for viper it will be much, much faster
|
||||||
if (/*comp->scope_cur->emit_options == EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_power)) {
|
if (/*comp->scope_cur->emit_options == EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_power)) {
|
||||||
mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1];
|
mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1];
|
||||||
if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range && MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren) && MP_PARSE_NODE_IS_NULL(pns_it->nodes[2])) {
|
if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])
|
||||||
|
&& MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range
|
||||||
|
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren)
|
||||||
|
&& MP_PARSE_NODE_IS_NULL(pns_it->nodes[2])) {
|
||||||
mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t*)pns_it->nodes[1])->nodes[0];
|
mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t*)pns_it->nodes[1])->nodes[0];
|
||||||
mp_parse_node_t *args;
|
mp_parse_node_t *args;
|
||||||
int n_args = list_get(&pn_range_args, PN_arglist, &args);
|
int n_args = list_get(&pn_range_args, PN_arglist, &args);
|
||||||
|
mp_parse_node_t pn_range_start;
|
||||||
|
mp_parse_node_t pn_range_end;
|
||||||
|
mp_parse_node_t pn_range_step;
|
||||||
|
bool optimize = false;
|
||||||
if (1 <= n_args && n_args <= 3) {
|
if (1 <= n_args && n_args <= 3) {
|
||||||
mp_parse_node_t pn_range_start;
|
optimize = true;
|
||||||
mp_parse_node_t pn_range_end;
|
|
||||||
mp_parse_node_t pn_range_step;
|
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
pn_range_start = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, 0);
|
pn_range_start = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, 0);
|
||||||
pn_range_end = args[0];
|
pn_range_end = args[0];
|
||||||
|
@ -1502,7 +1511,13 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||||
pn_range_start = args[0];
|
pn_range_start = args[0];
|
||||||
pn_range_end = args[1];
|
pn_range_end = args[1];
|
||||||
pn_range_step = args[2];
|
pn_range_step = args[2];
|
||||||
|
// We need to know sign of step. This is possible only if it's constant
|
||||||
|
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_range_step)) {
|
||||||
|
optimize = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (optimize) {
|
||||||
compile_for_stmt_optimised_range(comp, pns->nodes[0], pn_range_start, pn_range_end, pn_range_step, pns->nodes[2], pns->nodes[3]);
|
compile_for_stmt_optimised_range(comp, pns->nodes[0], pn_range_start, pn_range_end, pn_range_step, pns->nodes[2], pns->nodes[3]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,3 +7,13 @@ def f():
|
||||||
print(x, y, z)
|
print(x, y, z)
|
||||||
|
|
||||||
f()
|
f()
|
||||||
|
|
||||||
|
# range with negative step
|
||||||
|
for i in range(3, -1, -1):
|
||||||
|
print(i)
|
||||||
|
|
||||||
|
a = -1
|
||||||
|
# range with non-constant step - we optimize constant steps, so this
|
||||||
|
# will be executed differently
|
||||||
|
for i in range(3, -1, a):
|
||||||
|
print(i)
|
||||||
|
|
Loading…
Reference in New Issue