summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-01-12 16:32:21 -0800
committerDamien George <damien.p.george@gmail.com>2014-01-12 16:32:21 -0800
commitec3e14e2af48432a406d840896ae4551ddff0b7f (patch)
treeaa885d4d1d6840c3ecfa08ecaea5cfdc6dd0c251
parent45eb6eaa547384b595b8ef489bd5feb36e9c8ef1 (diff)
parent48b3572f7eb70a1af97f008d342ee266fdfc0717 (diff)
downloadmicropython-ec3e14e2af48432a406d840896ae4551ddff0b7f.tar.gz
micropython-ec3e14e2af48432a406d840896ae4551ddff0b7f.zip
Merge pull request #160 from pfalcon/elaborate-int
Elaborate small-int/long-int
-rw-r--r--py/gc.c7
-rw-r--r--py/mpconfig.h17
-rw-r--r--py/obj.h4
-rw-r--r--py/objint.c44
-rw-r--r--py/parse.c13
-rw-r--r--py/runtime.c17
-rw-r--r--tests/basics/tests/int-small.py26
7 files changed, 105 insertions, 23 deletions
diff --git a/py/gc.c b/py/gc.c
index 054a3cc315..70b071ebc8 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -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__
diff --git a/py/obj.h b/py/obj.h
index b92f1e2a7e..a9a5827ee7 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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