diff options
-rw-r--r-- | py/compile.c | 6 | ||||
-rw-r--r-- | py/mpz.c | 73 | ||||
-rw-r--r-- | py/obj.h | 4 | ||||
-rw-r--r-- | py/objint.c | 3 | ||||
-rw-r--r-- | py/objint_longlong.c | 3 | ||||
-rw-r--r-- | py/objint_mpz.c | 3 | ||||
-rw-r--r-- | py/parse.c | 20 | ||||
-rw-r--r-- | py/parse.h | 7 | ||||
-rw-r--r-- | py/parsenum.c | 17 | ||||
-rw-r--r-- | py/runtime.c | 2 | ||||
-rw-r--r-- | py/smallint.c | 1 | ||||
-rw-r--r-- | py/smallint.h | 5 | ||||
-rw-r--r-- | qemu-arm/README.md | 23 | ||||
-rw-r--r-- | tests/basics/int-big-and.py | 24 |
14 files changed, 138 insertions, 53 deletions
diff --git a/py/compile.c b/py/compile.c index f925c8c1ff..31ecbf0b91 100644 --- a/py/compile.c +++ b/py/compile.c @@ -249,7 +249,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m // shouldn't happen assert(0); } - if (MP_PARSE_FITS_SMALL_INT(arg0)) { + if (MP_SMALL_INT_FITS(arg0)) { //printf("%ld + %ld\n", arg0, arg1); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0); } @@ -264,7 +264,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m // int * int if (!mp_small_int_mul_overflow(arg0, arg1)) { arg0 *= arg1; - if (MP_PARSE_FITS_SMALL_INT(arg0)) { + if (MP_SMALL_INT_FITS(arg0)) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0); } } @@ -337,7 +337,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m mp_load_method_maybe(elem->value, q_attr, dest); if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) { machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]); - if (MP_PARSE_FITS_SMALL_INT(val)) { + if (MP_SMALL_INT_FITS(val)) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val); } } @@ -218,6 +218,38 @@ STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz return idig + 1 - oidig; } +/* computes i = j & -k = j & (~k + 1) + returns number of digits in i + assumes enough memory in i; assumes normalised j, k + can have i, j, k pointing to same memory +*/ +STATIC uint mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) { + mpz_dig_t *oidig = idig; + mpz_dbl_dig_t carry = 1; + + for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) { + carry += *kdig ^ DIG_MASK; + *idig = (*jdig & carry) & DIG_MASK; + carry >>= DIG_SIZE; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + carry += DIG_MASK; + *idig = (*jdig & carry) & DIG_MASK; + carry >>= DIG_SIZE; + } + + if (carry != 0) { + *idig = carry; + } else { + // remove trailing zeros + for (--idig; idig >= oidig && *idig == 0; --idig) { + } + } + + return idig + 1 - oidig; +} + /* computes i = j | k returns number of digits in i assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen @@ -896,24 +928,35 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { can have dest, lhs, rhs the same */ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { - // make sure lhs has the most digits - if (lhs->len < rhs->len) { - const mpz_t *temp = lhs; - lhs = rhs; - rhs = temp; - } - if (lhs->neg == rhs->neg) { - mpz_need_dig(dest, rhs->len); - dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + if (lhs->neg == 0) { + // make sure lhs has the most digits + if (lhs->len < rhs->len) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + // do the and'ing + mpz_need_dig(dest, rhs->len); + dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + dest->neg = 0; + } else { + // TODO both args are negative + assert(0); + } } else { - mpz_need_dig(dest, lhs->len); - // TODO - assert(0); -// dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + // args have different sign + // make sure lhs is the positive arg + if (rhs->neg == 0) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + mpz_need_dig(dest, lhs->len + 1); + dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + assert(dest->len <= dest->alloc); + dest->neg = 0; } - - dest->neg = lhs->neg; } /* computes dest = lhs | rhs @@ -72,10 +72,6 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // These macros check for small int, qstr or object, and access small int and qstr values -// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range -#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1)) -#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN))) -#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) // these macros have now become inline functions; see below //#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) diff --git a/py/objint.c b/py/objint.c index 7d6258b7d4..f631d698f3 100644 --- a/py/objint.c +++ b/py/objint.c @@ -35,6 +35,7 @@ #include "qstr.h" #include "obj.h" #include "parsenum.h" +#include "smallint.h" #include "mpz.h" #include "objint.h" #include "runtime0.h" @@ -251,7 +252,7 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) { } mp_obj_t mp_obj_new_int(machine_int_t value) { - if (MP_OBJ_FITS_SMALL_INT(value)) { + if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 381246dfe4..82db9e6608 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -34,6 +34,7 @@ #include "misc.h" #include "qstr.h" #include "obj.h" +#include "smallint.h" #include "mpz.h" #include "objint.h" #include "runtime0.h" @@ -140,7 +141,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } mp_obj_t mp_obj_new_int(machine_int_t value) { - if (MP_OBJ_FITS_SMALL_INT(value)) { + if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } return mp_obj_new_int_from_ll(value); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 733dc096a6..9cdbb71688 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -35,6 +35,7 @@ #include "qstr.h" #include "parsenumbase.h" #include "obj.h" +#include "smallint.h" #include "mpz.h" #include "objint.h" #include "runtime0.h" @@ -239,7 +240,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } mp_obj_t mp_obj_new_int(machine_int_t value) { - if (MP_OBJ_FITS_SMALL_INT(value)) { + if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } return mp_obj_new_int_from_ll(value); diff --git a/py/parse.c b/py/parse.c index 93bced843b..af09c335f2 100644 --- a/py/parse.c +++ b/py/parse.c @@ -36,6 +36,7 @@ #include "lexer.h" #include "parsenumbase.h" #include "parse.h" +#include "smallint.h" #define RULE_ACT_KIND_MASK (0xf0) #define RULE_ACT_ARG_MASK (0x0f) @@ -311,13 +312,13 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) { int i = mp_parse_num_base(str, len, &base); bool overflow = false; for (; i < len; i++) { - machine_int_t old_val = int_val; + int dig; if (unichar_isdigit(str[i]) && str[i] - '0' < base) { - int_val = base * int_val + str[i] - '0'; + dig = str[i] - '0'; } else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') { - int_val = base * int_val + str[i] - 'a' + 10; + dig = str[i] - 'a' + 10; } else if (base == 16 && 'A' <= str[i] && str[i] <= 'F') { - int_val = base * int_val + str[i] - 'A' + 10; + dig = str[i] - 'A' + 10; } else if (str[i] == '.' || str[i] == 'e' || str[i] == 'E' || str[i] == 'j' || str[i] == 'J') { dec = true; break; @@ -325,17 +326,18 @@ 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 + // add next digi and check for overflow + if (mp_small_int_mul_overflow(int_val, base)) { overflow = true; - } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) { - // If signed number changed sign - it's overflow + } + int_val = int_val * base + dig; + if (!MP_SMALL_INT_FITS(int_val)) { overflow = true; } } 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)) { + } else if (small_int && !overflow && MP_SMALL_INT_FITS(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(str, len)); diff --git a/py/parse.h b/py/parse.h index 43c74e73b8..6950139e7b 100644 --- a/py/parse.h +++ b/py/parse.h @@ -37,13 +37,6 @@ struct _mp_lexer_t; // - xx...x10010: a string of bytes; bits 5 and above are the qstr holding the value // - xx...x10110: a token; bits 5 and above are mp_token_kind_t -// TODO: these can now be unified with MP_OBJ_FITS_SMALL_INT(x) -// makes sure the top 2 bits of x are all cleared (positive number) or all set (negavite number) -// these macros can probably go somewhere else because they are used more than just in the parser -#define MP_UINT_HIGH_2_BITS (~((~((machine_uint_t)0)) >> 2)) -// parser's small ints are different from VM small int -#define MP_PARSE_FITS_SMALL_INT(x) (((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == 0) || ((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == MP_UINT_HIGH_2_BITS)) - #define MP_PARSE_NODE_NULL (0) #define MP_PARSE_NODE_SMALL_INT (0x1) #define MP_PARSE_NODE_ID (0x02) diff --git a/py/parsenum.c b/py/parsenum.c index 842a9e9599..9729ffe64a 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -34,6 +34,7 @@ #include "obj.h" #include "parsenumbase.h" #include "parsenum.h" +#include "smallint.h" #if MICROPY_ENABLE_FLOAT #include <math.h> @@ -70,16 +71,16 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { machine_int_t int_val = 0; const char *restrict str_val_start = str; for (; str < top; str++) { - machine_int_t old_val = int_val; + // get next digit as a value int dig = *str; if (unichar_isdigit(dig) && dig - '0' < base) { // 0-9 digit - int_val = base * int_val + dig - '0'; + dig = dig - '0'; } else if (base == 16) { dig |= 0x20; if ('a' <= dig && dig <= 'f') { // a-f hex digit - int_val = base * int_val + dig - 'a' + 10; + dig = dig - 'a' + 10; } else { // unknown character break; @@ -88,11 +89,13 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { // unknown character break; } - if (int_val < old_val) { - // If new value became less than previous, it's overflow + + // add next digi and check for overflow + if (mp_small_int_mul_overflow(int_val, base)) { goto overflow; - } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) { - // If signed number changed sign - it's overflow + } + int_val = int_val * base + dig; + if (!MP_SMALL_INT_FITS(int_val)) { goto overflow; } } diff --git a/py/runtime.c b/py/runtime.c index f487807256..a9d57460ac 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -413,7 +413,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { goto unsupported_op; } // TODO: We just should make mp_obj_new_int() inline and use that - if (MP_OBJ_FITS_SMALL_INT(lhs_val)) { + if (MP_SMALL_INT_FITS(lhs_val)) { return MP_OBJ_NEW_SMALL_INT(lhs_val); } else { return mp_obj_new_int(lhs_val); diff --git a/py/smallint.c b/py/smallint.c index 186c9c754f..5543f126c3 100644 --- a/py/smallint.c +++ b/py/smallint.c @@ -28,6 +28,7 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "smallint.h" bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) { // Check for multiply overflow; see CERT INT32-C diff --git a/py/smallint.h b/py/smallint.h index 9c1de42ad0..36b55f9197 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -26,6 +26,11 @@ // Functions for small integer arithmetic +// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range +#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1)) +#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN))) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) + bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y); machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor); machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom); diff --git a/qemu-arm/README.md b/qemu-arm/README.md new file mode 100644 index 0000000000..a1d389d164 --- /dev/null +++ b/qemu-arm/README.md @@ -0,0 +1,23 @@ +This is experimental, community-supported port for Cortex-M emulation as +provided my QEMU (http://qemu.org). + +The purposes of this port are to enable: + +1. Continuous integration + - run tests agains architecture-specific parts of code base +2. Experimentation + - simulation & prototyping of anything that has architecture-specific + code + - exploring instruction set in terms of optimising some part of + MicroPython or a module +3. Streamlined debugging + - no need for JTAG or even an MCU chip itself + - no need to use OpenOCD or anything else that might slow down the + process in terms of plugging things together, pressing buttons, etc. + +This port will only work with with [GCC ARM Embedded](launchpad.net/gcc-arm-embedded) +toolchain and not with CodeSourcery toolchain. You will need to modify +`LDFLAGS` if you want to use CodeSourcery's version of `arm-none-eabi`. +The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while +ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be +passed to the linker. diff --git a/tests/basics/int-big-and.py b/tests/basics/int-big-and.py index 75fbd52884..a48848dbf0 100644 --- a/tests/basics/int-big-and.py +++ b/tests/basics/int-big-and.py @@ -2,7 +2,23 @@ print(0 & (1 << 80)) print(0 & (1 << 80) == 0) print(bool(0 & (1 << 80))) -#a = 0xfffffffffffffffffffffffffffff -#print(a & (1 << 80)) -#print((a & (1 << 80)) >> 80) -#print((a & (1 << 80)) >> 80 == 1) +a = 0xfffffffffffffffffffffffffffff +print(a & (1 << 80)) +print((a & (1 << 80)) >> 80) +print((a & (1 << 80)) >> 80 == 1) + +# test negative on rhs +a = 123456789012345678901234567890 +print(a & -1) +print(a & -2) +print(a & -2345678901234567890123456789) +print(a & (-a)) + +# test negative on lhs +a = 123456789012345678901234567890 +print(-1 & a) +print(-2 & a) +print(-2345678901234567890123456789 & a) +print((-a) & a) +print((-a) & 0xffffffff) +print((-a) & 0xffffffffffffffffffffffffffffffff) |