Commit Graph

139 Commits

Author SHA1 Message Date
Angus Gratton 25ff5b52d9 py/parse: Allow const types other than int to optimise as true/false.
Allows optimisation of cases like:

    import micropython
    _DEBUG = micropython.const(False)
    if _DEBUG:
        print('Debugging info')

Previously the 'if' statement was only optimised out if the type of the
const() argument was integer.

The change is implemented in a way that makes the compiler slightly smaller
(-16 bytes on PYBV11) but compilation will also be very slightly slower.

As a bonus, if const support is enabled then the compiler can now optimise
const truthy/falsey expressions of other types, like:

    while "something":
        pass

... unclear if that is useful, but perhaps it could be.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2022-09-23 16:04:13 +10:00
Damien George 627ba38154 py/parsenum: Optimise when building with complex disabled.
To reduce code size when MICROPY_PY_BUILTINS_COMPLEX is disabled.

Signed-off-by: Damien George <damien@micropython.org>
2022-06-23 11:46:47 +10:00
Damien George f63b4f85aa py/parse: Work around xtensa esp-2020r3 compiler bug.
This commit works around a bug in xtensa-esp32-elf-gcc version esp-2020r3.

The bug is in generation of loop constructs.  The below code is generated
by the xtensa-esp32 compiler.  The first extract is the buggy machine code
and the second extract is the corrected machine code.  The test
`basics/logic_constfolding.py` fails with the first code and succeeds with
the second.

Disassembly of section .text.push_result_rule:

00000000 <push_result_rule>:
  ...
  d6:   209770       or      a9, a7, a7
  d9:   178976       loop    a9, f4 <push_result_rule+0xf4>
                     d9: R_XTENSA_SLOT0_OP   .text.push_result_rule+0xf4
  dc:   030190       rsr.lend        a9
  df:   130090       wsr.lbeg        a9
  e2:   a8c992       addi    a9, a9, -88
  e5:   06d992       addmi   a9, a9, 0x600
  e8:   130190       wsr.lend        a9
  eb:   002000       isync
  ee:   030290       rsr.lcount      a9
  f1:   01c992       addi    a9, a9, 1
  f4:   1494e7       bne     a4, a14, 10c <push_result_rule+0x10c>
                     f4: R_XTENSA_SLOT0_OP   .text.push_result_rule+0x10c

Disassembly of section .text.push_result_rule:

00000000 <push_result_rule>:
  ...
  d6:   209770       or      a9, a7, a7
  d9:   178976       loop    a9, f4 <push_result_rule+0xf4>
                     d9: R_XTENSA_SLOT0_OP   .text.push_result_rule+0xf4
  dc:   030190       rsr.lend        a9
  df:   130090       wsr.lbeg        a9
  e2:   000091       l32r    a9, fffc00e4 <push_result_rule+0xfffc00e4>
                     e2: R_XTENSA_SLOT0_OP   .literal.push_result_rule+0x18
  e5:   0020f0       nop
  e8:   130190       wsr.lend        a9
  eb:   002000       isync
  ee:   030290       rsr.lcount      a9
  f1:   01c992       addi    a9, a9, 1
  f4:   1494e7       bne     a4, a14, 10c <push_result_rule+0x10c>
                     f4: R_XTENSA_SLOT0_OP   .text.push_result_rule+0x10c

Work done in collaboration with @jimmo.

Signed-off-by: Damien George <damien@micropython.org>
2022-06-09 13:56:30 +10:00
Damien George 079f3e5e5b py/parse: Allow all constant objects to be used in "X = const(o)".
Now that constant tuples are supported in the parser, eg (1, True, "str"),
it's a small step to allow anything that is a constant to be used with the
pattern:

    from micropython import const

    X = const(obj)

This commit makes the required changes to allow the following types of
constants:

    from micropython import const

    _INT = const(123)
    _FLOAT = const(1.2)
    _COMPLEX = const(3.4j)
    _STR = const("str")
    _BYTES = const(b"bytes")
    _TUPLE = const((_INT, _STR, _BYTES))
    _TUPLE2 = const((None, False, True, ..., (), _TUPLE))

Prior to this, only integers could be used in const(...).

Signed-off-by: Damien George <damien@micropython.org>
2022-05-18 16:18:35 +10:00
Damien George 35c0cff92b py/parse: Add MICROPY_COMP_CONST_TUPLE option to build const tuples.
This commit adds support to the parser so that tuples which contain only
constant elements (bool, int, str, bytes, etc) are immediately converted to
a tuple object.  This makes it more efficient to use tuples containing
constant data because they no longer need to be created at runtime by the
bytecode (or native code).

Furthermore, with this improvement constant tuples that are part of frozen
code are now able to be stored fully in ROM (this will be implemented in
later commits).

Code size is increased by about 400 bytes on Cortex-M4 platforms.

See related issue #722.

Signed-off-by: Damien George <damien@micropython.org>
2022-04-14 23:52:12 +10:00
Damien George 24bc1f61f9 py/parse: Print const object value in mp_parse_node_print.
To give more information when printing the parse tree.

Signed-off-by: Damien George <damien@micropython.org>
2022-04-14 22:45:42 +10:00
Damien George e52f14d057 py/parse: Factor obj extract code to mp_parse_node_extract_const_object.
Signed-off-by: Damien George <damien@micropython.org>
2022-04-14 22:44:56 +10:00
Damien George 962ad8622e py/parse: Handle check for target small-int size in parser.
This means that all constants for EMIT_ARG(load_const_obj, obj) are created
in the parser (rather than some in the compiler).

Signed-off-by: Damien George <damien@micropython.org>
2022-03-16 00:41:10 +11:00
Damien George 3c7cab4e98 py/parse: Put const bytes objects in parse tree as const object.
Instead of as an intermediate qstr, which may unnecessarily intern the data
of the bytes object.

Signed-off-by: Damien George <damien@micropython.org>
2022-03-16 00:41:10 +11:00
Damien George 65851ebb51 py/parse: Simplify handling of const int parse nodes.
Signed-off-by: Damien George <damien@micropython.org>
2022-03-16 00:00:25 +11:00
Damien George e6850838cd py/parse: Simplify parse nodes representing a list.
This commit simplifies and optimises the parse tree in-memory
representation of lists of expressions, for tuples and lists, and when
tuples are used on the left-hand-side of assignments and within del
statements.  This reduces memory usage of the parse tree when such code is
compiled, and also reduces the size of the compiler.

For example, (1,) was previously the following parse tree:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=2)
          int(1)
          testlist_comp_3b(149) (n=1)
            NULL
      NULL

and with this commit is now:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=1)
          int(1)
      NULL

Similarly, (1, 2, 3) was previously:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=2)
          int(1)
          testlist_comp_3c(150) (n=2)
            int(2)
            int(3)
      NULL

and is now:

    expr_stmt(5) (n=2)
      atom_paren(45) (n=1)
        testlist_comp(146) (n=3)
          int(1)
          int(2)
          int(3)
      NULL

Signed-off-by: Damien George <damien@micropython.org>
2021-09-10 14:09:44 +10:00
Jim Mussared 692d36d779 py: Implement partial PEP-498 (f-string) support.
This implements (most of) the PEP-498 spec for f-strings and is based on
https://github.com/micropython/micropython/pull/4998 by @klardotsh.

It is implemented in the lexer as a syntax translation to `str.format`:
  f"{a}" --> "{}".format(a)

It also supports:
  f"{a=}" --> "a={}".format(a)

This is done by extracting the arguments into a temporary vstr buffer,
then after the string has been tokenized, the lexer input queue is saved
and the contents of the temporary vstr buffer are injected into the lexer
instead.

There are four main limitations:
- raw f-strings (`fr` or `rf` prefixes) are not supported and will raise
  `SyntaxError: raw f-strings are not supported`.

- literal concatenation of f-strings with adjacent strings will fail
    "{}" f"{a}" --> "{}{}".format(a)    (str.format will incorrectly use
                                         the braces from the non-f-string)
    f"{a}" f"{a}" --> "{}".format(a) "{}".format(a) (cannot concatenate)

- PEP-498 requires the full parser to understand the interpolated
  argument, however because this entirely runs in the lexer it cannot
  resolve nested braces in expressions like
    f"{'}'}"

- The !r, !s, and !a conversions are not supported.

Includes tests and cpydiffs.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
2021-08-14 16:58:40 +10:00
Damien George 843dcd4f85 py/parse: Expose rule-name printing as MICROPY_DEBUG_PARSE_RULE_NAME.
So it can be enabled without modifying the source.

Signed-off-by: Damien George <damien@micropython.org>
2020-10-01 15:26:43 +10:00
Damien George acdb0608b7 py/parse: Pass in an mp_print_t to mp_parse_node_print.
So the output can be redirected if needed.

Signed-off-by: Damien George <damien@micropython.org>
2020-09-11 23:00:03 +10:00
Damien George 172fc040aa py/parse: Make mp_parse_node_extract_list return size_t instead of int.
Because this function can only return non-negative values, and having the
correct return type gives more information to the caller.
2020-05-09 00:55:44 +10:00
Damien George 4ede703687 py/parse: Support constant folding of power operator for integers.
Constant expression like "2 ** 3" will now be folded, and the special form
"X = const(2 ** 3)" will now compile because the argument to the const is
now a constant.

Fixes issue #5865.
2020-05-03 16:23:19 +10:00
stijn 84fa3312cf all: Format code to add space after C++-style comment start.
Note: the uncrustify configuration is explicitly set to 'add' instead of
'force' in order not to alter the comments which use extra spaces after //
as a means of indenting text for clarity.
2020-04-23 11:24:25 +10:00
Damien George 4914731e58 py/parse: Remove unnecessary check in const folding for ** operator.
In this part of the code there is no way to get the ** operator, so no need
to check for it.

This commit also adds tests for this, and other related, invalid const
operations.
2020-04-09 16:02:39 +10:00
Jim Mussared def76fe4d9 all: Use MP_ERROR_TEXT for all error messages. 2020-04-05 15:02:06 +10:00
Damien George 69661f3343 all: Reformat C and Python source code with tools/codeformat.py.
This is run with uncrustify 0.70.1, and black 19.10b0.
2020-02-28 10:33:03 +11:00
Damien George 3f39d18c2b all: Add *FORMAT-OFF* in various places.
This string is recognised by uncrustify, to disable formatting in the
region marked by these comments.  This is necessary in the qstrdef*.h files
to prevent modification of the strings within the Q(...).  In other places
it is used to prevent excessive reformatting that would make the code less
readable.
2020-02-28 10:31:07 +11:00
Damien George b86075ef1f py/parse: Add parenthesis around calculated bit-width in struct.
To improve interaction with uncrustify formatter.
2020-02-28 10:30:52 +11:00
Josh Lloyd 7d58a197cf py: Rename MP_QSTR_NULL to MP_QSTRnull to avoid intern collisions.
Fixes #5140.
2019-09-26 16:04:56 +10:00
Damien George 2069c563f9 py: Add support for matmul operator @ as per PEP 465.
To make progress towards MicroPython supporting Python 3.5, adding the
matmul operator is important because it's a really "low level" part of the
language, being a new token and modifications to the grammar.

It doesn't make sense to make it configurable because 1) it would make the
grammar and lexer complicated/messy; 2) no other operators are
configurable; 3) it's not a feature that can be "dynamically plugged in"
via an import.

And matmul can be useful as a general purpose user-defined operator, it
doesn't have to be just for numpy use.

Based on work done by Jim Mussared.
2019-09-26 15:12:39 +10:00
Damien George 9bf2feba63 py/parse: Use calculation instead of table to convert token to operator. 2019-09-26 14:37:26 +10:00
Damien George 6ce7c051e8 py/lexer: Reorder operator tokens to match corresponding binary ops. 2019-09-26 14:37:26 +10:00
Damien George eee1e8841a py: Downcase all MP_OBJ_IS_xxx macros to make a more consistent C API.
These macros could in principle be (inline) functions so it makes sense to
have them lower case, to match the other C API functions.

The remaining macros that are upper case are:
- MP_OBJ_TO_PTR, MP_OBJ_FROM_PTR
- MP_OBJ_NEW_SMALL_INT, MP_OBJ_SMALL_INT_VALUE
- MP_OBJ_NEW_QSTR, MP_OBJ_QSTR_VALUE
- MP_OBJ_FUN_MAKE_SIG
- MP_DECLARE_CONST_xxx
- MP_DEFINE_CONST_xxx

These must remain macros because they are used when defining const data (at
least, MP_OBJ_NEW_SMALL_INT is so it makes sense to have
MP_OBJ_SMALL_INT_VALUE also a macro).

For those macros that have been made lower case, compatibility macros are
provided for the old names so that users do not need to change their code
immediately.
2019-02-12 14:54:51 +11:00
Damien George b01f66c5f1 py: Shorten error messages by using contractions and some rewording. 2018-09-20 14:33:10 +10:00
Damien George c7cb1dfcb9 py/parse: Fix macro evaluation by avoiding empty __VA_ARGS__.
Empty __VA_ARGS__ are not allowed in the C preprocessor so adjust the rule
arg offset calculation to not use them.  Also, some compilers (eg MSVC)
require an extra layer of macro expansion.
2017-12-29 13:44:26 +11:00
Damien George d3fbfa491f py/parse: Update debugging code to compile on 64-bit arch. 2017-12-29 00:13:36 +11:00
Damien George 0016a45368 py/parse: Compress rule pointer table to table of offsets.
This is the sixth and final patch in a series of patches to the parser that
aims to reduce code size by compressing the data corresponding to the rules
of the grammar.

Prior to this set of patches the rules were stored as rule_t structs with
rule_id, act and arg members.  And then there was a big table of pointers
which allowed to lookup the address of a rule_t struct given the id of that
rule.

The changes that have been made are:
- Breaking up of the rule_t struct into individual components, with each
  component in a separate array.
- Removal of the rule_id part of the struct because it's not needed.
- Put all the rule arg data in a big array.
- Change the table of pointers to rules to a table of offsets within the
  array of rule arg data.

The last point is what is done in this patch here and brings about the
biggest decreases in code size, because an array of pointers is now an
array of bytes.

Code size changes for the six patches combined is:

   bare-arm:  -644
minimal x86: -1856
   unix x64: -5408
unix nanbox: -2080
      stm32:  -720
    esp8266:  -812
     cc3200:  -712

For the change in parser performance: it was measured on pyboard that these
six patches combined gave an increase in script parse time of about 0.4%.
This is due to the slightly more complicated way of looking up the data for
a rule (since the 9th bit of the offset into the rule arg data table is
calculated with an if statement).  This is an acceptable increase in parse
time considering that parsing is only done once per script (if compiled on
the target).
2017-12-29 00:13:36 +11:00
Damien George c2c92ceefc py/parse: Remove rule_t struct because it's no longer needed. 2017-12-28 23:15:36 +11:00
Damien George 66d8885d85 py/parse: Pass rule_id to push_result_token, instead of passing rule_t*. 2017-12-28 23:12:10 +11:00
Damien George 815a8cd1ae py/parse: Pass rule_id to push_result_rule, instead of passing rule_t*.
Reduces code size by eliminating quite a few pointer dereferences.
2017-12-28 23:11:43 +11:00
Damien George 845511af25 py/parse: Break rule data into separate act and arg arrays.
Instead of each rule being stored in ROM as a struct with rule_id, act and
arg, the act and arg parts are now in separate arrays and the rule_id part
is removed because it's not needed.  This reduces code size, by roughly one
byte per grammar rule, around 150 bytes.
2017-12-28 23:09:49 +11:00
Damien George 1039c5e699 py/parse: Split out rule name from rule struct into separate array.
The rule name is only used for debugging, and this patch makes things a bit
cleaner by completely separating out the rule name from the rest of the
rule data.
2017-12-28 23:08:00 +11:00
Damien George 2759bec858 py: Extend nan-boxing config to have 47-bit small integers.
The nan-boxing representation has an extra 16-bits of space to store
small-int values, and making use of it allows to create and manipulate full
32-bit positive integers (ie up to 0xffffffff) without using the heap.
2017-12-11 22:39:12 +11:00
Damien George 1f1d5194d7 py/objstr: Make mp_obj_new_str_of_type check for existing interned qstr.
The function mp_obj_new_str_of_type is a general str object constructor
used in many places in the code to create either a str or bytes object.
When creating a str it should first check if the string data already exists
as an interned qstr, and if so then return the qstr object.  This patch
makes the function have such behaviour, which helps to reduce heap usage by
reusing existing interned data where possible.

The old behaviour of mp_obj_new_str_of_type (which didn't check for
existing interned data) is made available through the function
mp_obj_new_str_copy, but should only be used in very special cases.

One consequence of this patch is that the following expression is now True:

    'abc' is ' abc '.split()[0]
2017-11-16 13:53:04 +11:00
Damien George a3dc1b1957 all: Remove inclusion of internal py header files.
Header files that are considered internal to the py core and should not
normally be included directly are:
    py/nlr.h - internal nlr configuration and declarations
    py/bc0.h - contains bytecode macro definitions
    py/runtime0.h - contains basic runtime enums

Instead, the top-level header files to include are one of:
    py/obj.h - includes runtime0.h and defines everything to use the
        mp_obj_t type
    py/runtime.h - includes mpstate.h and hence nlr.h, obj.h, runtime0.h,
        and defines everything to use the general runtime support functions

Additional, specific headers (eg py/objlist.h) can be included if needed.
2017-10-04 12:37:50 +11:00
Alexander Steffen 55f33240f3 all: Use the name MicroPython consistently in comments
There were several different spellings of MicroPython present in comments,
when there should be only one.
2017-07-31 18:35:40 +10:00
Damien George f615d82d5b py/parse: Simplify handling of errors by raising them directly.
The parser was originally written to work without raising any exceptions
and instead return an error value to the caller.  But it's now required
that a call to the parser be wrapped in an nlr handler, so we may as well
make use of that fact and simplify the parser so that it doesn't need to
keep track of any memory errors that it had.  The parser anyway explicitly
raises an exception at the end if there was an error.

This patch simplifies the parser by letting the underlying memory
allocation functions raise an exception if they fail to allocate any
memory.  And if there is an error parsing the "<id> = const(<val>)" pattern
then that also raises an exception right away instead of trying to recover
gracefully and then raise.
2017-02-24 14:56:37 +11:00
Damien George 5255255fb9 py: Create str/bytes objects in the parser, not the compiler.
Previous to this patch any non-interned str/bytes objects would create a
special parse node that held a copy of the str/bytes data.  Then in the
compiler this data would be turned into a str/bytes object.  This actually
lead to 2 copies of the data, one in the parse node and one in the object.
The parse node's copy of the data would be freed at the end of the compile
stage but nevertheless it meant that the peak memory usage of the
parse/compile stage was higher than it needed to be (by an amount equal to
the number of bytes in all the non-interned str/bytes objects).

This patch changes the behaviour so that str/bytes objects are created
directly in the parser and the object stored in a const-object parse node
(which already exists for bignum, float and complex const objects).  This
reduces peak RAM usage of the parse/compile stage, simplifies the parser
and compiler, and reduces code size by about 170 bytes on Thumb2 archs,
and by about 300 bytes on Xtensa archs.
2017-02-24 13:43:43 +11:00
Damien George 74f4d2c659 py/parse: Allow parser/compiler consts to be bignums.
This patch allows uPy consts to be bignums, eg:

    X = const(1 << 100)

The infrastructure for consts to be a bignum (rather than restricted to
small integers) has been in place for a while, ever since constant folding
was upgraded to allow bignums.  It just required a small change (in this
patch) to enable it.
2017-02-24 13:03:44 +11:00
Damien George 71019ae4f5 py/grammar: Group no-compile grammar rules together to shrink tables.
Grammar rules have 2 variants: ones that are attached to a specific
compile function which is called to compile that grammar node, and ones
that don't have a compile function and are instead just inspected to see
what form they take.

In the compiler there is a table of all grammar rules, with each entry
having a pointer to the associated compile function.  Those rules with no
compile function have a null pointer.  There are 120 such rules, so that's
120 words of essentially wasted code space.

By grouping together the compile vs no-compile rules we can put all the
no-compile rules at the end of the list of rules, and then we don't need
to store the null pointers.  We just have a truncated table and it's
guaranteed that when indexing this table we only index the first half,
the half with populated pointers.

This patch implements such a grouping by having a specific macro for the
compile vs no-compile grammar rules (DEF_RULE vs DEF_RULE_NC).  It saves
around 460 bytes of code on 32-bit archs.
2017-02-16 19:45:06 +11:00
Damien George 86e942309a py/parse: Refactor code to remove assert(0)'s.
This helps to improve code coverage.  Note that most of the changes in
this patch are just de-denting the cases of the switch statements.
2017-01-17 17:00:55 +11:00
Damien George 9b525134d1 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.
2016-11-15 16:48:49 +11:00
Damien George ed9c93f0f1 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.
2016-11-15 16:48:48 +11:00
Damien George b0cbfb0492 py/parse: Move function to check for const parse node to parse.[ch]. 2016-11-15 16:48:48 +11:00
Colin Hogben f9b6b37cf6 py: Fix wrong assumption that m_renew will not move if shrinking
In both parse.c and qstr.c, an internal chunking allocator tidies up
by calling m_renew to shrink an allocated chunk to the size used, and
assumes that the chunk will not move.  However, when MICROPY_ENABLE_GC
is false, m_renew calls the system realloc, which does not guarantee
this behaviour.  Environments where realloc may return a different
pointer include:

(1) mbed-os with MBED_HEAP_STATS_ENABLED (which adds a wrapper around
malloc & friends; this is where I was hit by the bug);

(2) valgrind on linux (how I diagnosed it).

The fix is to call m_renew_maybe with allow_move=false.
2016-11-02 23:15:41 +11:00
Damien George 6d310a5552 py/parse: Only replace constants that are standalone identifiers.
This fixes constant substitution so that only standalone identifiers are
replaced with their constant value (if they have one).  I.e. don't
replace NAME in expressions like obj.NAME or NAME = expr.
2016-09-23 17:23:16 +10:00