diff options
author | Damien George <damien.p.george@gmail.com> | 2014-01-12 16:32:21 -0800 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-01-12 16:32:21 -0800 |
commit | ec3e14e2af48432a406d840896ae4551ddff0b7f (patch) | |
tree | aa885d4d1d6840c3ecfa08ecaea5cfdc6dd0c251 | |
parent | 45eb6eaa547384b595b8ef489bd5feb36e9c8ef1 (diff) | |
parent | 48b3572f7eb70a1af97f008d342ee266fdfc0717 (diff) | |
download | micropython-ec3e14e2af48432a406d840896ae4551ddff0b7f.tar.gz micropython-ec3e14e2af48432a406d840896ae4551ddff0b7f.zip |
Merge pull request #160 from pfalcon/elaborate-int
Elaborate small-int/long-int
-rw-r--r-- | py/gc.c | 7 | ||||
-rw-r--r-- | py/mpconfig.h | 17 | ||||
-rw-r--r-- | py/obj.h | 4 | ||||
-rw-r--r-- | py/objint.c | 44 | ||||
-rw-r--r-- | py/parse.c | 13 | ||||
-rw-r--r-- | py/runtime.c | 17 | ||||
-rw-r--r-- | tests/basics/tests/int-small.py | 26 |
7 files changed, 105 insertions, 23 deletions
@@ -8,15 +8,8 @@ #if MICROPY_ENABLE_GC -// a machine word is big enough to hold a pointer -/* -#define BYTES_PER_WORD (8) -typedef unsigned long machine_uint_t; -*/ typedef unsigned char byte; -#define BITS_PER_BYTE (8) -#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) #define WORDS_PER_BLOCK (4) #define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD) #define STACK_SIZE (64) // tunable; minimum is 1 diff --git a/py/mpconfig.h b/py/mpconfig.h index 2017ba366a..ada4aa2ea4 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -62,6 +62,18 @@ #define MICROPY_ENABLE_LEXER_UNIX (0) #endif +// Long int implementation +#define MICROPY_LONGINT_IMPL_NONE (0) +#define MICROPY_LONGINT_IMPL_LONGLONG (1) + +#ifndef MICROPY_LONGINT_IMPL +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG +typedef long long mp_longint_impl_t; +#endif + // Whether to support float and complex types #ifndef MICROPY_ENABLE_FLOAT #define MICROPY_ENABLE_FLOAT (0) @@ -76,6 +88,11 @@ /*****************************************************************************/ /* Miscellaneous settings */ +#define BITS_PER_BYTE (8) +#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) +// machine_int_t value with most significant bit set +#define WORD_MSBIT_HIGH (1 << (BYTES_PER_WORD * 8 - 1)) + // printf format spec to use for machine_int_t and friends #ifndef INT_FMT #ifdef __LP64__ @@ -34,6 +34,8 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // - xxxx...xx10: a qstr, bits 2 and above are the value // - xxxx...xx00: a pointer to an mp_obj_base_t +// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range +#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) #define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0) #define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2) #define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0) @@ -196,6 +198,8 @@ mp_obj_t mp_obj_new_none(void); mp_obj_t mp_obj_new_bool(bool value); mp_obj_t mp_obj_new_cell(mp_obj_t obj); mp_obj_t mp_obj_new_int(machine_int_t value); +mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value); +mp_obj_t mp_obj_new_int_from_long_str(const char *s); mp_obj_t mp_obj_new_str(qstr qstr); #if MICROPY_ENABLE_FLOAT mp_obj_t mp_obj_new_float(mp_float_t val); diff --git a/py/objint.c b/py/objint.c index 9cd5ebae29..26d3c0e337 100644 --- a/py/objint.c +++ b/py/objint.c @@ -11,8 +11,16 @@ typedef struct _mp_obj_int_t { mp_obj_base_t base; +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + mp_longint_impl_t val; +#endif } mp_obj_int_t; +void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in); +mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); + +// This dispatcher function is expected to be independent of the implementation +// of long int static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) { switch (n_args) { case 0: @@ -20,7 +28,7 @@ static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) case 1: // TODO allow string as arg and parse it - return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0])); + return mp_obj_new_int(mp_obj_get_int(args[0])); //case 2: // TODO, parse with given base @@ -33,9 +41,41 @@ static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) const mp_obj_type_t int_type = { { &mp_const_type }, "int", + .print = int_print, .make_new = int_make_new, + .binary_op = int_binary_op, }; +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE +// This is called only for non-SMALL_INT +void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { +} + +// This is called only for non-SMALL_INT +mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + assert(0); +} + +// This is called only with strings whose value doesn't fit in SMALL_INT +mp_obj_t mp_obj_new_int_from_long_str(const char *s) { + assert(0); +} + +mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) { + // SMALL_INT accepts only signed numbers, of one bit less size + // then word size, which totals 2 bits less for unsigned numbers. + if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) { + return MP_OBJ_NEW_SMALL_INT(value); + } + // TODO: Raise exception + assert(0); +} + mp_obj_t mp_obj_new_int(machine_int_t value) { - return MP_OBJ_NEW_SMALL_INT(value); + if (MP_OBJ_FITS_SMALL_INT(value)) { + return MP_OBJ_NEW_SMALL_INT(value); + } + // TODO: Raise exception + assert(0); } +#endif diff --git a/py/parse.c b/py/parse.c index a619c90507..e2c9520736 100644 --- a/py/parse.c +++ b/py/parse.c @@ -196,7 +196,7 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) { } else if (tok->kind == MP_TOKEN_NUMBER) { bool dec = false; bool small_int = true; - int int_val = 0; + machine_int_t int_val = 0; int len = tok->len; const char *str = tok->str; int base = 10; @@ -216,7 +216,9 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) { i = 2; } } + bool overflow = false; for (; i < len; i++) { + machine_int_t old_val = int_val; if (unichar_isdigit(str[i]) && str[i] - '0' < base) { int_val = base * int_val + str[i] - '0'; } else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') { @@ -230,10 +232,17 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) { small_int = false; break; } + if (int_val < old_val) { + // If new value became less than previous, it's overflow + overflow = true; + } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) { + // If signed number changed sign - it's overflow + overflow = true; + } } if (dec) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn_copy(str, len)); - } else if (small_int && MP_FIT_SMALL_INT(int_val)) { + } else if (small_int && !overflow && MP_FIT_SMALL_INT(int_val)) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val); } else { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn_copy(str, len)); diff --git a/py/runtime.c b/py/runtime.c index 8d3e900286..2af86b6abd 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -268,10 +268,6 @@ void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_ar #endif } -static bool fit_small_int(mp_small_int_t o) { - return true; -} - int rt_is_true(mp_obj_t arg) { DEBUG_OP_printf("is true %p\n", arg); if (MP_OBJ_IS_SMALL_INT(arg)) { @@ -436,13 +432,10 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) { case RT_UNARY_OP_INVERT: val = ~val; break; default: assert(0); val = 0; } - if (fit_small_int(val)) { + if (MP_OBJ_FITS_SMALL_INT(val)) { return MP_OBJ_NEW_SMALL_INT(val); - } else { - // TODO make a bignum - assert(0); - return mp_const_none; } + return mp_obj_new_int(val); } else { // will be an object (small ints are caught in previous if) mp_obj_base_t *o = arg; if (o->type->unary_op != NULL) { @@ -551,11 +544,11 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { default: assert(0); } - if (fit_small_int(lhs_val)) { + // TODO: We just should make mp_obj_new_int() inline and use that + if (MP_OBJ_FITS_SMALL_INT(lhs_val)) { return MP_OBJ_NEW_SMALL_INT(lhs_val); } - // TODO: return long int - assert(0); + return mp_obj_new_int(lhs_val); } else if (MP_OBJ_IS_TYPE(rhs, &float_type)) { return mp_obj_float_binary_op(op, lhs_val, rhs); } else if (MP_OBJ_IS_TYPE(rhs, &complex_type)) { diff --git a/tests/basics/tests/int-small.py b/tests/basics/tests/int-small.py new file mode 100644 index 0000000000..be338c4a4c --- /dev/null +++ b/tests/basics/tests/int-small.py @@ -0,0 +1,26 @@ +# This test small int range for 32-bit machine + +a = 0x3fffff +print(a) +a *= 0x10 +print(a) +a *= 0x10 +print(a) +a += 0xff +print(a) +# This would overflow +#a += 1 + +a = -0x3fffff +print(a) +a *= 0x10 +print(a) +a *= 0x10 +print(a) +a -= 0xff +print(a) +# This still doesn't overflow +a -= 1 +print(a) +# This would overflow +#a -= 1 |