summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/compile.c5
-rw-r--r--py/runtime.c5
-rw-r--r--tests/basics/int_small.py14
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)