| 14 | } |
| 15 | |
| 16 | std::string ExpNeonKernel::GetKernelBody(TContext*) const { |
| 17 | std::stringstream writer; |
| 18 | |
| 19 | writer << R"( |
| 20 | #include<arm_neon.h> |
| 21 | #include<math.h> |
| 22 | |
| 23 | typedef float32x4_t v4sf; // vector of 4 float |
| 24 | typedef uint32x4_t v4su; // vector of 4 uint32 |
| 25 | typedef int32x4_t v4si; // vector of 4 int32 |
| 26 | |
| 27 | #define c_exp_hi 88.3762626647949f |
| 28 | #define c_exp_lo -88.3762626647949f |
| 29 | |
| 30 | #define c_cephes_LOG2EF 1.44269504088896341 |
| 31 | #define c_cephes_exp_C1 0.693359375 |
| 32 | #define c_cephes_exp_C2 -2.12194440e-4 |
| 33 | |
| 34 | #define c_cephes_exp_p0 1.9875691500E-4 |
| 35 | #define c_cephes_exp_p1 1.3981999507E-3 |
| 36 | #define c_cephes_exp_p2 8.3334519073E-3 |
| 37 | #define c_cephes_exp_p3 4.1665795894E-2 |
| 38 | #define c_cephes_exp_p4 1.6666665459E-1 |
| 39 | #define c_cephes_exp_p5 5.0000001201E-1 |
| 40 | |
| 41 | /* exp() computed for 4 float at once */ |
| 42 | float32x4_t exp_ps_f32(float32x4_t x) { |
| 43 | v4sf tmp, fx; |
| 44 | |
| 45 | v4sf one = vdupq_n_f32(1); |
| 46 | x = vminq_f32(x, vdupq_n_f32(c_exp_hi)); |
| 47 | x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo)); |
| 48 | |
| 49 | /* express exp(x) as exp(g + n*log(2)) */ |
| 50 | fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF)); |
| 51 | |
| 52 | /* perform a floorf */ |
| 53 | tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx)); |
| 54 | |
| 55 | /* if greater, subtract 1 */ |
| 56 | v4su mask = vcgtq_f32(tmp, fx); |
| 57 | mask = vandq_u32(mask, vreinterpretq_u32_f32(one)); |
| 58 | |
| 59 | fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask)); |
| 60 | |
| 61 | tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1)); |
| 62 | v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2)); |
| 63 | x = vsubq_f32(x, tmp); |
| 64 | x = vsubq_f32(x, z); |
| 65 | |
| 66 | static const float cephes_exp_p[6] = {c_cephes_exp_p0, c_cephes_exp_p1, |
| 67 | c_cephes_exp_p2, c_cephes_exp_p3, |
| 68 | c_cephes_exp_p4, c_cephes_exp_p5}; |
| 69 | v4sf y = vld1q_dup_f32(cephes_exp_p + 0); |
| 70 | v4sf c1 = vld1q_dup_f32(cephes_exp_p + 1); |
| 71 | v4sf c2 = vld1q_dup_f32(cephes_exp_p + 2); |
| 72 | v4sf c3 = vld1q_dup_f32(cephes_exp_p + 3); |
| 73 | v4sf c4 = vld1q_dup_f32(cephes_exp_p + 4); |
nothing calls this directly
no outgoing calls
no test coverage detected