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.
This commit is contained in:
Damien George 2017-12-11 22:39:12 +11:00
parent 9c02707356
commit 2759bec858
4 changed files with 21 additions and 9 deletions

View File

@ -79,7 +79,7 @@
// - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff
// - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf
// - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan
// - 01111111 11111101 00000000 00000000 iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int
// - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int
// - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str
// - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)
// Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000.

View File

@ -170,8 +170,8 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0001000000000000); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((intptr_t)(o)) >> 1)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((uintptr_t)(small_int)) << 1) | 0x0001000000000001)
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17)
#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001)
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0002000000000000); }

View File

@ -369,6 +369,18 @@ STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line,
return (mp_parse_node_t)pn;
}
STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_obj_t o_val) {
(void)parser;
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_val);
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
// A parse node is only 32-bits and the small-int value must fit in 31-bits
if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) {
return make_node_const_object(parser, 0, o_val);
}
#endif
return mp_parse_node_new_small_int(val);
}
STATIC void push_result_token(parser_t *parser, const rule_t *rule) {
mp_parse_node_t pn;
mp_lexer_t *lex = parser->lexer;
@ -380,7 +392,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) {
if (rule->rule_id == RULE_atom
&& (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) {
if (MP_OBJ_IS_SMALL_INT(elem->value)) {
pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(elem->value));
pn = mp_parse_node_new_small_int_checked(parser, elem->value);
} else {
pn = make_node_const_object(parser, lex->tok_line, elem->value);
}
@ -394,7 +406,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_small_int(MP_OBJ_SMALL_INT_VALUE(o));
pn = mp_parse_node_new_small_int_checked(parser, o);
} else {
pn = make_node_const_object(parser, lex->tok_line, o);
}
@ -686,7 +698,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_small_int(MP_OBJ_SMALL_INT_VALUE(arg0)));
push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0));
} else {
// TODO reuse memory for parse node struct?
push_result_node(parser, make_node_const_object(parser, 0, arg0));

View File

@ -50,10 +50,10 @@
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffffffff80000000) >> 1))
#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffffffff80000000) == 0)
#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffff800000000000) >> 1))
#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffff800000000000) == 0)
// Mask to truncate mp_int_t to positive value
#define MP_SMALL_INT_POSITIVE_MASK ~(0xffffffff80000000 | (0xffffffff80000000 >> 1))
#define MP_SMALL_INT_POSITIVE_MASK ~(0xffff800000000000 | (0xffff800000000000 >> 1))
#endif