[pypy-svn] pypy jit-short_from_state: hg merge post-release-1.5

hakanardo commits-noreply at bitbucket.org
Mon Apr 25 19:43:52 CEST 2011


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-short_from_state
Changeset: r43607:4b434eb43229
Date: 2011-04-25 16:44 +0200
http://bitbucket.org/pypy/pypy/changeset/4b434eb43229/

Log:	hg merge post-release-1.5

diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py
--- a/pypy/translator/c/node.py
+++ b/pypy/translator/c/node.py
@@ -11,7 +11,7 @@
 from pypy.translator.c.support import c_char_array_constant, barebonearray
 from pypy.translator.c.primitive import PrimitiveType, name_signed
 from pypy.rlib import exports
-from pypy.rlib.rfloat import isinf, isnan
+from pypy.rlib.rfloat import isfinite
 from pypy.rlib.rstackovf import _StackOverflow
 from pypy.translator.c import extfunc
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -793,7 +793,7 @@
             node = db.getcontainernode(value._obj)
             expr = 'NULL /*%s*/' % node.name
             node.where_to_copy_me.append('&%s' % access_expr)
-        elif typeOf(value) == Float and (isinf(value) or isnan(value)):
+        elif typeOf(value) == Float and not isfinite(value):
             db.late_initializations.append(('%s' % access_expr, db.get(value)))
             expr = '0.0 /* patched later by %sinfinity */' % (
                 '-+'[value > 0])

diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -158,12 +158,12 @@
         return _formatd(x, code, precision, flags)
 
 def double_to_string(value, tp, precision, flags):
-    if isnan(value):
-        special = DIST_NAN
+    if isfinite(value):
+        special = DIST_FINITE
     elif isinf(value):
         special = DIST_INFINITY
-    else:
-        special = DIST_FINITE
+    else:  #isnan(value):
+        special = DIST_NAN
     result = formatd(value, tp, precision, flags)
     return result, special
 
@@ -344,7 +344,7 @@
     def asinh(x):
         "NOT_RPYTHON"
         absx = abs(x)
-        if isnan(x) or isinf(x):
+        if not isfinite(x):
             return x
         if absx < _2_to_m28:
             return x
@@ -405,3 +405,6 @@
         r = math.floor(absx)
     return copysign(r, x)
 
+def isfinite(x):
+    "NOT_RPYTHON"
+    return not isinf(x) and not isnan(x)

diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2223,6 +2223,45 @@
             return sa
         assert self.meta_interp(f, [10]) == f(10)
         
+    def test_bug688_multiple_immutable_fields(self):
+        myjitdriver = JitDriver(greens=[], reds=['counter','context'])
+
+        class Tag:
+            pass
+        class InnerContext():
+            _immutable_fields_ = ['variables','local_names']
+            def __init__(self, variables):
+                self.variables = variables
+                self.local_names = [0]
+
+            def store(self):
+                self.local_names[0] = 1
+
+            def retrieve(self):
+                variables = hint(self.variables, promote=True)
+                result = self.local_names[0]
+                if result == 0:
+                    return -1
+                else:
+                    return -1
+        def build():
+            context = InnerContext(Tag())
+
+            context.store()
+
+            counter = 0
+            while True:
+                myjitdriver.jit_merge_point(context=context, counter = counter)
+                context.retrieve()
+                context.retrieve()
+
+                counter += 1
+                if counter > 10:
+                    return 7
+        assert self.meta_interp(build, []) == 7
+        self.check_loops(getfield_gc_pure=0)
+        self.check_loops(getfield_gc_pure=2, everywhere=True)
+        
 class TestOOtype(BasicTests, OOJitMixin):
 
     def test_oohash(self):

diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py
--- a/pypy/rpython/extfuncregistry.py
+++ b/pypy/rpython/extfuncregistry.py
@@ -36,6 +36,9 @@
 register_external(rfloat.isnan, [float], bool,
                   export_name="ll_math.ll_math_isnan", sandboxsafe=True,
                   llimpl=ll_math.ll_math_isnan)
+register_external(rfloat.isfinite, [float], bool,
+                  export_name="ll_math.ll_math_isfinite", sandboxsafe=True,
+                  llimpl=ll_math.ll_math_isfinite)
 register_external(rfloat.copysign, [float, float], float,
                   export_name="ll_math.ll_math_copysign", sandboxsafe=True,
                   llimpl=ll_math.ll_math_copysign)

diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py
--- a/pypy/translator/c/test/test_genc.py
+++ b/pypy/translator/c/test/test_genc.py
@@ -273,7 +273,7 @@
     assert res == 1.5
 
 def test_nan_and_special_values():
-    from pypy.rlib.rfloat import isnan, isinf, copysign
+    from pypy.rlib.rfloat import isnan, isinf, isfinite, copysign
     inf = 1e300 * 1e300
     assert isinf(inf)
     nan = inf/inf
@@ -283,6 +283,7 @@
             (inf,   lambda x: isinf(x) and x > 0.0),
             (-inf,  lambda x: isinf(x) and x < 0.0),
             (nan,   isnan),
+            (42.0,  isfinite),
             (0.0,   lambda x: not x and copysign(1., x) == 1.),
             (-0.0,  lambda x: not x and copysign(1., x) == -1.),
             ]:

diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -1,7 +1,7 @@
 from pypy.rlib.rarithmetic import LONG_BIT, intmask, r_uint, r_ulonglong
 from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen
 from pypy.rlib.rarithmetic import most_neg_value_of_same_type
-from pypy.rlib.rfloat import isinf, isnan
+from pypy.rlib.rfloat import isfinite
 from pypy.rlib.debug import make_sure_not_resized, check_regular_int
 from pypy.rlib.objectmodel import we_are_translated, specialize
 from pypy.rlib import jit
@@ -173,9 +173,15 @@
     def fromfloat(dval):
         """ Create a new bigint object from a float """
         # This function is not marked as pure because it can raise
+        if isfinite(dval):
+            return rbigint._fromfloat_finite(dval)
+        else:
+            raise OverflowError
+
+    @staticmethod
+    @jit.purefunction
+    def _fromfloat_finite(dval):
         sign = 1
-        if isinf(dval) or isnan(dval):
-            raise OverflowError
         if dval < 0.0:
             sign = -1
             dval = -dval

diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -72,7 +72,8 @@
     def find_rewritable_bool(self, op, args):
         try:
             oldopnum = opboolinvers[op.getopnum()]
-            targs = [args[0], args[1], ConstInt(oldopnum)]
+            targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[0], args[1]],
+                                                              None))
             if self.try_boolinvers(op, targs):
                 return True
         except KeyError:
@@ -80,7 +81,8 @@
 
         try:
             oldopnum = opboolreflex[op.getopnum()] # FIXME: add INT_ADD, INT_MUL
-            targs = [args[1], args[0], ConstInt(oldopnum)]
+            targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[1], args[0]],
+                                                              None))            
             oldop = self.optimizer.pure_operations.get(targs, None)
             if oldop is not None and oldop.getdescr() is op.getdescr():
                 self.make_equal_to(op.result, self.getvalue(oldop.result))
@@ -90,7 +92,8 @@
 
         try:
             oldopnum = opboolinvers[opboolreflex[op.getopnum()]]
-            targs = [args[1], args[0], ConstInt(oldopnum)]
+            targs = self.optimizer.make_args_key(ResOperation(oldopnum, [args[1], args[0]],
+                                                              None))            
             if self.try_boolinvers(op, targs):
                 return True
         except KeyError:

diff --git a/pypy/jit/metainterp/optimizeutil.py b/pypy/jit/metainterp/optimizeutil.py
--- a/pypy/jit/metainterp/optimizeutil.py
+++ b/pypy/jit/metainterp/optimizeutil.py
@@ -99,7 +99,9 @@
     make_sure_not_resized(args)
     res = 0x345678
     for arg in args:
-        if isinstance(arg, history.Const):
+        if arg is None:
+            y = 17
+        elif isinstance(arg, history.Const):
             y = arg._get_hash_()
         else:
             y = compute_identity_hash(arg)

diff --git a/pypy/rpython/test/test_rfloat.py b/pypy/rpython/test/test_rfloat.py
--- a/pypy/rpython/test/test_rfloat.py
+++ b/pypy/rpython/test/test_rfloat.py
@@ -157,9 +157,9 @@
         self.interpret(fn, [1.0, 2.0, 3.0])
 
     def test_copysign(self):
-        import math
+        from pypy.rlib import rfloat
         def fn(x, y):
-            return math.copysign(x, y)
+            return rfloat.copysign(x, y)
         assert self.interpret(fn, [42, -1]) == -42
         assert self.interpret(fn, [42, -0.0]) == -42
         assert self.interpret(fn, [42, 0.0]) == 42
@@ -172,21 +172,42 @@
         assert self.interpret(fn, [0]) == 42.3
 
     def test_isnan(self):
-        import math
-        def fn(x):
-            inf = x * x
-            nan = inf / inf
-            return math.isnan(nan)
-        assert self.interpret(fn, [1e200])
+        from pypy.rlib import rfloat
+        def fn(x, y):
+            n1 = x * x
+            n2 = y * y * y
+            return rfloat.isnan(n1 / n2)
+        assert self.interpret(fn, [1e200, 1e200])   # nan
+        assert not self.interpret(fn, [1e200, 1.0])   # +inf
+        assert not self.interpret(fn, [1e200, -1.0])  # -inf
+        assert not self.interpret(fn, [42.5, 2.3])    # +finite
+        assert not self.interpret(fn, [42.5, -2.3])   # -finite
 
     def test_isinf(self):
-        import math
-        def fn(x):
-            inf = x * x
-            return math.isinf(inf)
-        assert self.interpret(fn, [1e200])
+        from pypy.rlib import rfloat
+        def fn(x, y):
+            n1 = x * x
+            n2 = y * y * y
+            return rfloat.isinf(n1 / n2)
+        assert self.interpret(fn, [1e200, 1.0])       # +inf
+        assert self.interpret(fn, [1e200, -1.0])      # -inf
+        assert not self.interpret(fn, [1e200, 1e200]) # nan
+        assert not self.interpret(fn, [42.5, 2.3])    # +finite
+        assert not self.interpret(fn, [42.5, -2.3])   # -finite
 
-        
+    def test_isfinite(self):
+        from pypy.rlib import rfloat
+        def fn(x, y):
+            n1 = x * x
+            n2 = y * y * y
+            return rfloat.isfinite(n1 / n2)
+        assert self.interpret(fn, [42.5, 2.3])        # +finite
+        assert self.interpret(fn, [42.5, -2.3])       # -finite
+        assert not self.interpret(fn, [1e200, 1.0])   # +inf
+        assert not self.interpret(fn, [1e200, -1.0])  # -inf
+        assert not self.interpret(fn, [1e200, 1e200]) # nan
+
+
 class TestLLtype(BaseTestRfloat, LLRtypeMixin):
 
     def test_hash(self):

diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -269,7 +269,7 @@
             self.optimizer.pure_operations[key] = op
 
     def has_pure_result(self, opnum, args, descr):
-        op = ResOperation(opnum, args, None)
+        op = ResOperation(opnum, args, None, descr)
         key = self.optimizer.make_args_key(op)
         op = self.optimizer.pure_operations.get(key, None)
         if op is None:
@@ -571,7 +571,7 @@
 
     def make_args_key(self, op):
         n = op.numargs()
-        args = [None] * (n + 1)
+        args = [None] * (n + 2)
         for i in range(n):
             arg = op.getarg(i)
             try:
@@ -582,6 +582,7 @@
                 arg = value.get_key_box()
             args[i] = arg
         args[n] = ConstInt(op.getopnum())
+        args[n+1] = op.getdescr()
         return args
 
     def optimize_default(self, op):

diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -219,6 +219,7 @@
     same before and after translation, except for RPython instances on the
     lltypesystem.
     """
+    assert x is not None
     result = object.__hash__(x)
     try:
         x.__dict__['__precomputed_identity_hash'] = result
@@ -267,14 +268,15 @@
     In RPython, floats cannot be used with ints in dicts, anyway.
     """
     from pypy.rlib.rarithmetic import intmask
-    from pypy.rlib.rfloat import isinf, isnan
-    if isinf(f):
-        if f < 0.0:
-            return -271828
-        else:
-            return 314159
-    elif isnan(f):
-        return 0
+    from pypy.rlib.rfloat import isfinite, isinf
+    if not isfinite(f):
+        if isinf(f):
+            if f < 0.0:
+                return -271828
+            else:
+                return 314159
+        else: #isnan(f):
+            return 0
     v, expo = math.frexp(f)
     v *= TAKE_NEXT
     hipart = int(v)

diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -10,7 +10,7 @@
 from pypy.objspace.std.longobject import W_LongObject
 from pypy.rlib.rarithmetic import ovfcheck_float_to_int, intmask, LONG_BIT
 from pypy.rlib.rfloat import (
-    isinf, isnan, INFINITY, NAN, copysign, formatd,
+    isinf, isnan, isfinite, INFINITY, NAN, copysign, formatd,
     DTSF_ADD_DOT_0, DTSF_STR_PRECISION)
 from pypy.rlib.rbigint import rbigint
 from pypy.rlib.objectmodel import we_are_translated
@@ -102,7 +102,7 @@
 
 def float_hex__Float(space, w_float):
     value = w_float.floatval
-    if isinf(value) or isnan(value):
+    if not isfinite(value):
         return str__Float(space, w_float)
     if value == 0.0:
         if copysign(1., value) == -1.:
@@ -136,15 +136,15 @@
 def float2string(space, w_float, code, precision):
     x = w_float.floatval
     # we special-case explicitly inf and nan here
-    if isinf(x):
+    if isfinite(x):
+        s = formatd(x, code, precision, DTSF_ADD_DOT_0)
+    elif isinf(x):
         if x > 0.0:
             s = "inf"
         else:
             s = "-inf"
-    elif isnan(x):
+    else:  # isnan(x):
         s = "nan"
-    else:
-        s = formatd(x, code, precision, DTSF_ADD_DOT_0)
     return space.wrap(s)
 
 def repr__Float(space, w_float):
@@ -179,7 +179,7 @@
     if opname == 'eq' or opname == 'ne':
         def do_compare_bigint(f1, b2):
             """f1 is a float.  b2 is a bigint."""
-            if isinf(f1) or isnan(f1) or math.floor(f1) != f1:
+            if not isfinite(f1) or math.floor(f1) != f1:
                 return opname == 'ne'
             b1 = rbigint.fromfloat(f1)
             res = b1.eq(b2)
@@ -189,7 +189,7 @@
     else:
         def do_compare_bigint(f1, b2):
             """f1 is a float.  b2 is a bigint."""
-            if isinf(f1) or isnan(f1):
+            if not isfinite(f1):
                 return op(f1, 0.0)
             if opname == 'gt' or opname == 'le':
                 # 'float > long'   <==>  'ceil(float) > long'
@@ -457,8 +457,6 @@
 
     if x == 0.0:
         if y < 0.0:
-            if isinf(y):
-                return space.wrap(INFINITY)
             raise OperationError(space.w_ZeroDivisionError,
                                  space.wrap("0.0 cannot be raised to "
                                             "a negative power"))

diff --git a/pypy/rpython/lltypesystem/module/test/test_ll_math.py b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
--- a/pypy/rpython/lltypesystem/module/test/test_ll_math.py
+++ b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
@@ -22,11 +22,60 @@
         assert ll_math.ll_math_isnan(nan)
         assert not ll_math.ll_math_isnan(inf)
 
+    def test_isfinite(self):
+        inf = 1e200 * 1e200
+        nan = inf / inf
+        assert ll_math.ll_math_isfinite(0.0)
+        assert ll_math.ll_math_isfinite(-42.0)
+        assert not ll_math.ll_math_isfinite(nan)
+        assert not ll_math.ll_math_isnan(inf)
+        assert not ll_math.ll_math_isnan(-inf)
+
+    def test_compiled_isnan(self):
+        def f(x, y):
+            n1 = normalize(x * x)
+            n2 = normalize(y * y * y)
+            return ll_math.ll_math_isnan(n1 / n2)
+        f = compile(f, [float, float], backendopt=False)
+        assert f(1e200, 1e200)     # nan
+        assert not f(1e200, 1.0)   # +inf
+        assert not f(1e200, -1.0)  # -inf
+        assert not f(42.5, 2.3)    # +finite
+        assert not f(42.5, -2.3)   # -finite
+
     def test_compiled_isinf(self):
-        def f(x):
-            return ll_math.ll_math_isinf(1. / x)
-        f = compile(f, [float], backendopt=False)
-        assert f(5.5e-309)
+        def f(x, y):
+            n1 = normalize(x * x)
+            n2 = normalize(y * y * y)
+            return ll_math.ll_math_isinf(n1 / n2)
+        f = compile(f, [float, float], backendopt=False)
+        assert f(1e200, 1.0)       # +inf
+        assert f(1e200, -1.0)      # -inf
+        assert not f(1e200, 1e200) # nan
+        assert not f(42.5, 2.3)    # +finite
+        assert not f(42.5, -2.3)   # -finite
+
+    def test_compiled_isfinite(self):
+        def f(x, y):
+            n1 = normalize(x * x)
+            n2 = normalize(y * y * y)
+            return ll_math.ll_math_isfinite(n1 / n2)
+        f = compile(f, [float, float], backendopt=False)
+        assert f(42.5, 2.3)        # +finite
+        assert f(42.5, -2.3)       # -finite
+        assert not f(1e200, 1.0)   # +inf
+        assert not f(1e200, -1.0)  # -inf
+        assert not f(1e200, 1e200) # nan
+
+
+from pypy.rpython.lltypesystem import lltype
+_A = lltype.GcArray(lltype.Float)
+def normalize(x):
+    # workaround: force the C compiler to cast to a double
+    a = lltype.malloc(_A, 1)
+    a[0] = x
+    import time; time.time()
+    return a[0]
 
 
 def make_test_case((fnname, args, expected), dict):

diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py
--- a/pypy/rpython/lltypesystem/module/ll_math.py
+++ b/pypy/rpython/lltypesystem/module/ll_math.py
@@ -8,7 +8,7 @@
 from pypy.tool.autopath import pypydir
 from pypy.rlib import jit, rposix
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rlib.rfloat import isinf, isnan, INFINITY, NAN
+from pypy.rlib.rfloat import isinf, isnan, isfinite, INFINITY, NAN
 
 if sys.platform == "win32":
     eci = ExternalCompilationInfo()
@@ -91,14 +91,20 @@
 # Custom implementations
 
 def ll_math_isnan(y):
-    # By not calling into the extenal function the JIT can inline this.  Floats
-    # are awesome.
+    # By not calling into the external function the JIT can inline this.
+    # Floats are awesome.
     return y != y
 
 def ll_math_isinf(y):
     # Use a bitwise OR so the JIT doesn't produce 2 different guards.
     return (y == INFINITY) | (y == -INFINITY)
 
+def ll_math_isfinite(y):
+    # Use a custom hack that is reasonably well-suited to the JIT.
+    # Floats are awesome (bis).
+    z = 0.0 * y
+    return z == z       # i.e.: z is not a NaN
+
 
 ll_math_floor = math_floor
 

diff --git a/pypy/rlib/rstruct/ieee.py b/pypy/rlib/rstruct/ieee.py
--- a/pypy/rlib/rstruct/ieee.py
+++ b/pypy/rlib/rstruct/ieee.py
@@ -87,12 +87,13 @@
         raise ValueError("invalid size value")
 
     sign = rfloat.copysign(1.0, x) < 0.0
-    if rfloat.isinf(x):
-        mant = r_ulonglong(0)
-        exp = MAX_EXP - MIN_EXP + 2
-    elif rfloat.isnan(x):
-        mant = r_ulonglong(1) << (MANT_DIG-2) # other values possible
-        exp = MAX_EXP - MIN_EXP + 2
+    if not rfloat.isfinite(x):
+        if rfloat.isinf(x):
+            mant = r_ulonglong(0)
+            exp = MAX_EXP - MIN_EXP + 2
+        else:  # rfloat.isnan(x):
+            mant = r_ulonglong(1) << (MANT_DIG-2) # other values possible
+            exp = MAX_EXP - MIN_EXP + 2
     elif x == 0.0:
         mant = r_ulonglong(0)
         exp = 0


More information about the Pypy-commit mailing list