Skip to content

Commit f6bc1e3

Browse files
committed
Implement some vec instructions with NEON
1 parent dccc553 commit f6bc1e3

1 file changed

Lines changed: 43 additions & 0 deletions

File tree

emu/vec.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#ifdef __ARM_NEON__
2+
#include <arm_neon.h>
3+
#endif
14
#include <math.h>
25
#include <string.h>
36

@@ -91,8 +94,15 @@ void vec_shiftr_q128(NO_CPU, union xmm_reg *amount, union xmm_reg *dst) {
9194
}
9295

9396
void vec_add_b128(NO_CPU, union xmm_reg *src, union xmm_reg *dst) {
97+
#ifdef __ARM_NEON__
98+
uint8x16_t neon_dst = vld1q_u8(dst->u8);
99+
uint8x16_t neon_src = vld1q_u8(src->u8);
100+
uint8x16_t neon_res = vaddq_u8(neon_dst, neon_src);
101+
vst1q_u8(dst->u8, neon_res);
102+
#else
94103
for (unsigned i = 0; i < array_size(src->u8); i++)
95104
dst->u8[i] += src->u8[i];
105+
#endif
96106
}
97107
void vec_add_d128(NO_CPU, union xmm_reg *src, union xmm_reg *dst) {
98108
for (unsigned i = 0; i < array_size(src->u32); i++)
@@ -142,9 +152,16 @@ void vec_xor64(NO_CPU, union mm_reg *src, union mm_reg *dst) {
142152
}
143153

144154
void vec_min_ub128(NO_CPU, union xmm_reg *src, union xmm_reg *dst) {
155+
#ifdef __ARM_NEON__
156+
uint8x16_t neon_dst = vld1q_u8(dst->u8);
157+
uint8x16_t neon_src = vld1q_u8(src->u8);
158+
uint8x16_t neon_res = vminq_u8(neon_dst, neon_src);
159+
vst1q_u8(dst->u8, neon_res);
160+
#else
145161
for (unsigned i = 0; i < array_size(src->u8); i++)
146162
if (src->u8[i] < dst->u8[i])
147163
dst->u8[i] = src->u8[i];
164+
#endif
148165
}
149166

150167
static bool cmpd(double a, double b, int type) {
@@ -253,20 +270,46 @@ void vec_shuffle_d128(NO_CPU, const union xmm_reg *src, union xmm_reg *dst, uint
253270
}
254271

255272
void vec_compare_eqb128(NO_CPU, const union xmm_reg *src, union xmm_reg *dst) {
273+
#ifdef __ARM_NEON__
274+
uint8x16_t neon_dst = vld1q_u8(dst->u8);
275+
uint8x16_t neon_src = vld1q_u8(src->u8);
276+
uint8x16_t neon_res = vceqq_u8(neon_dst, neon_src);
277+
vst1q_u8(dst->u8, neon_res);
278+
#else
256279
for (unsigned i = 0; i < array_size(src->u8); i++)
257280
dst->u8[i] = dst->u8[i] == src->u8[i] ? ~0 : 0;
281+
#endif
258282
}
259283
void vec_compare_eqd128(NO_CPU, const union xmm_reg *src, union xmm_reg *dst) {
260284
for (unsigned i = 0; i < array_size(src->u32); i++)
261285
dst->u32[i] = dst->u32[i] == src->u32[i] ? ~0 : 0;
262286
}
263287

288+
/*
289+
* Neon algo: (only one part (64bits) is demonstrated, algo works the same for another part)
290+
* z - is a bit which forms the mask, X - is not interesting bit.
291+
* neon_src: zXXXXXXXzXXXXXXXzXXXXXXXzXXXXXXXzXXXXXXXzXXXXXXXzXXXXXXXzXXXXXXX...
292+
* step1: 0000000z0000000z0000000z0000000z0000000z0000000z0000000z0000000z...
293+
* step2: 00000000000000zz00000000000000zz00000000000000zz00000000000000zz...
294+
* step3: 0000000000000000000000000000zzzz0000000000000000000000000000zzzz...
295+
* step4: 00000000000000000000000000000000000000000000000000000000zzzzzzzz...
296+
* After step4, 8 bits at the end of each 64bit lane are loaded into dst.
297+
*/
264298
void vec_movmask_b128(NO_CPU, const union xmm_reg *src, uint32_t *dst) {
265299
*dst = 0;
300+
#if defined(__ARM_NEON__) && defined(__LITTLE_ENDIAN__)
301+
uint8x16_t neon_src = vld1q_u8(src->u8);
302+
uint16x8_t step1 = vshrq_n_u8(neon_src, 7);
303+
uint32x4_t step2 = vsraq_n_u16(step1, step1, 7);
304+
uint64x2_t step3 = vsraq_n_u32(step2, step2, 14);
305+
uint16x8_t step4 = vsraq_n_u64(step3, step3, 28);
306+
*dst |= (vgetq_lane_u8(step4, 8) << 8) | (vgetq_lane_u8(step4, 0));
307+
#else
266308
for (unsigned i = 0; i < array_size(src->u8); i++) {
267309
if (src->u8[i] & (1 << 7))
268310
*dst |= 1 << i;
269311
}
312+
#endif
270313
}
271314

272315
void vec_fmovmask_d128(NO_CPU, const union xmm_reg *src, uint32_t *dst) {

0 commit comments

Comments
 (0)