summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/parse.c28
-rw-r--r--tests/cmdline/cmd_showbc_const.py69
-rw-r--r--tests/cmdline/cmd_showbc_const.py.exp160
3 files changed, 247 insertions, 10 deletions
diff --git a/py/parse.c b/py/parse.c
index d58098af2..62de3282b 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -334,16 +334,6 @@ STATIC uint8_t peek_rule(parser_t *parser, size_t n) {
}
#endif
-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));
@@ -427,6 +417,24 @@ STATIC mp_obj_t mp_parse_node_convert_to_obj(mp_parse_node_t pn) {
}
#endif
+STATIC bool parse_node_is_const_bool(mp_parse_node_t pn, bool value) {
+ // Returns true if 'pn' is a constant whose boolean value is equivalent to 'value'
+ #if MICROPY_COMP_CONST_TUPLE || MICROPY_COMP_CONST
+ return mp_parse_node_is_const(pn) && mp_obj_is_true(mp_parse_node_convert_to_obj(pn)) == value;
+ #else
+ return MP_PARSE_NODE_IS_TOKEN_KIND(pn, value ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE)
+ || (MP_PARSE_NODE_IS_SMALL_INT(pn) && !!MP_PARSE_NODE_LEAF_SMALL_INT(pn) == value);
+ #endif
+}
+
+bool mp_parse_node_is_const_false(mp_parse_node_t pn) {
+ return parse_node_is_const_bool(pn, false);
+}
+
+bool mp_parse_node_is_const_true(mp_parse_node_t pn) {
+ return parse_node_is_const_bool(pn, true);
+}
+
size_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes) {
if (MP_PARSE_NODE_IS_NULL(*pn)) {
*nodes = NULL;
diff --git a/tests/cmdline/cmd_showbc_const.py b/tests/cmdline/cmd_showbc_const.py
new file mode 100644
index 000000000..54f9ec23c
--- /dev/null
+++ b/tests/cmdline/cmd_showbc_const.py
@@ -0,0 +1,69 @@
+# cmdline: -v -v
+# Test constant-related bytecode optimisations
+# (constant folding, compile-time if/while evaluation, etc.)
+from micropython import const
+import sys
+
+try:
+ sys.settrace
+ # if MICROPY_PY_SYS_SETTRACE is enabled, compile-time const optimizations
+ # are disabled so the bytecode output is very different
+ print("SKIP")
+ raise SystemExit
+except AttributeError:
+ pass
+
+_STR = const("foo")
+_EMPTY_TUPLE = const(())
+_TRUE = const(True)
+_FALSE = const(False)
+_SMALLINT = const(33)
+_ZERO = const(0)
+
+# Bytecode generated for these if/while statements should contain no JUMP_IF
+# and no instances of string 'Eliminated'
+
+if _STR or _EMPTY_TUPLE:
+ print("Kept")
+if _STR and _EMPTY_TUPLE:
+ print("Eliminated")
+if _TRUE:
+ print("Kept")
+if _SMALLINT:
+ print("Kept")
+if _ZERO and _SMALLINT:
+ print("Eliminated")
+if _FALSE:
+ print("Eliminated")
+
+while _SMALLINT:
+ print("Kept")
+ break
+while _ZERO:
+ print("Eliminated")
+while _FALSE:
+ print("Eliminated")
+
+# These values are stored in variables, and therefore bytecode will contain JUMP_IF
+
+a = _EMPTY_TUPLE or _STR
+if a == _STR:
+ print("Kept")
+
+b = _SMALLINT and _STR
+if b == _STR:
+ print("Kept")
+
+# The compiler is also unable to optimise these expressions, even though the arguments are const,
+# so these also contain JUMP_IF
+
+if (_EMPTY_TUPLE or _STR) == _STR:
+ print("Kept")
+
+if (_EMPTY_TUPLE and _STR) == _STR:
+ print("Not Eliminated")
+
+if (not _STR) == _FALSE:
+ print("Kept")
+
+assert True
diff --git a/tests/cmdline/cmd_showbc_const.py.exp b/tests/cmdline/cmd_showbc_const.py.exp
new file mode 100644
index 000000000..6cdc3e9c9
--- /dev/null
+++ b/tests/cmdline/cmd_showbc_const.py.exp
@@ -0,0 +1,160 @@
+File cmdline/cmd_showbc_const.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ 198 bytes)
+Raw bytecode (code_info_size=40, bytecode_size=158):
+ 2c 4c 01 60 2c 46 22 65 27 4a 83 0c 20 27 40 20
+ 27 20 27 40 60 20 27 24 40 60 40 24 27 47 24 27
+ 67 40 27 47 27 47 26 47 80 10 02 2a 01 1b 03 1c
+ 02 16 02 59 80 51 1b 04 16 04 48 0f 11 04 13 05
+ 59 11 09 10 06 34 01 59 11 0a 65 57 11 0b df 44
+ 43 59 4a 01 5d 11 09 10 07 34 01 59 11 09 10 07
+ 34 01 59 11 09 10 07 34 01 59 11 09 10 07 34 01
+ 59 42 42 42 35 23 00 16 0c 11 0c 23 00 d9 44 47
+ 11 09 10 07 34 01 59 23 00 16 0d 11 0d 23 00 d9
+ 44 47 11 09 10 07 34 01 59 23 00 23 00 d9 44 47
+ 11 09 10 07 34 01 59 23 01 23 00 d9 44 47 11 09
+ 23 02 34 01 59 50 23 03 d9 44 47 11 09 10 07 34
+ 01 59 42 40 51 63
+arg names:
+(N_STATE 6)
+(N_EXC_STACK 1)
+ bc=0 line=1
+ bc=0 line=4
+ bc=12 line=5
+ bc=18 line=7
+ bc=20 line=8
+ bc=25 line=11
+ bc=32 line=12
+ bc=42 line=14
+ bc=45 line=26
+ bc=45 line=27
+ bc=52 line=28
+ bc=52 line=30
+ bc=52 line=31
+ bc=59 line=32
+ bc=59 line=33
+ bc=66 line=34
+ bc=66 line=36
+ bc=66 line=39
+ bc=66 line=40
+ bc=73 line=41
+ bc=77 line=42
+ bc=77 line=44
+ bc=77 line=47
+ bc=77 line=49
+ bc=81 line=50
+ bc=88 line=51
+ bc=95 line=53
+ bc=99 line=54
+ bc=106 line=55
+ bc=113 line=58
+ bc=113 line=60
+ bc=120 line=61
+ bc=127 line=63
+ bc=134 line=64
+ bc=141 line=66
+ bc=147 line=67
+ bc=154 line=69
+00 LOAD_CONST_SMALL_INT 0
+01 LOAD_CONST_STRING 'const'
+03 BUILD_TUPLE 1
+05 IMPORT_NAME 'micropython'
+07 IMPORT_FROM 'const'
+09 STORE_NAME const
+11 POP_TOP
+12 LOAD_CONST_SMALL_INT 0
+13 LOAD_CONST_NONE
+14 IMPORT_NAME 'sys'
+16 STORE_NAME sys
+18 SETUP_EXCEPT 35
+20 LOAD_NAME sys
+22 LOAD_ATTR settrace
+24 POP_TOP
+25 LOAD_NAME print
+27 LOAD_CONST_STRING 'SKIP'
+29 CALL_FUNCTION n=1 nkw=0
+31 POP_TOP
+32 LOAD_NAME SystemExit
+34 RAISE_OBJ
+35 DUP_TOP
+36 LOAD_NAME AttributeError
+38 BINARY_OP 8
+39 POP_JUMP_IF_FALSE 44
+41 POP_TOP
+42 POP_EXCEPT_JUMP 45
+44 END_FINALLY
+45 LOAD_NAME print
+47 LOAD_CONST_STRING 'Kept'
+49 CALL_FUNCTION n=1 nkw=0
+51 POP_TOP
+52 LOAD_NAME print
+54 LOAD_CONST_STRING 'Kept'
+56 CALL_FUNCTION n=1 nkw=0
+58 POP_TOP
+59 LOAD_NAME print
+61 LOAD_CONST_STRING 'Kept'
+63 CALL_FUNCTION n=1 nkw=0
+65 POP_TOP
+66 LOAD_NAME print
+68 LOAD_CONST_STRING 'Kept'
+70 CALL_FUNCTION n=1 nkw=0
+72 POP_TOP
+73 JUMP 77
+75 JUMP 66
+77 LOAD_CONST_OBJ \.\+='foo'
+79 STORE_NAME a
+81 LOAD_NAME a
+83 LOAD_CONST_OBJ \.\+='foo'
+85 BINARY_OP 2 __eq__
+86 POP_JUMP_IF_FALSE 95
+88 LOAD_NAME print
+90 LOAD_CONST_STRING 'Kept'
+92 CALL_FUNCTION n=1 nkw=0
+94 POP_TOP
+95 LOAD_CONST_OBJ \.\+='foo'
+97 STORE_NAME b
+99 LOAD_NAME b
+101 LOAD_CONST_OBJ \.\+='foo'
+103 BINARY_OP 2 __eq__
+104 POP_JUMP_IF_FALSE 113
+106 LOAD_NAME print
+108 LOAD_CONST_STRING 'Kept'
+110 CALL_FUNCTION n=1 nkw=0
+112 POP_TOP
+113 LOAD_CONST_OBJ \.\+='foo'
+115 LOAD_CONST_OBJ \.\+='foo'
+117 BINARY_OP 2 __eq__
+118 POP_JUMP_IF_FALSE 127
+120 LOAD_NAME print
+122 LOAD_CONST_STRING 'Kept'
+124 CALL_FUNCTION n=1 nkw=0
+126 POP_TOP
+127 LOAD_CONST_OBJ \.\+=()
+129 LOAD_CONST_OBJ \.\+='foo'
+131 BINARY_OP 2 __eq__
+132 POP_JUMP_IF_FALSE 141
+134 LOAD_NAME print
+136 LOAD_CONST_OBJ \.\+='Not Eliminated'
+138 CALL_FUNCTION n=1 nkw=0
+140 POP_TOP
+141 LOAD_CONST_FALSE
+142 LOAD_CONST_OBJ \.\+=False
+144 BINARY_OP 2 __eq__
+145 POP_JUMP_IF_FALSE 154
+147 LOAD_NAME print
+149 LOAD_CONST_STRING 'Kept'
+151 CALL_FUNCTION n=1 nkw=0
+153 POP_TOP
+154 JUMP 156
+156 LOAD_CONST_NONE
+157 RETURN_VALUE
+Kept
+Kept
+Kept
+Kept
+Kept
+Kept
+Kept
+Kept
+mem: total=\\d\+, current=\\d\+, peak=\\d\+
+stack: \\d\+ out of \\d\+
+GC: total: \\d\+, used: \\d\+, free: \\d\+
+ No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+