[pypy-commit] pypy default: Provide rarithmetic.ovfcheck_int32_add/sub/mul, with a reasonable

arigo pypy.commits at gmail.com
Mon Nov 28 12:24:29 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r88709:2b67d420c658
Date: 2016-11-28 18:23 +0100
http://bitbucket.org/pypy/pypy/changeset/2b67d420c658/

Log:	Provide rarithmetic.ovfcheck_int32_add/sub/mul, with a reasonable
	implementation (not special-cased by the JIT, but should generate
	only two extra instructions)

diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -25,6 +25,10 @@
          lltype.Unsigned, widen it to lltype.Signed.
          Useful because the translator doesn't support
          arithmetic on the smaller types.
+ovfcheck_int32_add/sub/mul(x, y)
+         perform an add/sub/mul between two regular integers,
+         but assumes that they fit inside signed 32-bit ints
+         and raises OverflowError if the result no longer does
 
 These are meant to be erased by translation, r_uint
 in the process should mark unsigned values, ovfcheck should
@@ -796,6 +800,47 @@
         return longlong2float(rffi.cast(rffi.LONGLONG, res))
     return rffi.cast(T, res)
 
+if sys.maxint == 2147483647:
+    def ovfcheck_int32_add(x, y):
+        return ovfcheck(x + y)
+    def ovfcheck_int32_sub(x, y):
+        return ovfcheck(x - y)
+    def ovfcheck_int32_mul(x, y):
+        return ovfcheck(x * y)
+else:
+    def ovfcheck_int32_add(x, y):
+        """x and y are assumed to fit inside the 32-bit rffi.INT;
+        raises OverflowError if the result doesn't fit rffi.INT"""
+        from rpython.rtyper.lltypesystem import lltype, rffi
+        x = rffi.cast(lltype.Signed, x)
+        y = rffi.cast(lltype.Signed, y)
+        z = x + y
+        if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)):
+            raise OverflowError
+        return z
+
+    def ovfcheck_int32_sub(x, y):
+        """x and y are assumed to fit inside the 32-bit rffi.INT;
+        raises OverflowError if the result doesn't fit rffi.INT"""
+        from rpython.rtyper.lltypesystem import lltype, rffi
+        x = rffi.cast(lltype.Signed, x)
+        y = rffi.cast(lltype.Signed, y)
+        z = x - y
+        if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)):
+            raise OverflowError
+        return z
+
+    def ovfcheck_int32_mul(x, y):
+        """x and y are assumed to fit inside the 32-bit rffi.INT;
+        raises OverflowError if the result doesn't fit rffi.INT"""
+        from rpython.rtyper.lltypesystem import lltype, rffi
+        x = rffi.cast(lltype.Signed, x)
+        y = rffi.cast(lltype.Signed, y)
+        z = x * y
+        if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)):
+            raise OverflowError
+        return z
+
 
 # String parsing support
 # ---------------------------
diff --git a/rpython/rlib/test/test_rarithmetic.py b/rpython/rlib/test/test_rarithmetic.py
--- a/rpython/rlib/test/test_rarithmetic.py
+++ b/rpython/rlib/test/test_rarithmetic.py
@@ -675,3 +675,11 @@
     assert a ^ r_uint32(42) == "a^42"
     assert r_uint32(42) ** a == "42**a"
     assert a ** r_uint32(42) == "a**42"
+
+def test_ovfcheck_int32():
+    assert ovfcheck_int32_add(-2**30, -2**30) == -2**31
+    py.test.raises(OverflowError, ovfcheck_int32_add, 2**30, 2**30)
+    assert ovfcheck_int32_sub(-2**30, 2**30) == -2**31
+    py.test.raises(OverflowError, ovfcheck_int32_sub, 2**30, -2**30)
+    assert ovfcheck_int32_mul(-2**16, 2**15) == -2**31
+    py.test.raises(OverflowError, ovfcheck_int32_mul, -2**16, -2**15)


More information about the pypy-commit mailing list