Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse: Implement hacky way to handle full range of small ints. #313

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion py/compile.c
Expand Up @@ -148,6 +148,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
break;

case PN_factor_2:
// TODO: Handle specially incoded MP_PARSE_NODE_INT here too?
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
Expand Down Expand Up @@ -2519,7 +2520,18 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break;
case MP_PARSE_NODE_SMALL_INT: EMIT_ARG(load_const_small_int, arg); break;
case MP_PARSE_NODE_INTEGER: EMIT_ARG(load_const_int, arg); break;
case MP_PARSE_NODE_INTEGER: {
const char *p = qstr_str(arg);
if (*p == 0) {
// Specially encoded full-range small int
machine_int_t val;
memcpy(&val, p + 1, sizeof(val));
EMIT_ARG(load_const_small_int, val);
} else {
EMIT_ARG(load_const_int, arg);
}
break;
}
case MP_PARSE_NODE_DECIMAL: EMIT_ARG(load_const_dec, arg); break;
case MP_PARSE_NODE_STRING: EMIT_ARG(load_const_str, arg, false); break;
case MP_PARSE_NODE_BYTES: EMIT_ARG(load_const_str, arg, true); break;
Expand Down
14 changes: 12 additions & 2 deletions py/parse.c
Expand Up @@ -11,6 +11,7 @@
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"

#define RULE_ACT_KIND_MASK (0xf0)
#define RULE_ACT_ARG_MASK (0x0f)
Expand Down Expand Up @@ -279,8 +280,17 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
}
if (dec) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn(str, len));
} else if (small_int && !overflow && MP_PARSE_FITS_SMALL_INT(int_val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val);
} else if (small_int && !overflow && MP_OBJ_FITS_SMALL_INT(int_val)) {
if (MP_PARSE_FITS_SMALL_INT(int_val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val);
} else {
// If value doesn't fit into parser's small int, but fits into
// object small int, encode it in special form of MP_PARSE_NODE_INTEGER
char buf[BYTES_PER_WORD + 1];
buf[0] = 0;
memcpy(buf + 1, &int_val, sizeof(int_val));
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn(buf, sizeof(buf)));
}
} else {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn(str, len));
}
Expand Down
25 changes: 25 additions & 0 deletions tests/basics/int-small.py
@@ -1,5 +1,30 @@
# This tests small int range for 32-bit machine

# Small ints are variable-length encoded in MicroPython, so first
# test that encoding works as expected.

print(0)
print(1)
print(-1)
# Value is split in 7-bit "subwords", and taking into account that all
# ints in Python are signed, there're 6 bits of magnitude. So, around 2^6
# there's "turning point"
print(63)
print(64)
print(65)
print(-63)
print(-64)
print(-65)
# Maximum values of small ints on 32-bit platform
print(1073741823)
# Per python semantics, lexical integer is without a sign (i.e. positive)
# and '-' is unary minus operation applied to it. That's why -1073741824
# (min two-complement's negative value) is not allowed. To fix this,
# see compile.c:fold_constants()
print(-1073741823)

# Operations tests

a = 0x3fffff
print(a)
a *= 0x10
Expand Down