diff options
-rw-r--r-- | py/compile.c | 5 | ||||
-rw-r--r-- | py/runtime.c | 5 | ||||
-rw-r--r-- | tests/basics/int_small.py | 14 |
3 files changed, 24 insertions, 0 deletions
diff --git a/py/compile.c b/py/compile.c index 61b827859d..3633503958 100644 --- a/py/compile.c +++ b/py/compile.c @@ -233,6 +233,11 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m } } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) { // int >> int + if (arg1 >= BITS_PER_WORD) { + // Shifting to big amounts is underfined behavior + // in C and is CPU-dependent; propagate sign bit. + arg1 = BITS_PER_WORD - 1; + } pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1); } else { // shouldn't happen diff --git a/py/runtime.c b/py/runtime.c index f6f34be940..e225ba8b05 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -337,6 +337,11 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); } else { // standard precision is enough for right-shift + if (rhs_val >= BITS_PER_WORD) { + // Shifting to big amounts is underfined behavior + // in C and is CPU-dependent; propagate sign bit. + rhs_val = BITS_PER_WORD - 1; + } lhs_val >>= rhs_val; } break; diff --git a/tests/basics/int_small.py b/tests/basics/int_small.py index 102dac8ae7..1b2c983e23 100644 --- a/tests/basics/int_small.py +++ b/tests/basics/int_small.py @@ -48,3 +48,17 @@ a -= 1 print(a) # This would overflow #a -= 1 + + +# Shifts to big amounts are undefined behavior in C and is CPU-specific + +# These are compile-time constexprs +print(1 >> 32) +print(1 >> 64) +print(1 >> 128) + +# These are runtime calcs +a = 1 +print(a >> 32) +print(a >> 64) +print(a >> 128) |