py: Add more compiler optimisations for constant if/while conditions.
This commit is contained in:
parent
235f9b33c8
commit
391db8669b
82
py/compile.c
82
py/compile.c
|
@ -603,12 +603,13 @@ void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
}
|
||||
|
||||
STATIC bool node_is_const_false(mp_parse_node_t pn) {
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE);
|
||||
// untested: || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE)
|
||||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
|
||||
}
|
||||
|
||||
STATIC bool node_is_const_true(mp_parse_node_t pn) {
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE) || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 1);
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE)
|
||||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0);
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
|
@ -1658,25 +1659,31 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
|
||||
uint l_end = comp_next_label(comp);
|
||||
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
|
||||
if (
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// optimisation to not jump over non-existent elif/else blocks (this optimisation is not in CPython)
|
||||
!(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])) &&
|
||||
#endif
|
||||
// optimisation to not jump if last instruction was return
|
||||
!EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
// jump over elif/else blocks
|
||||
EMIT_ARG(jump, l_end);
|
||||
// optimisation: skip everything else when "if True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (
|
||||
// optimisation: don't jump over non-existent elif/else blocks (not in CPython)
|
||||
(MICROPY_EMIT_CPYTHON || !(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])))
|
||||
// optimisation: don't jump if last instruction was return
|
||||
&& !EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
// jump over elif/else blocks
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
|
||||
// compile elif blocks (if any)
|
||||
mp_parse_node_t *pn_elif;
|
||||
int n_elif = list_get(&pns->nodes[2], PN_if_stmt_elif_list, &pn_elif);
|
||||
|
@ -1684,19 +1691,30 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_elif[i], PN_if_stmt_elif)); // should be
|
||||
mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pn_elif[i];
|
||||
|
||||
l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns_elif->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition
|
||||
|
||||
compile_node(comp, pns_elif->nodes[1]); // elif block
|
||||
if (!EMIT(last_emit_was_return_value)) { // simple optimisation to align with CPython
|
||||
EMIT_ARG(jump, l_end);
|
||||
compile_node(comp, pns_elif->nodes[1]); // elif block
|
||||
|
||||
// optimisation: skip everything else when "elif True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns_elif->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// optimisation: don't jump if last instruction was return
|
||||
if (!EMIT(last_emit_was_return_value)) {
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
|
||||
// compile else block
|
||||
compile_node(comp, pns->nodes[3]); // can be null
|
||||
|
||||
done:
|
||||
EMIT_ARG(label_assign, l_end);
|
||||
}
|
||||
|
||||
|
@ -1735,12 +1753,16 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
EMIT(pop_block);
|
||||
}
|
||||
#else
|
||||
uint top_label = comp_next_label(comp);
|
||||
EMIT_ARG(jump, continue_label);
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
if (!node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for "while False"
|
||||
uint top_label = comp_next_label(comp);
|
||||
if (!node_is_const_true(pns->nodes[0])) { // optimisation: don't jump to cond for "while True"
|
||||
EMIT_ARG(jump, continue_label);
|
||||
}
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
}
|
||||
#endif
|
||||
|
||||
// break/continue apply to outer loop (if any) in the else block
|
||||
|
|
|
@ -1,5 +1,38 @@
|
|||
# test if conditions which are optimised by the compiler
|
||||
|
||||
if 0:
|
||||
print(5)
|
||||
else:
|
||||
print(6)
|
||||
|
||||
if 1:
|
||||
print(7)
|
||||
|
||||
if 2:
|
||||
print(8)
|
||||
|
||||
if -1:
|
||||
print(9)
|
||||
elif 1:
|
||||
print(10)
|
||||
|
||||
if 0:
|
||||
print(11)
|
||||
else:
|
||||
print(12)
|
||||
|
||||
if 0:
|
||||
print(13)
|
||||
elif 1:
|
||||
print(14)
|
||||
|
||||
if 0:
|
||||
print(15)
|
||||
elif 0:
|
||||
print(16)
|
||||
else:
|
||||
print(17)
|
||||
|
||||
f2 = 0
|
||||
|
||||
def f(t1, t2, f1):
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# test while conditions which are optimised by the compiler
|
||||
|
||||
while 0:
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
|
||||
while 1:
|
||||
print(2)
|
||||
break
|
||||
|
||||
while 2:
|
||||
print(3)
|
||||
break
|
||||
|
||||
while -1:
|
||||
print(4)
|
||||
break
|
Loading…
Reference in New Issue