Buckets:
agent-collaborations/hutter-prize-67 / decoder-bundle-minimization /work /paq8px-src /src /Mixer_Neon.cpp
| | |
| static constexpr int SIMD_WIDTH_NEON = 16 / sizeof(short); // 8 shorts per 128-bit lane | |
| // NEON helpers emulating the x86 intrinsics used in the algorithm | |
| static inline int32x4_t neon_mulhi_epi16(int32x4_t a, int32x4_t b) { | |
| int32x4_t rl = vmull_s16(vget_low_s16(vreinterpretq_s16_s32(a)), vget_low_s16(vreinterpretq_s16_s32(b))); | |
| int32x4_t rh = vmull_s16(vget_high_s16(vreinterpretq_s16_s32(a)), vget_high_s16(vreinterpretq_s16_s32(b))); | |
| uint16x8x2_t r = vuzpq_u16(vreinterpretq_u16_s32(rl), vreinterpretq_u16_s32(rh)); | |
| return vreinterpretq_s32_u16(r.val[1]); | |
| } | |
| static inline int32x4_t neon_madd_epi16(int32x4_t a, int32x4_t b) { | |
| int32x4_t pl = vmull_s16(vget_low_s16(vreinterpretq_s16_s32(a)), vget_low_s16(vreinterpretq_s16_s32(b))); | |
| int32x4_t ph = vmull_s16(vget_high_s16(vreinterpretq_s16_s32(a)), vget_high_s16(vreinterpretq_s16_s32(b))); | |
| int32x2_t rl = vpadd_s32(vget_low_s32(pl), vget_high_s32(pl)); | |
| int32x2_t rh = vpadd_s32(vget_low_s32(ph), vget_high_s32(ph)); | |
| return vcombine_s32(rl, rh); | |
| } | |
| Mixer_Neon::Mixer_Neon(const Shared* const sh, const int n, const int m, const int s, const int promoted) | |
| : Mixer(sh, n, m, s, SIMD_WIDTH_NEON) { | |
| if (s > 1) { | |
| mp = new Mixer_Neon(shared, s + promoted, 1, 1, 0); | |
| } | |
| } | |
| int Mixer_Neon::dotProduct(const short* const w, const size_t n) { | |
| int32x4_t sum = vdupq_n_s32(0); | |
| for (size_t i = 0; i < n; i += 8) { | |
| int32x4_t tmp = neon_madd_epi16(*(int32x4_t*)&tx[i], *(int32x4_t*)&w[i]); | |
| tmp = vshrq_n_s32(tmp, 8); | |
| sum = vaddq_s32(sum, tmp); | |
| } | |
| sum = vaddq_s32(sum, vreinterpretq_s32_s8(vextq_s8(vreinterpretq_s8_s32(sum), vdupq_n_s8(0), 8))); | |
| sum = vaddq_s32(sum, vreinterpretq_s32_s8(vextq_s8(vreinterpretq_s8_s32(sum), vdupq_n_s8(0), 4))); | |
| return vgetq_lane_s32(sum, 0); | |
| } | |
| int Mixer_Neon::dotProduct2(const short* const w0, const short* const w1, const size_t n, int& sum1) { | |
| int32x4_t s0 = vdupq_n_s32(0); | |
| int32x4_t s1 = vdupq_n_s32(0); | |
| for (size_t i = 0; i < n; i += 8) { | |
| const int32x4_t t = *(int32x4_t*)&tx[i]; | |
| int32x4_t tmp0 = neon_madd_epi16(t, *(int32x4_t*)&w0[i]); | |
| int32x4_t tmp1 = neon_madd_epi16(t, *(int32x4_t*)&w1[i]); | |
| s0 = vaddq_s32(s0, vshrq_n_s32(tmp0, 8)); | |
| s1 = vaddq_s32(s1, vshrq_n_s32(tmp1, 8)); | |
| } | |
| s0 = vaddq_s32(s0, vreinterpretq_s32_s8(vextq_s8(vreinterpretq_s8_s32(s0), vdupq_n_s8(0), 8))); | |
| s0 = vaddq_s32(s0, vreinterpretq_s32_s8(vextq_s8(vreinterpretq_s8_s32(s0), vdupq_n_s8(0), 4))); | |
| s1 = vaddq_s32(s1, vreinterpretq_s32_s8(vextq_s8(vreinterpretq_s8_s32(s1), vdupq_n_s8(0), 8))); | |
| s1 = vaddq_s32(s1, vreinterpretq_s32_s8(vextq_s8(vreinterpretq_s8_s32(s1), vdupq_n_s8(0), 4))); | |
| sum1 = vgetq_lane_s32(s1, 0); | |
| return vgetq_lane_s32(s0, 0); | |
| } | |
| void Mixer_Neon::train(short* const w, const size_t n, const int e) { | |
| const int32x4_t one = vreinterpretq_s32_s16(vdupq_n_s16(1)); | |
| const int32x4_t err = vreinterpretq_s32_s16(vdupq_n_s16(short(e))); | |
| for (size_t i = 0; i < n; i += 8) { | |
| int32x4_t tmp = vreinterpretq_s32_s16(vqaddq_s16(vreinterpretq_s16_s32(*(int32x4_t*)&tx[i]), vreinterpretq_s16_s32(*(int32x4_t*)&tx[i]))); | |
| tmp = neon_mulhi_epi16(tmp, err); | |
| tmp = vreinterpretq_s32_s16(vqaddq_s16(vreinterpretq_s16_s32(tmp), vreinterpretq_s16_s32(one))); | |
| tmp = vreinterpretq_s32_s16(vshrq_n_s16(vreinterpretq_s16_s32(tmp), 1)); | |
| tmp = vreinterpretq_s32_s16(vqaddq_s16(vreinterpretq_s16_s32(tmp), vreinterpretq_s16_s32(*reinterpret_cast<int32x4_t*>(&w[i])))); | |
| *reinterpret_cast<int32x4_t*>(&w[i]) = tmp; | |
| } | |
| } | |
Xet Storage Details
- Size:
- 3.63 kB
- Xet hash:
- 21c0707263b091b860d3e3475afdd2a03bd780fcad8bdb39582c022b4c1cff67
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.