From b0cbfb0492028192a28f0514fba71ec954330108 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 13 Nov 2016 15:32:05 +1100 Subject: py/parse: Move function to check for const parse node to parse.[ch]. --- py/parse.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'py/parse.c') diff --git a/py/parse.c b/py/parse.c index 397d46d9f..aa6034a6a 100644 --- a/py/parse.c +++ b/py/parse.c @@ -234,6 +234,16 @@ mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg) { return (mp_parse_node_t)(kind | (arg << 4)); } +bool mp_parse_node_is_const_false(mp_parse_node_t pn) { + 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); +} + +bool mp_parse_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) != 0); +} + bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn)); -- cgit v1.2.3 From ed9c93f0f13fe2b6b4b0fbc1155b1e38ee1be242 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 13 Nov 2016 15:35:11 +1100 Subject: py/parse: Make mp_parse_node_new_leaf an inline function. It is split into 2 functions, one to make small ints and the other to make a non-small-int leaf node. This reduces code size by 32 bytes on bare-arm, 64 bytes on unix (x64-64) and 144 bytes on stmhal. --- py/compile.c | 6 +++--- py/parse.c | 13 +++---------- py/parse.h | 7 ++++++- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'py/parse.c') diff --git a/py/compile.c b/py/compile.c index cd38b07f3..6efd15eff 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1403,13 +1403,13 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (1 <= n_args && n_args <= 3) { optimize = true; 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_small_int(0); pn_range_end = args[0]; - pn_range_step = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, 1); + pn_range_step = mp_parse_node_new_small_int(1); } else if (n_args == 2) { pn_range_start = args[0]; pn_range_end = args[1]; - pn_range_step = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, 1); + pn_range_step = mp_parse_node_new_small_int(1); } else { pn_range_start = args[0]; pn_range_end = args[1]; diff --git a/py/parse.c b/py/parse.c index aa6034a6a..698f79617 100644 --- a/py/parse.c +++ b/py/parse.c @@ -227,13 +227,6 @@ STATIC void pop_rule(parser_t *parser, const rule_t **rule, size_t *arg_i, size_ *src_line = parser->rule_stack[parser->rule_stack_top].src_line; } -mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg) { - if (kind == MP_PARSE_NODE_SMALL_INT) { - return (mp_parse_node_t)(kind | (arg << 1)); - } - return (mp_parse_node_t)(kind | (arg << 4)); -} - bool mp_parse_node_is_const_false(mp_parse_node_t pn) { 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); @@ -418,7 +411,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { mp_map_elem_t *elem; if (rule->rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(elem->value)); + pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(elem->value)); } else { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); } @@ -429,7 +422,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); if (MP_OBJ_IS_SMALL_INT(o)) { - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(o)); + pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(o)); } else { pn = make_node_const_object(parser, lex->tok_line, o); } @@ -658,7 +651,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args pop_result(parser); } if (MP_OBJ_IS_SMALL_INT(arg0)) { - push_result_node(parser, mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(arg0))); + push_result_node(parser, mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(arg0))); } else { // TODO reuse memory for parse node struct? push_result_node(parser, make_node_const_object(parser, 0, arg0)); diff --git a/py/parse.h b/py/parse.h index 54bbd2645..769f5a875 100644 --- a/py/parse.h +++ b/py/parse.h @@ -76,7 +76,12 @@ typedef struct _mp_parse_node_struct_t { #define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff) #define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8) -mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg); +static inline mp_parse_node_t mp_parse_node_new_small_int(mp_int_t val) { + return (mp_parse_node_t)(MP_PARSE_NODE_SMALL_INT | ((mp_uint_t)val << 1)); +} +static inline mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg) { + return (mp_parse_node_t)(kind | ((mp_uint_t)arg << 4)); +} bool mp_parse_node_is_const_false(mp_parse_node_t pn); bool mp_parse_node_is_const_true(mp_parse_node_t pn); bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o); -- cgit v1.2.3 From 9b525134d1bf5b3f05b39fe90ddaa4bd33ea3e0d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 13 Nov 2016 15:36:49 +1100 Subject: py/parse: Add code to fold logical constants in or/and/not operations. Adds about 200 bytes to the code size when constant folding is enabled. --- py/parse.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'py/parse.c') diff --git a/py/parse.c b/py/parse.c index 698f79617..dc360e40c 100644 --- a/py/parse.c +++ b/py/parse.c @@ -470,6 +470,63 @@ STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args); #if MICROPY_COMP_CONST_FOLDING +STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t *num_args) { + if (rule->rule_id == RULE_or_test + || rule->rule_id == RULE_and_test) { + // folding for binary logical ops: or and + size_t copy_to = *num_args; + for (size_t i = copy_to; i > 0;) { + mp_parse_node_t pn = peek_result(parser, --i); + parser->result_stack[parser->result_stack_top - copy_to] = pn; + if (i == 0) { + // always need to keep the last value + break; + } + if (rule->rule_id == RULE_or_test) { + if (mp_parse_node_is_const_true(pn)) { + // + break; + } else if (!mp_parse_node_is_const_false(pn)) { + copy_to -= 1; + } + } else { + // RULE_and_test + if (mp_parse_node_is_const_false(pn)) { + break; + } else if (!mp_parse_node_is_const_true(pn)) { + copy_to -= 1; + } + } + } + copy_to -= 1; // copy_to now contains number of args to pop + + // pop and discard all the short-circuited expressions + for (size_t i = 0; i < copy_to; ++i) { + pop_result(parser); + } + *num_args -= copy_to; + + // we did a complete folding if there's only 1 arg left + return *num_args == 1; + + } else if (rule->rule_id == RULE_not_test_2) { + // folding for unary logical op: not + mp_parse_node_t pn = peek_result(parser, 0); + if (mp_parse_node_is_const_false(pn)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_TRUE); + } else if (mp_parse_node_is_const_true(pn)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_FALSE); + } else { + return false; + } + pop_result(parser); + push_result_node(parser, pn); + return true; + } + + return false; +} + STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args) { // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x @@ -677,6 +734,10 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru } #if MICROPY_COMP_CONST_FOLDING + if (fold_logical_constants(parser, rule, &num_args)) { + // we folded this rule so return straight away + return; + } if (fold_constants(parser, rule, num_args)) { // we folded this rule so return straight away return; -- cgit v1.2.3