[pypy-commit] pypy default: (zain, alex): specialize the error checking for math.{sin, cos} this way is much cleaner, plus the error checking is written in terms of the input, which means the JIT can often remove duplicate checks.

alex_gaynor noreply at buildbot.pypy.org
Mon Jul 25 03:10:26 CEST 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r45959:af99487db00f
Date: 2011-07-24 18:10 -0700
http://bitbucket.org/pypy/pypy/changeset/af99487db00f/

Log:	(zain, alex): specialize the error checking for math.{sin,cos} this
	way is much cleaner, plus the error checking is written in terms of
	the input, which means the JIT can often remove duplicate checks.

diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py
--- a/pypy/module/pypyjit/test_pypy_c/test_math.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_math.py
@@ -30,3 +30,34 @@
             --TICK--
             jump(..., descr=<Loop0>)
         """)
+
+    def test_sin_cos(self):
+        def main(n):
+            import math
+
+            i = 1
+            s = 0.0
+            while i < n:
+                s += math.sin(i) - math.cos(i)
+                i += 1
+            return s
+        log = self.run(main, [500])
+        assert round(log.result, 6) == round(main(500), 6)
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i2 = int_lt(i0, i1)
+            guard_true(i2, descr=...)
+            f1 = cast_int_to_float(i0)
+            i3 = float_eq(f1, inf)
+            i4 = float_eq(f1, -inf)
+            i5 = int_or(i3, i4)
+            i6 = int_is_true(i5)
+            guard_false(i6, descr=...)
+            f2 = call(ConstClass(sin), f1, descr=<FloatCallDescr>)
+            f3 = call(ConstClass(cos), f1, descr=<FloatCallDescr>)
+            f4 = float_sub(f2, f3)
+            f5 = float_add(f0, f4)
+            i7 = int_add(i0, f1)
+            --TICK--
+            jump(..., descr=)
+        """)
\ No newline at end of file
diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py
--- a/pypy/rpython/extfuncregistry.py
+++ b/pypy/rpython/extfuncregistry.py
@@ -42,6 +42,8 @@
        ('sqrt', [float], float),
        ('log', [float], float),
        ('log10', [float], float),
+       ('sin', [float], float),
+       ('cos', [float], float),
     ]),
 ]
 for module, methods in _register:
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
@@ -69,6 +69,8 @@
                         [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE)
 math_floor = llexternal('floor', [rffi.DOUBLE], rffi.DOUBLE, elidable_function=True)
 math_sqrt = llexternal('sqrt', [rffi.DOUBLE], rffi.DOUBLE)
+math_sin = llexternal('sin', [rffi.DOUBLE], rffi.DOUBLE)
+math_cos = llexternal('cos', [rffi.DOUBLE], rffi.DOUBLE)
 
 @jit.elidable
 def sqrt_nonneg(x):
@@ -340,6 +342,16 @@
         raise ValueError("math domain error")
     return math_log10(x)
 
+def ll_math_sin(x):
+    if isinf(x):
+        raise ValueError("math domain error")
+    return math_sin(x)
+
+def ll_math_cos(x):
+    if isinf(x):
+        raise ValueError("math domain error")
+    return math_cos(x)
+
 # ____________________________________________________________
 #
 # Default implementations
@@ -377,8 +389,8 @@
 
 unary_math_functions = [
     'acos', 'asin', 'atan',
-    'ceil', 'cos', 'cosh', 'exp', 'fabs',
-    'sin', 'sinh', 'tan', 'tanh',
+    'ceil', 'cosh', 'exp', 'fabs',
+    'sinh', 'tan', 'tanh',
     'acosh', 'asinh', 'atanh', 'log1p', 'expm1',
     ]
 unary_math_functions_can_overflow = [
diff --git a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py
--- a/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py
+++ b/pypy/rpython/lltypesystem/module/test/test_llinterp_math.py
@@ -37,7 +37,7 @@
             assert self.interpret(f, [0.3, 0.4]) == f(0.3, 0.4)
         return next_test
 
-    for name in ll_math.unary_math_functions + ['log', 'log10', 'sqrt']:
+    for name in ll_math.unary_math_functions + ['log', 'log10', 'sin', 'cos', 'sqrt']:
         func_name = 'test_%s' % (name,)
         next_test = new_unary_test(name)
         next_test.func_name = func_name


More information about the pypy-commit mailing list