From 0779693c23fcc55993a06e4e0adf30a3d41f90f5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 27 Feb 2019 00:10:04 +1100 Subject: [PATCH] py/compile: Add optimisation to compile OrderedDict inplace. This optimisation eliminates the need to create a temporary normal dict. The optimisation is enabled via MICROPY_COMP_CONST_LITERAL which is enabled by default (although only has an effect if OrderdDict is enabled). Thanks to @pfalcon for the initial idea and implementation. --- py/compile.c | 33 +++++++++++++++++++++++++++++---- py/mpconfig.h | 5 +++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/py/compile.c b/py/compile.c index e660e668c4..42222528e2 100644 --- a/py/compile.c +++ b/py/compile.c @@ -164,6 +164,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra); STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind); +STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map); STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn); STATIC uint comp_next_label(compiler_t *comp) { @@ -2247,6 +2248,20 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p EMIT_ARG(call_function, 2, 0, 0); i = 1; } + + #if MICROPY_COMP_CONST_LITERAL && MICROPY_PY_COLLECTIONS_ORDEREDDICT + // handle special OrderedDict constructor + } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_OrderedDict + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren + && MP_PARSE_NODE_IS_STRUCT_KIND(pns_trail[0]->nodes[0], PN_atom_brace)) { + // at this point we have matched "OrderedDict({...})" + + EMIT_ARG(call_function, 0, 0, 0); + mp_parse_node_struct_t *pns_dict = (mp_parse_node_struct_t*)pns_trail[0]->nodes[0]; + compile_atom_brace_helper(comp, pns_dict, false); + i = 1; + #endif } // compile the remaining trailers @@ -2455,16 +2470,20 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) } } -STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map) { mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // empty dict - EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + } } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) { // dict with one element - EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); + } compile_node(comp, pn); EMIT(store_map); } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { @@ -2481,7 +2500,9 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { bool is_dict; if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { // a dictionary - EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); + if (create_map) { + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); + } compile_node(comp, pns->nodes[0]); EMIT(store_map); is_dict = true; @@ -2551,6 +2572,10 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { } } +STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_atom_brace_helper(comp, pns, true); +} + STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_trailer_paren_helper(comp, pns->nodes[0], false, 0); } diff --git a/py/mpconfig.h b/py/mpconfig.h index 47638fb0a4..c4b62dd847 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -356,6 +356,11 @@ #define MICROPY_COMP_CONST_FOLDING (1) #endif +// Whether to enable optimisations for constant literals, eg OrderedDict +#ifndef MICROPY_COMP_CONST_LITERAL +#define MICROPY_COMP_CONST_LITERAL (1) +#endif + // Whether to enable lookup of constants in modules; eg module.CONST #ifndef MICROPY_COMP_MODULE_CONST #define MICROPY_COMP_MODULE_CONST (0)