[pypy-commit] pypy default: Fix the declaration of the lloperation 'cast_float_to_int' to

arigo noreply at buildbot.pypy.org
Mon Oct 24 14:43:43 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r48372:4241a19c0141
Date: 2011-10-24 14:35 +0200
http://bitbucket.org/pypy/pypy/changeset/4241a19c0141/

Log:	Fix the declaration of the lloperation 'cast_float_to_int' to no
	longer pretend it raises OverflowError, which is wrong.

	Fix the JIT by refusing to jtransform operationsl like
	'cast_float_to_uint' and 'cast_uint_to_float' and their longlong and
	ulonglong equivalents. These would each require their own custom
	messy code in the backends. (If really needed, they are probably
	better written as '_ll_1_cast_x_to_y' support functions.)

diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -847,6 +847,12 @@
             return self._float_to_float_cast(v_arg, v_result)
         elif not float_arg and float_res:
             # some int -> some float
+            size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype)
+            assert size1 <= rffi.sizeof(lltype.Signed), (
+                "not implemented: cast_longlong_to_float")
+            assert size1 < rffi.sizeof(lltype.Signed) or not unsigned1, (
+                "not implemented: cast_uint_to_float")
+            #
             ops = []
             v1 = varoftype(lltype.Signed)
             oplist = self.rewrite_operation(
@@ -871,6 +877,12 @@
             return ops
         elif float_arg and not float_res:
             # some float -> some int
+            size2, unsigned2 = rffi.size_and_sign(v_result.concretetype)
+            assert size2 <= rffi.sizeof(lltype.Signed), (
+                "not implemented: cast_float_to_longlong")
+            assert size2 < rffi.sizeof(lltype.Signed) or not unsigned2, (
+                "not implemented: cast_float_to_uint")
+            #
             ops = []
             v1 = varoftype(lltype.Float)
             op1 = self.rewrite_operation(
@@ -1097,8 +1109,8 @@
     # The new operation is optionally further processed by rewrite_operation().
     for _old, _new in [('bool_not', 'int_is_zero'),
                        ('cast_bool_to_float', 'cast_int_to_float'),
-                       ('cast_uint_to_float', 'cast_int_to_float'),
-                       ('cast_float_to_uint', 'cast_float_to_int'),
+                       ('cast_uint_to_float', 'cast_primitive'),
+                       ('cast_float_to_uint', 'cast_primitive'),
 
                        ('int_add_nonneg_ovf', 'int_add_ovf'),
                        ('keepalive', '-live-'),
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -630,6 +630,9 @@
         a = longlong.getrealfloat(a)
         # note: we need to call int() twice to care for the fact that
         # int(-2147483648.0) returns a long :-(
+        # we could also call intmask() instead of the outermost int(), but
+        # it's probably better to explicitly crash (by getting a long) if a
+        # non-translated version tries to cast a too large float to an int.
         return int(int(a))
 
     @arguments("i", returns="f")
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -404,8 +404,8 @@
     'FLOAT_TRUEDIV/2',
     'FLOAT_NEG/1',
     'FLOAT_ABS/1',
-    'CAST_FLOAT_TO_INT/1',
-    'CAST_INT_TO_FLOAT/1',
+    'CAST_FLOAT_TO_INT/1',          # don't use for unsigned ints; we would
+    'CAST_INT_TO_FLOAT/1',          # need some messy code in the backend
     'CAST_FLOAT_TO_SINGLEFLOAT/1',
     'CAST_SINGLEFLOAT_TO_FLOAT/1',
     #
diff --git a/pypy/jit/metainterp/test/test_float.py b/pypy/jit/metainterp/test/test_float.py
--- a/pypy/jit/metainterp/test/test_float.py
+++ b/pypy/jit/metainterp/test/test_float.py
@@ -1,5 +1,6 @@
-import math
+import math, sys
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from pypy.rlib.rarithmetic import intmask, r_uint
 
 
 class FloatTests:
@@ -45,6 +46,41 @@
         res = self.interp_operations(f, [-2.0])
         assert res == -8.5
 
+    def test_cast_float_to_int(self):
+        def g(f):
+            return int(f)
+        res = self.interp_operations(g, [-12345.9])
+        assert res == -12345
+
+    def test_cast_float_to_uint(self):
+        def g(f):
+            return intmask(r_uint(f))
+        raises(AssertionError, self.interp_operations, g, [0.0])   # for now
+        #res = self.interp_operations(g, [sys.maxint*2.0])
+        #assert res == intmask(long(sys.maxint*2.0))
+        #res = self.interp_operations(g, [-12345.9])
+        #assert res == -12345
+
+    def test_cast_int_to_float(self):
+        def g(i):
+            return float(i)
+        res = self.interp_operations(g, [-12345])
+        assert type(res) is float and res == -12345.0
+
+    def test_cast_uint_to_float(self):
+        def g(i):
+            return float(r_uint(i))
+        raises(AssertionError, self.interp_operations, g, [0])    # for now
+        #res = self.interp_operations(g, [sys.maxint*2])
+        #assert type(res) is float and res == float(sys.maxint*2)
+        #res = self.interp_operations(g, [-12345])
+        #assert type(res) is float and res == float(long(r_uint(-12345)))
+
+    #def test_cast_longlong_to_float(self):
+    #def test_cast_ulonglong_to_float(self):
+    #def test_cast_float_to_longlong(self):
+    #def test_cast_float_to_ulonglong(self):
+
 
 class TestOOtype(FloatTests, OOJitMixin):
     pass
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -1095,13 +1095,6 @@
             assert y >= 0
         return self.op_int_add_ovf(x, y)
 
-    def op_cast_float_to_int(self, f):
-        assert type(f) is float
-        try:
-            return ovfcheck(int(f))
-        except OverflowError:
-            self.make_llexception()
-
     def op_int_is_true(self, x):
         # special case
         if type(x) is CDefinedIntSymbolic:
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -343,8 +343,8 @@
     'cast_uint_to_float':   LLOp(canfold=True),
     'cast_longlong_to_float' :LLOp(canfold=True),
     'cast_ulonglong_to_float':LLOp(canfold=True),
-    'cast_float_to_int':    LLOp(canraise=(OverflowError,), tryfold=True),
-    'cast_float_to_uint':   LLOp(canfold=True),    # XXX need OverflowError?
+    'cast_float_to_int':    LLOp(canfold=True),
+    'cast_float_to_uint':   LLOp(canfold=True),
     'cast_float_to_longlong' :LLOp(canfold=True),
     'cast_float_to_ulonglong':LLOp(canfold=True),
     'truncate_longlong_to_int':LLOp(canfold=True),
diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -355,6 +355,10 @@
     assert type(b) is bool
     return float(b)
 
+def op_cast_float_to_int(f):
+    assert type(f) is float
+    return intmask(int(f))
+
 def op_cast_float_to_uint(f):
     assert type(f) is float
     return r_uint(long(f))


More information about the pypy-commit mailing list