xref: /freebsd/contrib/arm-optimized-routines/math/aarch64/sve/sincos.c (revision f3087bef11543b42e0d69b708f367097a4118d24)
1 /*
2  * Double-precision vector sincos function.
3  *
4  * Copyright (c) 2023-2024, Arm Limited.
5  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6  */
7 
8 /* Define _GNU_SOURCE in order to include sincos declaration. If building
9    pre-GLIBC 2.1, or on a non-GNU conforming system, this routine will need to
10    be linked against the scalar sincosf from math/.  */
11 #define _GNU_SOURCE
12 
13 #include "sv_math.h"
14 #include "sv_sincos_common.h"
15 #include "test_defs.h"
16 
17 #include <math.h>
18 
19 /* sincos not available for all scalar libm implementations.  */
20 #ifndef __GLIBC__
21 static void
sincos(double x,double * out_sin,double * out_cos)22 sincos (double x, double *out_sin, double *out_cos)
23 {
24   *out_sin = sin (x);
25   *out_cos = cos (x);
26 }
27 #endif
28 
29 static void NOINLINE
special_case(svfloat64_t x,svbool_t special,double * out_sin,double * out_cos)30 special_case (svfloat64_t x, svbool_t special, double *out_sin,
31 	      double *out_cos)
32 {
33   svbool_t p = svptrue_pat_b64 (SV_VL1);
34   for (int i = 0; i < svcntd (); i++)
35     {
36       if (svptest_any (special, p))
37 	sincos (svlastb (p, x), out_sin + i, out_cos + i);
38       p = svpnext_b64 (svptrue_b64 (), p);
39     }
40 }
41 
42 /* Double-precision vector function allowing calculation of both sin and cos in
43    one function call, using shared argument reduction and separate polynomials.
44    Largest observed error is for sin, 3.22 ULP:
45    sv_sincos_sin (0x1.d70eef40f39b1p+12) got -0x1.ffe9537d5dbb7p-3
46 					want -0x1.ffe9537d5dbb4p-3.  */
47 void
_ZGVsMxvl8l8_sincos(svfloat64_t x,double * out_sin,double * out_cos,svbool_t pg)48 _ZGVsMxvl8l8_sincos (svfloat64_t x, double *out_sin, double *out_cos,
49 		     svbool_t pg)
50 {
51   const struct sv_sincos_data *d = ptr_barrier (&sv_sincos_data);
52   svbool_t special = check_ge_rangeval (pg, x, d);
53 
54   svfloat64x2_t sc = sv_sincos_inline (pg, x, d);
55 
56   svst1 (pg, out_sin, svget2 (sc, 0));
57   svst1 (pg, out_cos, svget2 (sc, 1));
58 
59   if (unlikely (svptest_any (pg, special)))
60     special_case (x, special, out_sin, out_cos);
61 }
62 
63 TEST_DISABLE_FENV (_ZGVsMxv_sincos_sin)
64 TEST_DISABLE_FENV (_ZGVsMxv_sincos_cos)
65 TEST_ULP (_ZGVsMxv_sincos_sin, 2.73)
66 TEST_ULP (_ZGVsMxv_sincos_cos, 2.73)
67 #define SV_SINCOS_INTERVAL(lo, hi, n)                                         \
68   TEST_SYM_INTERVAL (_ZGVsMxv_sincos_sin, lo, hi, n)                          \
69   TEST_SYM_INTERVAL (_ZGVsMxv_sincos_cos, lo, hi, n)
70 SV_SINCOS_INTERVAL (0, 0x1p-63, 50000)
71 SV_SINCOS_INTERVAL (0x1p-63, 0x1p23, 500000)
72 SV_SINCOS_INTERVAL (0x1p23, inf, 10000)
73 CLOSE_SVE_ATTR
74