This combines the following upstream commits: e45af510bc AArch64: Fix instability in AdvSIMD sinh 6c22823da5 AArch64: Fix instability in AdvSIMD tan aebaeb2c33 AArch64: Update math-vector-fortran.h e20ca759af AArch64: add optimised strspn/strcspn aac077645a AArch64: Fix SVE powf routine [BZ #33299] 1e3d1ddf97 AArch64: Optimize SVE exp functions dee22d2a81 AArch64: Optimise SVE FP64 Hyperbolics 6849c5b791 AArch64: Improve codegen SVE log1p helper 09795c5612 AArch64: Fix builderror with GCC 12.1/12.2 aa18367c11 AArch64: Improve enabling of SVE for libmvec 691edbdf77 aarch64: fix unwinding in longjmp 4352e2cc93 aarch64: Fix _dl_tlsdesc_dynamic unwind for pac-ret (BZ 32612) cf56eb28fa AArch64: Optimize algorithm in users of SVE expf helper ce2f26a22e AArch64: Remove PTR_ARG/SIZE_ARG defines 8f0e7fe61e Aarch64: Improve codegen in SVE asinh c0ff447edf Aarch64: Improve codegen in SVE exp and users, and update expf_inline f5ff34cb3c AArch64: Improve codegen for SVE erfcf 0b195651db AArch64: Improve codegen for SVE pow 95e807209b AArch64: Improve codegen for SVE powf d3f2b71ef1 aarch64: Fix tests not compatible with targets supporting GCS f86b4cf875 AArch64: Improve codegen in SVE expm1f and users 140b985e5a AArch64: Improve codegen in AdvSIMD asinh 91c1fadba3 AArch64: Improve codegen for SVE log1pf users cff9648d0b AArch64: Improve codegen of AdvSIMD expf family 569cfaaf49 AArch64: Improve codegen in AdvSIMD pow ca0c0d0f26 AArch64: Improve codegen in users of ADVSIMD log1p helper 13a7ef5999 AArch64: Improve codegen in users of ADVSIMD expm1 helper 2d82d781a5 AArch64: Remove SVE erf and erfc tables 1cf29fbc5b AArch64: Small optimisation in AdvSIMD erf and erfc 7b8c134b54 AArch64: Improve codegen in SVE expf & related routines a15b1394b5 AArch64: Improve codegen in SVE F32 logs 5bc100bd4b AArch64: Improve codegen in users of AdvSIMD log1pf helper 7900ac490d AArch64: Improve codegen in users of ADVSIMD expm1f helper 0fed0b250f aarch64/fpu: Add vector variants of pow 75207bde68 aarch64/fpu: Add vector variants of cbrt 157f89fa3d aarch64/fpu: Add vector variants of hypot 90a6ca8b28 aarch64: Fix AdvSIMD libmvec routines for big-endian 87cb1dfcd6 aarch64/fpu: Add vector variants of erfc 3d3a4fb8e4 aarch64/fpu: Add vector variants of tanh eedbbca0bf aarch64/fpu: Add vector variants of sinh 8b67920528 aarch64/fpu: Add vector variants of atanh 81406ea3c5 aarch64/fpu: Add vector variants of asinh b09fee1d21 aarch64/fpu: Add vector variants of acosh bdb5705b7b aarch64/fpu: Add vector variants of cosh cb5d84f1f8 aarch64/fpu: Add vector variants of erf Resolves: RHEL-118273
502 lines
19 KiB
Diff
502 lines
19 KiB
Diff
commit cff9648d0b50d19cdaf685f6767add040d4e1a8e
|
|
Author: Joana Cruz <Joana.Cruz@arm.com>
|
|
Date: Tue Dec 17 14:50:33 2024 +0000
|
|
|
|
AArch64: Improve codegen of AdvSIMD expf family
|
|
|
|
Load the polynomial evaluation coefficients into 2 vectors and use lanewise MLAs.
|
|
Also use intrinsics instead of native operations.
|
|
expf: 3% improvement in throughput microbenchmark on Neoverse V1, exp2f: 5%,
|
|
exp10f: 13%, coshf: 14%.
|
|
|
|
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
|
|
|
diff --git a/sysdeps/aarch64/fpu/coshf_advsimd.c b/sysdeps/aarch64/fpu/coshf_advsimd.c
|
|
index c1ab4923b826569b..cd5c86652129ea9c 100644
|
|
--- a/sysdeps/aarch64/fpu/coshf_advsimd.c
|
|
+++ b/sysdeps/aarch64/fpu/coshf_advsimd.c
|
|
@@ -23,19 +23,27 @@
|
|
static const struct data
|
|
{
|
|
struct v_expf_data expf_consts;
|
|
- uint32x4_t tiny_bound, special_bound;
|
|
+ uint32x4_t tiny_bound;
|
|
+ float32x4_t bound;
|
|
+#if WANT_SIMD_EXCEPT
|
|
+ uint32x4_t special_bound;
|
|
+#endif
|
|
} data = {
|
|
.expf_consts = V_EXPF_DATA,
|
|
.tiny_bound = V4 (0x20000000), /* 0x1p-63: Round to 1 below this. */
|
|
/* 0x1.5a92d8p+6: expf overflows above this, so have to use special case. */
|
|
+ .bound = V4 (0x1.5a92d8p+6),
|
|
+#if WANT_SIMD_EXCEPT
|
|
.special_bound = V4 (0x42ad496c),
|
|
+#endif
|
|
};
|
|
|
|
#if !WANT_SIMD_EXCEPT
|
|
static float32x4_t NOINLINE VPCS_ATTR
|
|
-special_case (float32x4_t x, float32x4_t y, uint32x4_t special)
|
|
+special_case (float32x4_t x, float32x4_t half_t, float32x4_t half_over_t,
|
|
+ uint32x4_t special)
|
|
{
|
|
- return v_call_f32 (coshf, x, y, special);
|
|
+ return v_call_f32 (coshf, x, vaddq_f32 (half_t, half_over_t), special);
|
|
}
|
|
#endif
|
|
|
|
@@ -47,14 +55,13 @@ float32x4_t VPCS_ATTR V_NAME_F1 (cosh) (float32x4_t x)
|
|
{
|
|
const struct data *d = ptr_barrier (&data);
|
|
|
|
- float32x4_t ax = vabsq_f32 (x);
|
|
- uint32x4_t iax = vreinterpretq_u32_f32 (ax);
|
|
- uint32x4_t special = vcgeq_u32 (iax, d->special_bound);
|
|
-
|
|
#if WANT_SIMD_EXCEPT
|
|
/* If fp exceptions are to be triggered correctly, fall back to the scalar
|
|
variant for all inputs if any input is a special value or above the bound
|
|
at which expf overflows. */
|
|
+ float32x4_t ax = vabsq_f32 (x);
|
|
+ uint32x4_t iax = vreinterpretq_u32_f32 (ax);
|
|
+ uint32x4_t special = vcgeq_u32 (iax, d->special_bound);
|
|
if (__glibc_unlikely (v_any_u32 (special)))
|
|
return v_call_f32 (coshf, x, x, v_u32 (-1));
|
|
|
|
@@ -63,10 +70,13 @@ float32x4_t VPCS_ATTR V_NAME_F1 (cosh) (float32x4_t x)
|
|
input to 0, which will generate no exceptions. */
|
|
if (__glibc_unlikely (v_any_u32 (tiny)))
|
|
ax = v_zerofy_f32 (ax, tiny);
|
|
+ float32x4_t t = v_expf_inline (ax, &d->expf_consts);
|
|
+#else
|
|
+ uint32x4_t special = vcageq_f32 (x, d->bound);
|
|
+ float32x4_t t = v_expf_inline (x, &d->expf_consts);
|
|
#endif
|
|
|
|
/* Calculate cosh by exp(x) / 2 + exp(-x) / 2. */
|
|
- float32x4_t t = v_expf_inline (ax, &d->expf_consts);
|
|
float32x4_t half_t = vmulq_n_f32 (t, 0.5);
|
|
float32x4_t half_over_t = vdivq_f32 (v_f32 (0.5), t);
|
|
|
|
@@ -75,7 +85,7 @@ float32x4_t VPCS_ATTR V_NAME_F1 (cosh) (float32x4_t x)
|
|
return vbslq_f32 (tiny, v_f32 (1), vaddq_f32 (half_t, half_over_t));
|
|
#else
|
|
if (__glibc_unlikely (v_any_u32 (special)))
|
|
- return special_case (x, vaddq_f32 (half_t, half_over_t), special);
|
|
+ return special_case (x, half_t, half_over_t, special);
|
|
#endif
|
|
|
|
return vaddq_f32 (half_t, half_over_t);
|
|
diff --git a/sysdeps/aarch64/fpu/exp10f_advsimd.c b/sysdeps/aarch64/fpu/exp10f_advsimd.c
|
|
index cf53e73290fcedb6..55d9cd83f2968ab9 100644
|
|
--- a/sysdeps/aarch64/fpu/exp10f_advsimd.c
|
|
+++ b/sysdeps/aarch64/fpu/exp10f_advsimd.c
|
|
@@ -18,16 +18,15 @@
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
#include "v_math.h"
|
|
-#include "poly_advsimd_f32.h"
|
|
|
|
#define ScaleBound 192.0f
|
|
|
|
static const struct data
|
|
{
|
|
- float32x4_t poly[5];
|
|
- float log10_2_and_inv[4];
|
|
- float32x4_t shift;
|
|
-
|
|
+ float32x4_t c0, c1, c3;
|
|
+ float log10_2_high, log10_2_low, c2, c4;
|
|
+ float32x4_t inv_log10_2, special_bound;
|
|
+ uint32x4_t exponent_bias, special_offset, special_bias;
|
|
#if !WANT_SIMD_EXCEPT
|
|
float32x4_t scale_thresh;
|
|
#endif
|
|
@@ -37,19 +36,24 @@ static const struct data
|
|
rel error: 0x1.89dafa3p-24
|
|
abs error: 0x1.167d55p-23 in [-log10(2)/2, log10(2)/2]
|
|
maxerr: 1.85943 +0.5 ulp. */
|
|
- .poly = { V4 (0x1.26bb16p+1f), V4 (0x1.5350d2p+1f), V4 (0x1.04744ap+1f),
|
|
- V4 (0x1.2d8176p+0f), V4 (0x1.12b41ap-1f) },
|
|
- .shift = V4 (0x1.8p23f),
|
|
-
|
|
- /* Stores constants 1/log10(2), log10(2)_high, log10(2)_low, 0. */
|
|
- .log10_2_and_inv = { 0x1.a934fp+1, 0x1.344136p-2, -0x1.ec10cp-27, 0 },
|
|
+ .c0 = V4 (0x1.26bb16p+1f),
|
|
+ .c1 = V4 (0x1.5350d2p+1f),
|
|
+ .c2 = 0x1.04744ap+1f,
|
|
+ .c3 = V4 (0x1.2d8176p+0f),
|
|
+ .c4 = 0x1.12b41ap-1f,
|
|
+ .inv_log10_2 = V4 (0x1.a934fp+1),
|
|
+ .log10_2_high = 0x1.344136p-2,
|
|
+ .log10_2_low = 0x1.ec10cp-27,
|
|
+ /* rint (log2 (2^127 / (1 + sqrt (2)))). */
|
|
+ .special_bound = V4 (126.0f),
|
|
+ .exponent_bias = V4 (0x3f800000),
|
|
+ .special_offset = V4 (0x82000000),
|
|
+ .special_bias = V4 (0x7f000000),
|
|
#if !WANT_SIMD_EXCEPT
|
|
.scale_thresh = V4 (ScaleBound)
|
|
#endif
|
|
};
|
|
|
|
-#define ExponentBias v_u32 (0x3f800000)
|
|
-
|
|
#if WANT_SIMD_EXCEPT
|
|
|
|
# define SpecialBound 38.0f /* rint(log10(2^127)). */
|
|
@@ -67,17 +71,15 @@ special_case (float32x4_t x, float32x4_t y, uint32x4_t cmp)
|
|
|
|
#else
|
|
|
|
-# define SpecialBound 126.0f /* rint (log2 (2^127 / (1 + sqrt (2)))). */
|
|
-# define SpecialOffset v_u32 (0x82000000)
|
|
-# define SpecialBias v_u32 (0x7f000000)
|
|
+# define SpecialBound 126.0f
|
|
|
|
static float32x4_t VPCS_ATTR NOINLINE
|
|
special_case (float32x4_t poly, float32x4_t n, uint32x4_t e, uint32x4_t cmp1,
|
|
float32x4_t scale, const struct data *d)
|
|
{
|
|
/* 2^n may overflow, break it up into s1*s2. */
|
|
- uint32x4_t b = vandq_u32 (vclezq_f32 (n), SpecialOffset);
|
|
- float32x4_t s1 = vreinterpretq_f32_u32 (vaddq_u32 (b, SpecialBias));
|
|
+ uint32x4_t b = vandq_u32 (vclezq_f32 (n), d->special_offset);
|
|
+ float32x4_t s1 = vreinterpretq_f32_u32 (vaddq_u32 (b, d->special_bias));
|
|
float32x4_t s2 = vreinterpretq_f32_u32 (vsubq_u32 (e, b));
|
|
uint32x4_t cmp2 = vcagtq_f32 (n, d->scale_thresh);
|
|
float32x4_t r2 = vmulq_f32 (s1, s1);
|
|
@@ -112,23 +114,23 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (exp10) (float32x4_t x)
|
|
/* exp10(x) = 2^n * 10^r = 2^n * (1 + poly (r)),
|
|
with poly(r) in [1/sqrt(2), sqrt(2)] and
|
|
x = r + n * log10 (2), with r in [-log10(2)/2, log10(2)/2]. */
|
|
- float32x4_t log10_2_and_inv = vld1q_f32 (d->log10_2_and_inv);
|
|
- float32x4_t z = vfmaq_laneq_f32 (d->shift, x, log10_2_and_inv, 0);
|
|
- float32x4_t n = vsubq_f32 (z, d->shift);
|
|
- float32x4_t r = vfmsq_laneq_f32 (x, n, log10_2_and_inv, 1);
|
|
- r = vfmsq_laneq_f32 (r, n, log10_2_and_inv, 2);
|
|
- uint32x4_t e = vshlq_n_u32 (vreinterpretq_u32_f32 (z), 23);
|
|
+ float32x4_t log10_2_c24 = vld1q_f32 (&d->log10_2_high);
|
|
+ float32x4_t n = vrndaq_f32 (vmulq_f32 (x, d->inv_log10_2));
|
|
+ float32x4_t r = vfmsq_laneq_f32 (x, n, log10_2_c24, 0);
|
|
+ r = vfmaq_laneq_f32 (r, n, log10_2_c24, 1);
|
|
+ uint32x4_t e = vshlq_n_u32 (vreinterpretq_u32_s32 (vcvtaq_s32_f32 (n)), 23);
|
|
|
|
- float32x4_t scale = vreinterpretq_f32_u32 (vaddq_u32 (e, ExponentBias));
|
|
+ float32x4_t scale = vreinterpretq_f32_u32 (vaddq_u32 (e, d->exponent_bias));
|
|
|
|
#if !WANT_SIMD_EXCEPT
|
|
- uint32x4_t cmp = vcagtq_f32 (n, v_f32 (SpecialBound));
|
|
+ uint32x4_t cmp = vcagtq_f32 (n, d->special_bound);
|
|
#endif
|
|
|
|
float32x4_t r2 = vmulq_f32 (r, r);
|
|
- float32x4_t poly
|
|
- = vfmaq_f32 (vmulq_f32 (r, d->poly[0]),
|
|
- v_pairwise_poly_3_f32 (r, r2, d->poly + 1), r2);
|
|
+ float32x4_t p12 = vfmaq_laneq_f32 (d->c1, r, log10_2_c24, 2);
|
|
+ float32x4_t p34 = vfmaq_laneq_f32 (d->c3, r, log10_2_c24, 3);
|
|
+ float32x4_t p14 = vfmaq_f32 (p12, r2, p34);
|
|
+ float32x4_t poly = vfmaq_f32 (vmulq_f32 (r, d->c0), p14, r2);
|
|
|
|
if (__glibc_unlikely (v_any_u32 (cmp)))
|
|
#if WANT_SIMD_EXCEPT
|
|
diff --git a/sysdeps/aarch64/fpu/exp2f_advsimd.c b/sysdeps/aarch64/fpu/exp2f_advsimd.c
|
|
index 69e0b193a1a91249..a4220da63c624490 100644
|
|
--- a/sysdeps/aarch64/fpu/exp2f_advsimd.c
|
|
+++ b/sysdeps/aarch64/fpu/exp2f_advsimd.c
|
|
@@ -21,24 +21,28 @@
|
|
|
|
static const struct data
|
|
{
|
|
- float32x4_t poly[5];
|
|
- uint32x4_t exponent_bias;
|
|
+ float32x4_t c1, c3;
|
|
+ uint32x4_t exponent_bias, special_offset, special_bias;
|
|
#if !WANT_SIMD_EXCEPT
|
|
- float32x4_t special_bound, scale_thresh;
|
|
+ float32x4_t scale_thresh, special_bound;
|
|
#endif
|
|
+ float c0, c2, c4, zero;
|
|
} data = {
|
|
/* maxerr: 1.962 ulp. */
|
|
- .poly = { V4 (0x1.59977ap-10f), V4 (0x1.3ce9e4p-7f), V4 (0x1.c6bd32p-5f),
|
|
- V4 (0x1.ebf9bcp-3f), V4 (0x1.62e422p-1f) },
|
|
+ .c0 = 0x1.59977ap-10f,
|
|
+ .c1 = V4 (0x1.3ce9e4p-7f),
|
|
+ .c2 = 0x1.c6bd32p-5f,
|
|
+ .c3 = V4 (0x1.ebf9bcp-3f),
|
|
+ .c4 = 0x1.62e422p-1f,
|
|
.exponent_bias = V4 (0x3f800000),
|
|
+ .special_offset = V4 (0x82000000),
|
|
+ .special_bias = V4 (0x7f000000),
|
|
#if !WANT_SIMD_EXCEPT
|
|
.special_bound = V4 (126.0f),
|
|
.scale_thresh = V4 (192.0f),
|
|
#endif
|
|
};
|
|
|
|
-#define C(i) d->poly[i]
|
|
-
|
|
#if WANT_SIMD_EXCEPT
|
|
|
|
# define TinyBound v_u32 (0x20000000) /* asuint (0x1p-63). */
|
|
@@ -55,16 +59,13 @@ special_case (float32x4_t x, float32x4_t y, uint32x4_t cmp)
|
|
|
|
#else
|
|
|
|
-# define SpecialOffset v_u32 (0x82000000)
|
|
-# define SpecialBias v_u32 (0x7f000000)
|
|
-
|
|
static float32x4_t VPCS_ATTR NOINLINE
|
|
special_case (float32x4_t poly, float32x4_t n, uint32x4_t e, uint32x4_t cmp1,
|
|
float32x4_t scale, const struct data *d)
|
|
{
|
|
/* 2^n may overflow, break it up into s1*s2. */
|
|
- uint32x4_t b = vandq_u32 (vclezq_f32 (n), SpecialOffset);
|
|
- float32x4_t s1 = vreinterpretq_f32_u32 (vaddq_u32 (b, SpecialBias));
|
|
+ uint32x4_t b = vandq_u32 (vclezq_f32 (n), d->special_offset);
|
|
+ float32x4_t s1 = vreinterpretq_f32_u32 (vaddq_u32 (b, d->special_bias));
|
|
float32x4_t s2 = vreinterpretq_f32_u32 (vsubq_u32 (e, b));
|
|
uint32x4_t cmp2 = vcagtq_f32 (n, d->scale_thresh);
|
|
float32x4_t r2 = vmulq_f32 (s1, s1);
|
|
@@ -80,13 +81,11 @@ special_case (float32x4_t poly, float32x4_t n, uint32x4_t e, uint32x4_t cmp1,
|
|
float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (exp2) (float32x4_t x)
|
|
{
|
|
const struct data *d = ptr_barrier (&data);
|
|
- float32x4_t n, r, r2, scale, p, q, poly;
|
|
- uint32x4_t cmp, e;
|
|
|
|
#if WANT_SIMD_EXCEPT
|
|
/* asuint(|x|) - TinyBound >= BigBound - TinyBound. */
|
|
uint32x4_t ia = vreinterpretq_u32_f32 (vabsq_f32 (x));
|
|
- cmp = vcgeq_u32 (vsubq_u32 (ia, TinyBound), SpecialBound);
|
|
+ uint32x4_t cmp = vcgeq_u32 (vsubq_u32 (ia, TinyBound), SpecialBound);
|
|
float32x4_t xm = x;
|
|
/* If any lanes are special, mask them with 1 and retain a copy of x to allow
|
|
special_case to fix special lanes later. This is only necessary if fenv
|
|
@@ -95,23 +94,24 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (exp2) (float32x4_t x)
|
|
x = vbslq_f32 (cmp, v_f32 (1), x);
|
|
#endif
|
|
|
|
- /* exp2(x) = 2^n (1 + poly(r)), with 1 + poly(r) in [1/sqrt(2),sqrt(2)]
|
|
- x = n + r, with r in [-1/2, 1/2]. */
|
|
- n = vrndaq_f32 (x);
|
|
- r = vsubq_f32 (x, n);
|
|
- e = vshlq_n_u32 (vreinterpretq_u32_s32 (vcvtaq_s32_f32 (x)), 23);
|
|
- scale = vreinterpretq_f32_u32 (vaddq_u32 (e, d->exponent_bias));
|
|
+ /* exp2(x) = 2^n (1 + poly(r)), with 1 + poly(r) in [1/sqrt(2),sqrt(2)]
|
|
+ x = n + r, with r in [-1/2, 1/2]. */
|
|
+ float32x4_t n = vrndaq_f32 (x);
|
|
+ float32x4_t r = vsubq_f32 (x, n);
|
|
+ uint32x4_t e = vshlq_n_u32 (vreinterpretq_u32_s32 (vcvtaq_s32_f32 (x)), 23);
|
|
+ float32x4_t scale = vreinterpretq_f32_u32 (vaddq_u32 (e, d->exponent_bias));
|
|
|
|
#if !WANT_SIMD_EXCEPT
|
|
- cmp = vcagtq_f32 (n, d->special_bound);
|
|
+ uint32x4_t cmp = vcagtq_f32 (n, d->special_bound);
|
|
#endif
|
|
|
|
- r2 = vmulq_f32 (r, r);
|
|
- p = vfmaq_f32 (C (1), C (0), r);
|
|
- q = vfmaq_f32 (C (3), C (2), r);
|
|
+ float32x4_t c024 = vld1q_f32 (&d->c0);
|
|
+ float32x4_t r2 = vmulq_f32 (r, r);
|
|
+ float32x4_t p = vfmaq_laneq_f32 (d->c1, r, c024, 0);
|
|
+ float32x4_t q = vfmaq_laneq_f32 (d->c3, r, c024, 1);
|
|
q = vfmaq_f32 (q, p, r2);
|
|
- p = vmulq_f32 (C (4), r);
|
|
- poly = vfmaq_f32 (p, q, r2);
|
|
+ p = vmulq_laneq_f32 (r, c024, 2);
|
|
+ float32x4_t poly = vfmaq_f32 (p, q, r2);
|
|
|
|
if (__glibc_unlikely (v_any_u32 (cmp)))
|
|
#if WANT_SIMD_EXCEPT
|
|
diff --git a/sysdeps/aarch64/fpu/expf_advsimd.c b/sysdeps/aarch64/fpu/expf_advsimd.c
|
|
index 5c9cb726205ece6e..70f137e2e5b46207 100644
|
|
--- a/sysdeps/aarch64/fpu/expf_advsimd.c
|
|
+++ b/sysdeps/aarch64/fpu/expf_advsimd.c
|
|
@@ -21,20 +21,25 @@
|
|
|
|
static const struct data
|
|
{
|
|
- float32x4_t poly[5];
|
|
- float32x4_t inv_ln2, ln2_hi, ln2_lo;
|
|
- uint32x4_t exponent_bias;
|
|
+ float32x4_t c1, c3, c4, inv_ln2;
|
|
+ float ln2_hi, ln2_lo, c0, c2;
|
|
+ uint32x4_t exponent_bias, special_offset, special_bias;
|
|
#if !WANT_SIMD_EXCEPT
|
|
float32x4_t special_bound, scale_thresh;
|
|
#endif
|
|
} data = {
|
|
/* maxerr: 1.45358 +0.5 ulp. */
|
|
- .poly = { V4 (0x1.0e4020p-7f), V4 (0x1.573e2ep-5f), V4 (0x1.555e66p-3f),
|
|
- V4 (0x1.fffdb6p-2f), V4 (0x1.ffffecp-1f) },
|
|
+ .c0 = 0x1.0e4020p-7f,
|
|
+ .c1 = V4 (0x1.573e2ep-5f),
|
|
+ .c2 = 0x1.555e66p-3f,
|
|
+ .c3 = V4 (0x1.fffdb6p-2f),
|
|
+ .c4 = V4 (0x1.ffffecp-1f),
|
|
.inv_ln2 = V4 (0x1.715476p+0f),
|
|
- .ln2_hi = V4 (0x1.62e4p-1f),
|
|
- .ln2_lo = V4 (0x1.7f7d1cp-20f),
|
|
+ .ln2_hi = 0x1.62e4p-1f,
|
|
+ .ln2_lo = 0x1.7f7d1cp-20f,
|
|
.exponent_bias = V4 (0x3f800000),
|
|
+ .special_offset = V4 (0x82000000),
|
|
+ .special_bias = V4 (0x7f000000),
|
|
#if !WANT_SIMD_EXCEPT
|
|
.special_bound = V4 (126.0f),
|
|
.scale_thresh = V4 (192.0f),
|
|
@@ -59,19 +64,17 @@ special_case (float32x4_t x, float32x4_t y, uint32x4_t cmp)
|
|
|
|
#else
|
|
|
|
-# define SpecialOffset v_u32 (0x82000000)
|
|
-# define SpecialBias v_u32 (0x7f000000)
|
|
-
|
|
static float32x4_t VPCS_ATTR NOINLINE
|
|
special_case (float32x4_t poly, float32x4_t n, uint32x4_t e, uint32x4_t cmp1,
|
|
float32x4_t scale, const struct data *d)
|
|
{
|
|
/* 2^n may overflow, break it up into s1*s2. */
|
|
- uint32x4_t b = vandq_u32 (vclezq_f32 (n), SpecialOffset);
|
|
- float32x4_t s1 = vreinterpretq_f32_u32 (vaddq_u32 (b, SpecialBias));
|
|
+ uint32x4_t b = vandq_u32 (vclezq_f32 (n), d->special_offset);
|
|
+ float32x4_t s1 = vreinterpretq_f32_u32 (vaddq_u32 (b, d->special_bias));
|
|
float32x4_t s2 = vreinterpretq_f32_u32 (vsubq_u32 (e, b));
|
|
uint32x4_t cmp2 = vcagtq_f32 (n, d->scale_thresh);
|
|
float32x4_t r2 = vmulq_f32 (s1, s1);
|
|
+ // (s2 + p*s2)*s1 = s2(p+1)s1
|
|
float32x4_t r1 = vmulq_f32 (vfmaq_f32 (s2, poly, s2), s1);
|
|
/* Similar to r1 but avoids double rounding in the subnormal range. */
|
|
float32x4_t r0 = vfmaq_f32 (scale, poly, scale);
|
|
@@ -84,12 +87,11 @@ special_case (float32x4_t poly, float32x4_t n, uint32x4_t e, uint32x4_t cmp1,
|
|
float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (exp) (float32x4_t x)
|
|
{
|
|
const struct data *d = ptr_barrier (&data);
|
|
- float32x4_t n, r, r2, scale, p, q, poly;
|
|
- uint32x4_t cmp, e;
|
|
+ float32x4_t ln2_c02 = vld1q_f32 (&d->ln2_hi);
|
|
|
|
#if WANT_SIMD_EXCEPT
|
|
/* asuint(x) - TinyBound >= BigBound - TinyBound. */
|
|
- cmp = vcgeq_u32 (
|
|
+ uint32x4_t cmp = vcgeq_u32 (
|
|
vsubq_u32 (vandq_u32 (vreinterpretq_u32_f32 (x), v_u32 (0x7fffffff)),
|
|
TinyBound),
|
|
SpecialBound);
|
|
@@ -103,22 +105,22 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (exp) (float32x4_t x)
|
|
|
|
/* exp(x) = 2^n (1 + poly(r)), with 1 + poly(r) in [1/sqrt(2),sqrt(2)]
|
|
x = ln2*n + r, with r in [-ln2/2, ln2/2]. */
|
|
- n = vrndaq_f32 (vmulq_f32 (x, d->inv_ln2));
|
|
- r = vfmsq_f32 (x, n, d->ln2_hi);
|
|
- r = vfmsq_f32 (r, n, d->ln2_lo);
|
|
- e = vshlq_n_u32 (vreinterpretq_u32_s32 (vcvtq_s32_f32 (n)), 23);
|
|
- scale = vreinterpretq_f32_u32 (vaddq_u32 (e, d->exponent_bias));
|
|
+ float32x4_t n = vrndaq_f32 (vmulq_f32 (x, d->inv_ln2));
|
|
+ float32x4_t r = vfmsq_laneq_f32 (x, n, ln2_c02, 0);
|
|
+ r = vfmsq_laneq_f32 (r, n, ln2_c02, 1);
|
|
+ uint32x4_t e = vshlq_n_u32 (vreinterpretq_u32_s32 (vcvtq_s32_f32 (n)), 23);
|
|
+ float32x4_t scale = vreinterpretq_f32_u32 (vaddq_u32 (e, d->exponent_bias));
|
|
|
|
#if !WANT_SIMD_EXCEPT
|
|
- cmp = vcagtq_f32 (n, d->special_bound);
|
|
+ uint32x4_t cmp = vcagtq_f32 (n, d->special_bound);
|
|
#endif
|
|
|
|
- r2 = vmulq_f32 (r, r);
|
|
- p = vfmaq_f32 (C (1), C (0), r);
|
|
- q = vfmaq_f32 (C (3), C (2), r);
|
|
+ float32x4_t r2 = vmulq_f32 (r, r);
|
|
+ float32x4_t p = vfmaq_laneq_f32 (d->c1, r, ln2_c02, 2);
|
|
+ float32x4_t q = vfmaq_laneq_f32 (d->c3, r, ln2_c02, 3);
|
|
q = vfmaq_f32 (q, p, r2);
|
|
- p = vmulq_f32 (C (4), r);
|
|
- poly = vfmaq_f32 (p, q, r2);
|
|
+ p = vmulq_f32 (d->c4, r);
|
|
+ float32x4_t poly = vfmaq_f32 (p, q, r2);
|
|
|
|
if (__glibc_unlikely (v_any_u32 (cmp)))
|
|
#if WANT_SIMD_EXCEPT
|
|
diff --git a/sysdeps/aarch64/fpu/v_expf_inline.h b/sysdeps/aarch64/fpu/v_expf_inline.h
|
|
index 08b06e0a6b34b4f4..eacd2af24161fe3a 100644
|
|
--- a/sysdeps/aarch64/fpu/v_expf_inline.h
|
|
+++ b/sysdeps/aarch64/fpu/v_expf_inline.h
|
|
@@ -24,50 +24,45 @@
|
|
|
|
struct v_expf_data
|
|
{
|
|
- float32x4_t poly[5];
|
|
- float32x4_t shift;
|
|
- float invln2_and_ln2[4];
|
|
+ float ln2_hi, ln2_lo, c0, c2;
|
|
+ float32x4_t inv_ln2, c1, c3, c4;
|
|
+ /* asuint(1.0f). */
|
|
+ uint32x4_t exponent_bias;
|
|
};
|
|
|
|
/* maxerr: 1.45358 +0.5 ulp. */
|
|
#define V_EXPF_DATA \
|
|
{ \
|
|
- .poly = { V4 (0x1.0e4020p-7f), V4 (0x1.573e2ep-5f), V4 (0x1.555e66p-3f), \
|
|
- V4 (0x1.fffdb6p-2f), V4 (0x1.ffffecp-1f) }, \
|
|
- .shift = V4 (0x1.8p23f), \
|
|
- .invln2_and_ln2 = { 0x1.715476p+0f, 0x1.62e4p-1f, 0x1.7f7d1cp-20f, 0 }, \
|
|
+ .c0 = 0x1.0e4020p-7f, .c1 = V4 (0x1.573e2ep-5f), .c2 = 0x1.555e66p-3f, \
|
|
+ .c3 = V4 (0x1.fffdb6p-2f), .c4 = V4 (0x1.ffffecp-1f), \
|
|
+ .ln2_hi = 0x1.62e4p-1f, .ln2_lo = 0x1.7f7d1cp-20f, \
|
|
+ .inv_ln2 = V4 (0x1.715476p+0f), .exponent_bias = V4 (0x3f800000), \
|
|
}
|
|
|
|
-#define ExponentBias v_u32 (0x3f800000) /* asuint(1.0f). */
|
|
-#define C(i) d->poly[i]
|
|
-
|
|
static inline float32x4_t
|
|
v_expf_inline (float32x4_t x, const struct v_expf_data *d)
|
|
{
|
|
- /* Helper routine for calculating exp(x).
|
|
+ /* Helper routine for calculating exp(ax).
|
|
Copied from v_expf.c, with all special-case handling removed - the
|
|
calling routine should handle special values if required. */
|
|
|
|
- /* exp(x) = 2^n (1 + poly(r)), with 1 + poly(r) in [1/sqrt(2),sqrt(2)]
|
|
- x = ln2*n + r, with r in [-ln2/2, ln2/2]. */
|
|
- float32x4_t n, r, z;
|
|
- float32x4_t invln2_and_ln2 = vld1q_f32 (d->invln2_and_ln2);
|
|
- z = vfmaq_laneq_f32 (d->shift, x, invln2_and_ln2, 0);
|
|
- n = vsubq_f32 (z, d->shift);
|
|
- r = vfmsq_laneq_f32 (x, n, invln2_and_ln2, 1);
|
|
- r = vfmsq_laneq_f32 (r, n, invln2_and_ln2, 2);
|
|
- uint32x4_t e = vshlq_n_u32 (vreinterpretq_u32_f32 (z), 23);
|
|
- float32x4_t scale = vreinterpretq_f32_u32 (vaddq_u32 (e, ExponentBias));
|
|
+ /* exp(ax) = 2^n (1 + poly(r)), with 1 + poly(r) in [1/sqrt(2),sqrt(2)]
|
|
+ ax = ln2*n + r, with r in [-ln2/2, ln2/2]. */
|
|
+ float32x4_t ax = vabsq_f32 (x);
|
|
+ float32x4_t ln2_c02 = vld1q_f32 (&d->ln2_hi);
|
|
+ float32x4_t n = vrndaq_f32 (vmulq_f32 (ax, d->inv_ln2));
|
|
+ float32x4_t r = vfmsq_laneq_f32 (ax, n, ln2_c02, 0);
|
|
+ r = vfmsq_laneq_f32 (r, n, ln2_c02, 1);
|
|
+ uint32x4_t e = vshlq_n_u32 (vreinterpretq_u32_s32 (vcvtq_s32_f32 (n)), 23);
|
|
+ float32x4_t scale = vreinterpretq_f32_u32 (vaddq_u32 (e, d->exponent_bias));
|
|
|
|
/* Custom order-4 Estrin avoids building high order monomial. */
|
|
float32x4_t r2 = vmulq_f32 (r, r);
|
|
- float32x4_t p, q, poly;
|
|
- p = vfmaq_f32 (C (1), C (0), r);
|
|
- q = vfmaq_f32 (C (3), C (2), r);
|
|
+ float32x4_t p = vfmaq_laneq_f32 (d->c1, r, ln2_c02, 2);
|
|
+ float32x4_t q = vfmaq_laneq_f32 (d->c3, r, ln2_c02, 3);
|
|
q = vfmaq_f32 (q, p, r2);
|
|
- p = vmulq_f32 (C (4), r);
|
|
- poly = vfmaq_f32 (p, q, r2);
|
|
+ p = vmulq_f32 (d->c4, r);
|
|
+ float32x4_t poly = vfmaq_f32 (p, q, r2);
|
|
return vfmaq_f32 (scale, poly, scale);
|
|
}
|
|
-
|
|
#endif
|