Commits

Alex Gaynor committed af99487

(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.

Comments (0)

Files changed (4)

pypy/module/pypyjit/test_pypy_c/test_math.py

             --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=)
+        """)

pypy/rpython/extfuncregistry.py

        ('sqrt', [float], float),
        ('log', [float], float),
        ('log10', [float], float),
+       ('sin', [float], float),
+       ('cos', [float], float),
     ]),
 ]
 for module, methods in _register:

pypy/rpython/lltypesystem/module/ll_math.py

                         [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):
         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
 
 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 = [

pypy/rpython/lltypesystem/module/test/test_llinterp_math.py

             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