[PATCH 4/4] AArch64: Add vector tanpi routines

Paul Zimmermann Paul.Zimmermann@inria.fr
Thu Jan 2 13:39:39 GMT 2025


       Hi Joe,

this patch fails to apply to master. There are extra cospi/sinpi entries
in sysdeps/unix/sysv/linux/aarch64/libmvec.abilist.

Paul

> From: Joe Ramsay <Joe.Ramsay@arm.com>
> CC: Joe Ramsay <Joe.Ramsay@arm.com>
> Date: Tue, 17 Dec 2024 10:35:26 +0000
> NoDisclaimer: true
> 
> Vector variant of the new C23 tanpi. New tests pass on AArch64.
> ---
> OK for master? If so please commit for me as I don't have commit rights.
> Thanks,
> Joe
>  bits/libm-simd-decl-stubs.h                   | 11 +++
>  math/bits/mathcalls.h                         |  2 +-
>  sysdeps/aarch64/fpu/Makefile                  |  3 +-
>  sysdeps/aarch64/fpu/Versions                  |  5 ++
>  sysdeps/aarch64/fpu/advsimd_f32_protos.h      |  1 +
>  sysdeps/aarch64/fpu/bits/math-vector.h        |  8 ++
>  sysdeps/aarch64/fpu/tanpi_advsimd.c           | 88 +++++++++++++++++++
>  sysdeps/aarch64/fpu/tanpi_sve.c               | 88 +++++++++++++++++++
>  sysdeps/aarch64/fpu/tanpif_advsimd.c          | 72 +++++++++++++++
>  sysdeps/aarch64/fpu/tanpif_sve.c              | 68 ++++++++++++++
>  .../fpu/test-double-advsimd-wrappers.c        |  1 +
>  .../aarch64/fpu/test-double-sve-wrappers.c    |  1 +
>  .../aarch64/fpu/test-float-advsimd-wrappers.c |  1 +
>  sysdeps/aarch64/fpu/test-float-sve-wrappers.c |  1 +
>  sysdeps/aarch64/libm-test-ulps                |  8 ++
>  .../unix/sysv/linux/aarch64/libmvec.abilist   |  5 ++
>  16 files changed, 361 insertions(+), 2 deletions(-)
>  create mode 100644 sysdeps/aarch64/fpu/tanpi_advsimd.c
>  create mode 100644 sysdeps/aarch64/fpu/tanpi_sve.c
>  create mode 100644 sysdeps/aarch64/fpu/tanpif_advsimd.c
>  create mode 100644 sysdeps/aarch64/fpu/tanpif_sve.c
> 
> diff --git a/bits/libm-simd-decl-stubs.h b/bits/libm-simd-decl-stubs.h
> index 7f2857a13d..c926ed9de1 100644
> --- a/bits/libm-simd-decl-stubs.h
> +++ b/bits/libm-simd-decl-stubs.h
> @@ -362,4 +362,15 @@
>  #define __DECL_SIMD_cospif32x
>  #define __DECL_SIMD_cospif64x
>  #define __DECL_SIMD_cospif128x
> +
> +#define __DECL_SIMD_tanpi
> +#define __DECL_SIMD_tanpif
> +#define __DECL_SIMD_tanpil
> +#define __DECL_SIMD_tanpif16
> +#define __DECL_SIMD_tanpif32
> +#define __DECL_SIMD_tanpif64
> +#define __DECL_SIMD_tanpif128
> +#define __DECL_SIMD_tanpif32x
> +#define __DECL_SIMD_tanpif64x
> +#define __DECL_SIMD_tanpif128x
>  #endif
> diff --git a/math/bits/mathcalls.h b/math/bits/mathcalls.h
> index 67f8d0b853..ccfa056814 100644
> --- a/math/bits/mathcalls.h
> +++ b/math/bits/mathcalls.h
> @@ -80,7 +80,7 @@ __MATHCALL_VEC (cospi,, (_Mdouble_ __x));
>  /* Sine of pi * X.  */
>  __MATHCALL_VEC (sinpi,, (_Mdouble_ __x));
>  /* Tangent of pi * X.  */
> -__MATHCALL (tanpi,, (_Mdouble_ __x));
> +__MATHCALL_VEC (tanpi,, (_Mdouble_ __x));
>  #endif
>  
>  /* Hyperbolic functions.  */
> diff --git a/sysdeps/aarch64/fpu/Makefile b/sysdeps/aarch64/fpu/Makefile
> index 6d1e55c4e6..aadedf1517 100644
> --- a/sysdeps/aarch64/fpu/Makefile
> +++ b/sysdeps/aarch64/fpu/Makefile
> @@ -25,7 +25,8 @@ libmvec-supported-funcs = acos \
>                            sinh \
>                            sinpi \
>                            tan \
> -                          tanh
> +                          tanh \
> +                          tanpi
>  
>  float-advsimd-funcs = $(libmvec-supported-funcs)
>  double-advsimd-funcs = $(libmvec-supported-funcs)
> diff --git a/sysdeps/aarch64/fpu/Versions b/sysdeps/aarch64/fpu/Versions
> index f8581cf881..0f9503f9d8 100644
> --- a/sysdeps/aarch64/fpu/Versions
> +++ b/sysdeps/aarch64/fpu/Versions
> @@ -151,5 +151,10 @@ libmvec {
>      _ZGVnN4v_sinpif;
>      _ZGVsMxv_sinpi;
>      _ZGVsMxv_sinpif;
> +    _ZGVnN2v_tanpi;
> +    _ZGVnN2v_tanpif;
> +    _ZGVnN4v_tanpif;
> +    _ZGVsMxv_tanpi;
> +    _ZGVsMxv_tanpif;
>    }
>  }
> diff --git a/sysdeps/aarch64/fpu/advsimd_f32_protos.h b/sysdeps/aarch64/fpu/advsimd_f32_protos.h
> index eca8dfd616..2471b148ad 100644
> --- a/sysdeps/aarch64/fpu/advsimd_f32_protos.h
> +++ b/sysdeps/aarch64/fpu/advsimd_f32_protos.h
> @@ -45,4 +45,5 @@ libmvec_hidden_proto (V_NAME_F1(sinh));
>  libmvec_hidden_proto (V_NAME_F1(sinpi));
>  libmvec_hidden_proto (V_NAME_F1(tan));
>  libmvec_hidden_proto (V_NAME_F1(tanh));
> +libmvec_hidden_proto (V_NAME_F1(tanpi));
>  libmvec_hidden_proto (V_NAME_F2(atan2));
> diff --git a/sysdeps/aarch64/fpu/bits/math-vector.h b/sysdeps/aarch64/fpu/bits/math-vector.h
> index 530ad246ea..b242cef7ef 100644
> --- a/sysdeps/aarch64/fpu/bits/math-vector.h
> +++ b/sysdeps/aarch64/fpu/bits/math-vector.h
> @@ -145,6 +145,10 @@
>  # define __DECL_SIMD_tanh __DECL_SIMD_aarch64
>  # undef __DECL_SIMD_tanhf
>  # define __DECL_SIMD_tanhf __DECL_SIMD_aarch64
> +# undef __DECL_SIMD_tanpi
> +# define __DECL_SIMD_tanpi __DECL_SIMD_aarch64
> +# undef __DECL_SIMD_tanpif
> +# define __DECL_SIMD_tanpif __DECL_SIMD_aarch64
>  #endif
>  
>  #if __GNUC_PREREQ(9, 0)
> @@ -200,6 +204,7 @@ __vpcs __f32x4_t _ZGVnN4v_sinhf (__f32x4_t);
>  __vpcs __f32x4_t _ZGVnN4v_sinpif (__f32x4_t);
>  __vpcs __f32x4_t _ZGVnN4v_tanf (__f32x4_t);
>  __vpcs __f32x4_t _ZGVnN4v_tanhf (__f32x4_t);
> +__vpcs __f32x4_t _ZGVnN4v_tanpif (__f32x4_t);
>  
>  __vpcs __f64x2_t _ZGVnN2vv_atan2 (__f64x2_t, __f64x2_t);
>  __vpcs __f64x2_t _ZGVnN2v_acos (__f64x2_t);
> @@ -230,6 +235,7 @@ __vpcs __f64x2_t _ZGVnN2v_sinh (__f64x2_t);
>  __vpcs __f64x2_t _ZGVnN2v_sinpi (__f64x2_t);
>  __vpcs __f64x2_t _ZGVnN2v_tan (__f64x2_t);
>  __vpcs __f64x2_t _ZGVnN2v_tanh (__f64x2_t);
> +__vpcs __f64x2_t _ZGVnN2v_tanpi (__f64x2_t);
>  
>  #  undef __ADVSIMD_VEC_MATH_SUPPORTED
>  #endif /* __ADVSIMD_VEC_MATH_SUPPORTED */
> @@ -265,6 +271,7 @@ __sv_f32_t _ZGVsMxv_sinhf (__sv_f32_t, __sv_bool_t);
>  __sv_f32_t _ZGVsMxv_sinpif (__sv_f32_t, __sv_bool_t);
>  __sv_f32_t _ZGVsMxv_tanf (__sv_f32_t, __sv_bool_t);
>  __sv_f32_t _ZGVsMxv_tanhf (__sv_f32_t, __sv_bool_t);
> +__sv_f32_t _ZGVsMxv_tanpif (__sv_f32_t, __sv_bool_t);
>  
>  __sv_f64_t _ZGVsMxvv_atan2 (__sv_f64_t, __sv_f64_t, __sv_bool_t);
>  __sv_f64_t _ZGVsMxv_acos (__sv_f64_t, __sv_bool_t);
> @@ -295,6 +302,7 @@ __sv_f64_t _ZGVsMxv_sinh (__sv_f64_t, __sv_bool_t);
>  __sv_f64_t _ZGVsMxv_sinpi (__sv_f64_t, __sv_bool_t);
>  __sv_f64_t _ZGVsMxv_tan (__sv_f64_t, __sv_bool_t);
>  __sv_f64_t _ZGVsMxv_tanh (__sv_f64_t, __sv_bool_t);
> +__sv_f64_t _ZGVsMxv_tanpi (__sv_f64_t, __sv_bool_t);
>  
>  #  undef __SVE_VEC_MATH_SUPPORTED
>  #endif /* __SVE_VEC_MATH_SUPPORTED */
> diff --git a/sysdeps/aarch64/fpu/tanpi_advsimd.c b/sysdeps/aarch64/fpu/tanpi_advsimd.c
> new file mode 100644
> index 0000000000..0a93beebca
> --- /dev/null
> +++ b/sysdeps/aarch64/fpu/tanpi_advsimd.c
> @@ -0,0 +1,88 @@
> +/* Double-precision (Advanced SIMD) tanpi function
> +
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include "v_math.h"
> +
> +const static struct v_tanpi_data
> +{
> +  float64x2_t c0, c2, c4, c6, c8, c10, c12;
> +  double c1, c3, c5, c7, c9, c11, c13, c14;
> +} tanpi_data = {
> +  /* Coefficents for tan(pi * x) computed with fpminimax
> +     on [ 0x1p-1022 0x1p-2 ]
> +     approx rel error: 0x1.7eap-55
> +     approx abs error: 0x1.7eap-55.  */
> +  .c0 = V2 (0x1.921fb54442d18p1), /* pi.  */
> +  .c1 = 0x1.4abbce625be52p3,	  .c2 = V2 (0x1.466bc6775b0f9p5),
> +  .c3 = 0x1.45fff9b426f5ep7,	  .c4 = V2 (0x1.45f4730dbca5cp9),
> +  .c5 = 0x1.45f3265994f85p11,	  .c6 = V2 (0x1.45f4234b330cap13),
> +  .c7 = 0x1.45dca11be79ebp15,	  .c8 = V2 (0x1.47283fc5eea69p17),
> +  .c9 = 0x1.3a6d958cdefaep19,	  .c10 = V2 (0x1.927896baee627p21),
> +  .c11 = -0x1.89333f6acd922p19,	  .c12 = V2 (0x1.5d4e912bb8456p27),
> +  .c13 = -0x1.a854d53ab6874p29,	  .c14 = 0x1.1b76de7681424p32,
> +};
> +
> +/* Approximation for double-precision vector tanpi(x)
> +   The maximum error is 3.06 ULP:
> +   _ZGVnN2v_tanpi(0x1.0a4a07dfcca3ep-1) got -0x1.fa30112702c98p+3
> +				       want -0x1.fa30112702c95p+3.  */
> +float64x2_t VPCS_ATTR V_NAME_D1 (tanpi) (float64x2_t x)
> +{
> +  const struct v_tanpi_data *d = ptr_barrier (&tanpi_data);
> +
> +  float64x2_t n = vrndnq_f64 (x);
> +
> +  /* inf produces nan that propagates.  */
> +  float64x2_t xr = vsubq_f64 (x, n);
> +  float64x2_t ar = vabdq_f64 (x, n);
> +  uint64x2_t flip = vcgtq_f64 (ar, v_f64 (0.25));
> +  float64x2_t r = vbslq_f64 (flip, vsubq_f64 (v_f64 (0.5), ar), ar);
> +
> +  /* Order-14 pairwise Horner.  */
> +  float64x2_t r2 = vmulq_f64 (r, r);
> +  float64x2_t r4 = vmulq_f64 (r2, r2);
> +
> +  float64x2_t c_1_3 = vld1q_f64 (&d->c1);
> +  float64x2_t c_5_7 = vld1q_f64 (&d->c5);
> +  float64x2_t c_9_11 = vld1q_f64 (&d->c9);
> +  float64x2_t c_13_14 = vld1q_f64 (&d->c13);
> +  float64x2_t p01 = vfmaq_laneq_f64 (d->c0, r2, c_1_3, 0);
> +  float64x2_t p23 = vfmaq_laneq_f64 (d->c2, r2, c_1_3, 1);
> +  float64x2_t p45 = vfmaq_laneq_f64 (d->c4, r2, c_5_7, 0);
> +  float64x2_t p67 = vfmaq_laneq_f64 (d->c6, r2, c_5_7, 1);
> +  float64x2_t p89 = vfmaq_laneq_f64 (d->c8, r2, c_9_11, 0);
> +  float64x2_t p1011 = vfmaq_laneq_f64 (d->c10, r2, c_9_11, 1);
> +  float64x2_t p1213 = vfmaq_laneq_f64 (d->c12, r2, c_13_14, 0);
> +
> +  float64x2_t p = vfmaq_laneq_f64 (p1213, r4, c_13_14, 1);
> +  p = vfmaq_f64 (p1011, r4, p);
> +  p = vfmaq_f64 (p89, r4, p);
> +  p = vfmaq_f64 (p67, r4, p);
> +  p = vfmaq_f64 (p45, r4, p);
> +  p = vfmaq_f64 (p23, r4, p);
> +  p = vfmaq_f64 (p01, r4, p);
> +  p = vmulq_f64 (r, p);
> +
> +  float64x2_t p_recip = vdivq_f64 (v_f64 (1.0), p);
> +  float64x2_t y = vbslq_f64 (flip, p_recip, p);
> +
> +  uint64x2_t sign
> +      = veorq_u64 (vreinterpretq_u64_f64 (xr), vreinterpretq_u64_f64 (ar));
> +  return vreinterpretq_f64_u64 (vorrq_u64 (vreinterpretq_u64_f64 (y), sign));
> +}
> diff --git a/sysdeps/aarch64/fpu/tanpi_sve.c b/sysdeps/aarch64/fpu/tanpi_sve.c
> new file mode 100644
> index 0000000000..57c643ae29
> --- /dev/null
> +++ b/sysdeps/aarch64/fpu/tanpi_sve.c
> @@ -0,0 +1,88 @@
> +/* Double-precision (SVE) tanpi function
> +
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include "sv_math.h"
> +
> +const static struct v_tanpi_data
> +{
> +  double c0, c2, c4, c6, c8, c10, c12;
> +  double c1, c3, c5, c7, c9, c11, c13, c14;
> +} tanpi_data = {
> +  /* Coefficents for tan(pi * x) computed with fpminimax
> +     on [ 0x1p-1022 0x1p-2 ]
> +     approx rel error: 0x1.7eap-55
> +     approx abs error: 0x1.7eap-55.  */
> +  .c0 = 0x1.921fb54442d18p1, /* pi.  */
> +  .c1 = 0x1.4abbce625be52p3,	.c2 = 0x1.466bc6775b0f9p5,
> +  .c3 = 0x1.45fff9b426f5ep7,	.c4 = 0x1.45f4730dbca5cp9,
> +  .c5 = 0x1.45f3265994f85p11,	.c6 = 0x1.45f4234b330cap13,
> +  .c7 = 0x1.45dca11be79ebp15,	.c8 = 0x1.47283fc5eea69p17,
> +  .c9 = 0x1.3a6d958cdefaep19,	.c10 = 0x1.927896baee627p21,
> +  .c11 = -0x1.89333f6acd922p19, .c12 = 0x1.5d4e912bb8456p27,
> +  .c13 = -0x1.a854d53ab6874p29, .c14 = 0x1.1b76de7681424p32,
> +};
> +
> +/* Approximation for double-precision vector tanpi(x)
> +   The maximum error is 3.06 ULP:
> +   _ZGVsMxv_tanpi(0x1.0a4a07dfcca3ep-1) got -0x1.fa30112702c98p+3
> +				       want -0x1.fa30112702c95p+3.  */
> +svfloat64_t SV_NAME_D1 (tanpi) (svfloat64_t x, const svbool_t pg)
> +{
> +  const struct v_tanpi_data *d = ptr_barrier (&tanpi_data);
> +
> +  svfloat64_t n = svrintn_x (pg, x);
> +
> +  /* inf produces nan that propagates.  */
> +  svfloat64_t xr = svsub_x (pg, x, n);
> +  svfloat64_t ar = svabd_x (pg, x, n);
> +  svbool_t flip = svcmpgt (pg, ar, 0.25);
> +  svfloat64_t r = svsel (flip, svsubr_x (pg, ar, 0.5), ar);
> +
> +  /* Order-14 pairwise Horner.  */
> +  svfloat64_t r2 = svmul_x (pg, r, r);
> +  svfloat64_t r4 = svmul_x (pg, r2, r2);
> +
> +  svfloat64_t c_1_3 = svld1rq (pg, &d->c1);
> +  svfloat64_t c_5_7 = svld1rq (pg, &d->c5);
> +  svfloat64_t c_9_11 = svld1rq (pg, &d->c9);
> +  svfloat64_t c_13_14 = svld1rq (pg, &d->c13);
> +  svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), r2, c_1_3, 0);
> +  svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), r2, c_1_3, 1);
> +  svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), r2, c_5_7, 0);
> +  svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), r2, c_5_7, 1);
> +  svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), r2, c_9_11, 0);
> +  svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), r2, c_9_11, 1);
> +  svfloat64_t p1213 = svmla_lane (sv_f64 (d->c12), r2, c_13_14, 0);
> +
> +  svfloat64_t p = svmla_lane (p1213, r4, c_13_14, 1);
> +  p = svmad_x (pg, p, r4, p1011);
> +  p = svmad_x (pg, p, r4, p89);
> +  p = svmad_x (pg, p, r4, p67);
> +  p = svmad_x (pg, p, r4, p45);
> +  p = svmad_x (pg, p, r4, p23);
> +  p = svmad_x (pg, p, r4, p01);
> +  p = svmul_x (pg, r, p);
> +
> +  svfloat64_t p_recip = svdivr_x (pg, p, 1.0);
> +  svfloat64_t y = svsel (flip, p_recip, p);
> +
> +  svuint64_t sign
> +      = sveor_x (pg, svreinterpret_u64 (xr), svreinterpret_u64 (ar));
> +  return svreinterpret_f64 (svorr_x (pg, svreinterpret_u64 (y), sign));
> +}
> diff --git a/sysdeps/aarch64/fpu/tanpif_advsimd.c b/sysdeps/aarch64/fpu/tanpif_advsimd.c
> new file mode 100644
> index 0000000000..248cb0f999
> --- /dev/null
> +++ b/sysdeps/aarch64/fpu/tanpif_advsimd.c
> @@ -0,0 +1,72 @@
> +/* Single-precision (Advanced SIMD) tanpi function
> +
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include "v_math.h"
> +
> +const static struct v_tanpif_data
> +{
> +  float32x4_t c0, c2, c4, c6;
> +  float c1, c3, c5, c7;
> +} tanpif_data = {
> +  /* Coefficents for tan(pi * x).  */
> +  .c0 = V4 (0x1.921fb4p1f),  .c1 = 0x1.4abbcep3f,      .c2 = V4 (0x1.466b8p5f),
> +  .c3 = 0x1.461c72p7f,	     .c4 = V4 (0x1.42e9d4p9f), .c5 = 0x1.69e2c4p11f,
> +  .c6 = V4 (0x1.e85558p11f), .c7 = 0x1.a52e08p16f,
> +};
> +
> +/* Approximation for single-precision vector tanpi(x)
> +   The maximum error is 3.34 ULP:
> +   _ZGVnN4v_tanpif(0x1.d6c09ap-2) got 0x1.f70aacp+2
> +				 want 0x1.f70aa6p+2.  */
> +float32x4_t VPCS_ATTR V_NAME_F1 (tanpi) (float32x4_t x)
> +{
> +  const struct v_tanpif_data *d = ptr_barrier (&tanpif_data);
> +
> +  float32x4_t n = vrndnq_f32 (x);
> +
> +  /* inf produces nan that propagates.  */
> +  float32x4_t xr = vsubq_f32 (x, n);
> +  float32x4_t ar = vabdq_f32 (x, n);
> +  uint32x4_t flip = vcgtq_f32 (ar, v_f32 (0.25f));
> +  float32x4_t r = vbslq_f32 (flip, vsubq_f32 (v_f32 (0.5f), ar), ar);
> +
> +  /* Order-7 pairwise Horner polynomial evaluation scheme.  */
> +  float32x4_t r2 = vmulq_f32 (r, r);
> +  float32x4_t r4 = vmulq_f32 (r2, r2);
> +
> +  float32x4_t odd_coeffs = vld1q_f32 (&d->c1);
> +  float32x4_t p01 = vfmaq_laneq_f32 (d->c0, r2, odd_coeffs, 0);
> +  float32x4_t p23 = vfmaq_laneq_f32 (d->c2, r2, odd_coeffs, 1);
> +  float32x4_t p45 = vfmaq_laneq_f32 (d->c4, r2, odd_coeffs, 2);
> +  float32x4_t p67 = vfmaq_laneq_f32 (d->c6, r2, odd_coeffs, 3);
> +  float32x4_t p = vfmaq_f32 (p45, r4, p67);
> +  p = vfmaq_f32 (p23, r4, p);
> +  p = vfmaq_f32 (p01, r4, p);
> +
> +  p = vmulq_f32 (r, p);
> +  float32x4_t p_recip = vdivq_f32 (v_f32 (1.0f), p);
> +  float32x4_t y = vbslq_f32 (flip, p_recip, p);
> +
> +  uint32x4_t sign
> +      = veorq_u32 (vreinterpretq_u32_f32 (xr), vreinterpretq_u32_f32 (ar));
> +  return vreinterpretq_f32_u32 (vorrq_u32 (vreinterpretq_u32_f32 (y), sign));
> +}
> +
> +libmvec_hidden_def (V_NAME_F1 (tanpi))
> +HALF_WIDTH_ALIAS_F1 (tanpi)
> diff --git a/sysdeps/aarch64/fpu/tanpif_sve.c b/sysdeps/aarch64/fpu/tanpif_sve.c
> new file mode 100644
> index 0000000000..0285f56f34
> --- /dev/null
> +++ b/sysdeps/aarch64/fpu/tanpif_sve.c
> @@ -0,0 +1,68 @@
> +/* Single-precision (SVE) tanpi function
> +
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include "sv_math.h"
> +
> +const static struct v_tanpif_data
> +{
> +  float c0, c2, c4, c6;
> +  float c1, c3, c5, c7;
> +} tanpif_data = {
> +  /* Coefficients for tan(pi * x).  */
> +  .c0 = 0x1.921fb4p1f,	.c1 = 0x1.4abbcep3f,  .c2 = 0x1.466b8p5f,
> +  .c3 = 0x1.461c72p7f,	.c4 = 0x1.42e9d4p9f,  .c5 = 0x1.69e2c4p11f,
> +  .c6 = 0x1.e85558p11f, .c7 = 0x1.a52e08p16f,
> +};
> +
> +/* Approximation for single-precision vector tanpif(x)
> +   The maximum error is 3.34 ULP:
> +   _ZGVsMxv_tanpif(0x1.d6c09ap-2) got 0x1.f70aacp+2
> +				 want 0x1.f70aa6p+2.  */
> +svfloat32_t SV_NAME_F1 (tanpi) (svfloat32_t x, const svbool_t pg)
> +{
> +  const struct v_tanpif_data *d = ptr_barrier (&tanpif_data);
> +  svfloat32_t odd_coeffs = svld1rq (pg, &d->c1);
> +  svfloat32_t n = svrintn_x (pg, x);
> +
> +  /* inf produces nan that propagates.  */
> +  svfloat32_t xr = svsub_x (pg, x, n);
> +  svfloat32_t ar = svabd_x (pg, x, n);
> +  svbool_t flip = svcmpgt (pg, ar, 0.25f);
> +  svfloat32_t r = svsel (flip, svsub_x (pg, sv_f32 (0.5f), ar), ar);
> +
> +  svfloat32_t r2 = svmul_x (pg, r, r);
> +  svfloat32_t r4 = svmul_x (pg, r2, r2);
> +
> +  /* Order-7 Pairwise Horner.  */
> +  svfloat32_t p01 = svmla_lane (sv_f32 (d->c0), r2, odd_coeffs, 0);
> +  svfloat32_t p23 = svmla_lane (sv_f32 (d->c2), r2, odd_coeffs, 1);
> +  svfloat32_t p45 = svmla_lane (sv_f32 (d->c4), r2, odd_coeffs, 2);
> +  svfloat32_t p67 = svmla_lane (sv_f32 (d->c6), r2, odd_coeffs, 3);
> +  svfloat32_t p = svmad_x (pg, p67, r4, p45);
> +  p = svmad_x (pg, p, r4, p23);
> +  p = svmad_x (pg, p, r4, p01);
> +  svfloat32_t poly = svmul_x (pg, r, p);
> +
> +  svfloat32_t poly_recip = svdiv_x (pg, sv_f32 (1.0), poly);
> +  svfloat32_t y = svsel (flip, poly_recip, poly);
> +
> +  svuint32_t sign
> +      = sveor_x (pg, svreinterpret_u32 (xr), svreinterpret_u32 (ar));
> +  return svreinterpret_f32 (svorr_x (pg, svreinterpret_u32 (y), sign));
> +}
> diff --git a/sysdeps/aarch64/fpu/test-double-advsimd-wrappers.c b/sysdeps/aarch64/fpu/test-double-advsimd-wrappers.c
> index f4babdda95..1855ee1aaf 100644
> --- a/sysdeps/aarch64/fpu/test-double-advsimd-wrappers.c
> +++ b/sysdeps/aarch64/fpu/test-double-advsimd-wrappers.c
> @@ -51,3 +51,4 @@ VPCS_VECTOR_WRAPPER (sinh_advsimd, _ZGVnN2v_sinh)
>  VPCS_VECTOR_WRAPPER (sinpi_advsimd, _ZGVnN2v_sinpi)
>  VPCS_VECTOR_WRAPPER (tan_advsimd, _ZGVnN2v_tan)
>  VPCS_VECTOR_WRAPPER (tanh_advsimd, _ZGVnN2v_tanh)
> +VPCS_VECTOR_WRAPPER (tanpi_advsimd, _ZGVnN2v_tanpi)
> diff --git a/sysdeps/aarch64/fpu/test-double-sve-wrappers.c b/sysdeps/aarch64/fpu/test-double-sve-wrappers.c
> index 4627ea91b1..db35819172 100644
> --- a/sysdeps/aarch64/fpu/test-double-sve-wrappers.c
> +++ b/sysdeps/aarch64/fpu/test-double-sve-wrappers.c
> @@ -70,3 +70,4 @@ SVE_VECTOR_WRAPPER (sinh_sve, _ZGVsMxv_sinh)
>  SVE_VECTOR_WRAPPER (sinpi_sve, _ZGVsMxv_sinpi)
>  SVE_VECTOR_WRAPPER (tan_sve, _ZGVsMxv_tan)
>  SVE_VECTOR_WRAPPER (tanh_sve, _ZGVsMxv_tanh)
> +SVE_VECTOR_WRAPPER (tanpi_sve, _ZGVsMxv_tanpi)
> diff --git a/sysdeps/aarch64/fpu/test-float-advsimd-wrappers.c b/sysdeps/aarch64/fpu/test-float-advsimd-wrappers.c
> index 882109d986..6811eefa0c 100644
> --- a/sysdeps/aarch64/fpu/test-float-advsimd-wrappers.c
> +++ b/sysdeps/aarch64/fpu/test-float-advsimd-wrappers.c
> @@ -51,3 +51,4 @@ VPCS_VECTOR_WRAPPER (sinhf_advsimd, _ZGVnN4v_sinhf)
>  VPCS_VECTOR_WRAPPER (sinpif_advsimd, _ZGVnN4v_sinpif)
>  VPCS_VECTOR_WRAPPER (tanf_advsimd, _ZGVnN4v_tanf)
>  VPCS_VECTOR_WRAPPER (tanhf_advsimd, _ZGVnN4v_tanhf)
> +VPCS_VECTOR_WRAPPER (tanpif_advsimd, _ZGVnN4v_tanpif)
> diff --git a/sysdeps/aarch64/fpu/test-float-sve-wrappers.c b/sysdeps/aarch64/fpu/test-float-sve-wrappers.c
> index 8b4e17e09a..ffe505334f 100644
> --- a/sysdeps/aarch64/fpu/test-float-sve-wrappers.c
> +++ b/sysdeps/aarch64/fpu/test-float-sve-wrappers.c
> @@ -70,3 +70,4 @@ SVE_VECTOR_WRAPPER (sinhf_sve, _ZGVsMxv_sinhf)
>  SVE_VECTOR_WRAPPER (sinpif_sve, _ZGVsMxv_sinpif)
>  SVE_VECTOR_WRAPPER (tanf_sve, _ZGVsMxv_tanf)
>  SVE_VECTOR_WRAPPER (tanhf_sve, _ZGVsMxv_tanhf)
> +SVE_VECTOR_WRAPPER (tanpif_sve, _ZGVsMxv_tanpif)
> diff --git a/sysdeps/aarch64/libm-test-ulps b/sysdeps/aarch64/libm-test-ulps
> index 4534c4de45..a71001249e 100644
> --- a/sysdeps/aarch64/libm-test-ulps
> +++ b/sysdeps/aarch64/libm-test-ulps
> @@ -1752,11 +1752,19 @@ double: 2
>  float: 2
>  ldouble: 2
>  
> +Function: "tanpi_advsimd":
> +double: 2
> +float: 1
> +
>  Function: "tanpi_downward":
>  double: 2
>  float: 3
>  ldouble: 4
>  
> +Function: "tanpi_sve":
> +double: 2
> +float: 1
> +
>  Function: "tanpi_towardzero":
>  double: 2
>  float: 3
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libmvec.abilist b/sysdeps/unix/sysv/linux/aarch64/libmvec.abilist
> index c081f5fb28..a56ce7f4e2 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libmvec.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libmvec.abilist
> @@ -134,12 +134,17 @@ GLIBC_2.41 _ZGVnN2v_logp1 F
>  GLIBC_2.41 _ZGVnN2v_logp1f F
>  GLIBC_2.41 _ZGVnN2v_sinpi F
>  GLIBC_2.41 _ZGVnN2v_sinpif F
> +GLIBC_2.41 _ZGVnN2v_tanpi F
> +GLIBC_2.41 _ZGVnN2v_tanpif F
>  GLIBC_2.41 _ZGVnN4v_cospif F
>  GLIBC_2.41 _ZGVnN4v_logp1f F
>  GLIBC_2.41 _ZGVnN4v_sinpif F
> +GLIBC_2.41 _ZGVnN4v_tanpif F
>  GLIBC_2.41 _ZGVsMxv_cospi F
>  GLIBC_2.41 _ZGVsMxv_cospif F
>  GLIBC_2.41 _ZGVsMxv_logp1 F
>  GLIBC_2.41 _ZGVsMxv_logp1f F
>  GLIBC_2.41 _ZGVsMxv_sinpi F
>  GLIBC_2.41 _ZGVsMxv_sinpif F
> +GLIBC_2.41 _ZGVsMxv_tanpi F
> +GLIBC_2.41 _ZGVsMxv_tanpif F
> -- 
> 2.27.0
> 
> 


More information about the Libc-alpha mailing list