@@ -1776,26 +1776,40 @@ STATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
17761776}
17771777
17781778#if !MICROPY_EMIT_CPYTHON
1779- // TODO preload end and step onto stack if they are not constants
1780- // Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
1781- // And, if the loop never runs, the loop variable should never be assigned
1779+ // This function compiles an optimised for-loop of the form:
1780+ // for <var> in range(<start>, <end>, <step>):
1781+ // <body>
1782+ // else:
1783+ // <else>
1784+ // <var> must be an identifier and <step> must be a small-int.
1785+ //
1786+ // Semantics of for-loop require:
1787+ // - final failing value should not be stored in the loop variable
1788+ // - if the loop never runs, the loop variable should never be assigned
1789+ // - assignments to <var>, <end> or <step> in the body do not alter the loop
1790+ // (<step> is a constant for us, so no need to worry about it changing)
1791+ //
1792+ // If <end> is a small-int, then the stack during the for-loop contains just
1793+ // the current value of <var>. Otherwise, the stack contains <end> then the
1794+ // current value of <var>.
17821795STATIC 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 ) {
17831796 START_BREAK_CONTINUE_BLOCK
1784- // note that we don't need to pop anything when breaking from an optimise for loop
17851797
17861798 uint top_label = comp_next_label (comp );
17871799 uint entry_label = comp_next_label (comp );
17881800
1789- // compile: start, duplicated on stack
1801+ // put the end value on the stack if it's not a small-int constant
1802+ bool end_on_stack = !MP_PARSE_NODE_IS_SMALL_INT (pn_end );
1803+ if (end_on_stack ) {
1804+ compile_node (comp , pn_end );
1805+ }
1806+
1807+ // compile: start
17901808 compile_node (comp , pn_start );
1791- EMIT (dup_top );
17921809
17931810 EMIT_ARG (jump , entry_label );
17941811 EMIT_ARG (label_assign , top_label );
17951812
1796- // at this point we actually have 1 less element on the stack
1797- EMIT_ARG (adjust_stack_size , -1 );
1798-
17991813 // duplicate next value and store it to var
18001814 EMIT (dup_top );
18011815 c_assign (comp , pn_var , ASSIGN_STORE );
@@ -1805,15 +1819,20 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p
18051819
18061820 EMIT_ARG (label_assign , continue_label );
18071821
1808- // compile: var + step, duplicated on stack
1822+ // compile: var + step
18091823 compile_node (comp , pn_step );
18101824 EMIT_ARG (binary_op , MP_BINARY_OP_INPLACE_ADD );
1811- EMIT (dup_top );
18121825
18131826 EMIT_ARG (label_assign , entry_label );
18141827
18151828 // compile: if var <cond> end: goto top
1816- compile_node (comp , pn_end );
1829+ if (end_on_stack ) {
1830+ EMIT (dup_top_two );
1831+ EMIT (rot_two );
1832+ } else {
1833+ EMIT (dup_top );
1834+ compile_node (comp , pn_end );
1835+ }
18171836 assert (MP_PARSE_NODE_IS_SMALL_INT (pn_step ));
18181837 if (MP_PARSE_NODE_LEAF_SMALL_INT (pn_step ) >= 0 ) {
18191838 EMIT_ARG (binary_op , MP_BINARY_OP_LESS );
@@ -1822,15 +1841,20 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p
18221841 }
18231842 EMIT_ARG (pop_jump_if_true , top_label );
18241843
1825- // discard final value of var that failed the loop condition
1826- EMIT (pop_top );
1827-
18281844 // break/continue apply to outer loop (if any) in the else block
18291845 END_BREAK_CONTINUE_BLOCK
18301846
18311847 compile_node (comp , pn_else );
18321848
18331849 EMIT_ARG (label_assign , break_label );
1850+
1851+ // discard final value of var that failed the loop condition
1852+ EMIT (pop_top );
1853+
1854+ // discard <end> value if it's on the stack
1855+ if (end_on_stack ) {
1856+ EMIT (pop_top );
1857+ }
18341858}
18351859#endif
18361860
0 commit comments