|
|
1.1 root 1: /*
2: * ARM NEON vector operations.
3: *
4: * Copyright (c) 2007 CodeSourcery.
5: * Written by Paul Brook
6: *
7: * This code is licenced under the GPL.
8: */
9: /* Note that for NEON an "l" prefix means it is a wide operation, unlike
10: scalar arm ops where it means a word size operation. */
11:
12: /* ??? NEON ops should probably have their own float status. */
13: #define NFS &env->vfp.fp_status
14: #define NEON_OP(name) void OPPROTO op_neon_##name (void)
15:
16: NEON_OP(getreg_T0)
17: {
18: T0 = *(uint32_t *)((char *) env + PARAM1);
19: }
20:
21: NEON_OP(getreg_T1)
22: {
23: T1 = *(uint32_t *)((char *) env + PARAM1);
24: }
25:
26: NEON_OP(getreg_T2)
27: {
28: T2 = *(uint32_t *)((char *) env + PARAM1);
29: }
30:
31: NEON_OP(setreg_T0)
32: {
33: *(uint32_t *)((char *) env + PARAM1) = T0;
34: }
35:
36: NEON_OP(setreg_T1)
37: {
38: *(uint32_t *)((char *) env + PARAM1) = T1;
39: }
40:
41: NEON_OP(setreg_T2)
42: {
43: *(uint32_t *)((char *) env + PARAM1) = T2;
44: }
45:
46: #define NEON_TYPE1(name, type) \
47: typedef struct \
48: { \
49: type v1; \
50: } neon_##name;
51: #ifdef WORDS_BIGENDIAN
52: #define NEON_TYPE2(name, type) \
53: typedef struct \
54: { \
55: type v2; \
56: type v1; \
57: } neon_##name;
58: #define NEON_TYPE4(name, type) \
59: typedef struct \
60: { \
61: type v4; \
62: type v3; \
63: type v2; \
64: type v1; \
65: } neon_##name;
66: #else
67: #define NEON_TYPE2(name, type) \
68: typedef struct \
69: { \
70: type v1; \
71: type v2; \
72: } neon_##name;
73: #define NEON_TYPE4(name, type) \
74: typedef struct \
75: { \
76: type v1; \
77: type v2; \
78: type v3; \
79: type v4; \
80: } neon_##name;
81: #endif
82:
83: NEON_TYPE4(s8, int8_t)
84: NEON_TYPE4(u8, uint8_t)
85: NEON_TYPE2(s16, int16_t)
86: NEON_TYPE2(u16, uint16_t)
87: NEON_TYPE1(s32, int32_t)
88: NEON_TYPE1(u32, uint32_t)
89: #undef NEON_TYPE4
90: #undef NEON_TYPE2
91: #undef NEON_TYPE1
92:
93: /* Copy from a uint32_t to a vector structure type. */
94: #define NEON_UNPACK(vtype, dest, val) do { \
95: union { \
96: vtype v; \
97: uint32_t i; \
98: } conv_u; \
99: conv_u.i = (val); \
100: dest = conv_u.v; \
101: } while(0)
102:
103: /* Copy from a vector structure type to a uint32_t. */
104: #define NEON_PACK(vtype, dest, val) do { \
105: union { \
106: vtype v; \
107: uint32_t i; \
108: } conv_u; \
109: conv_u.v = (val); \
110: dest = conv_u.i; \
111: } while(0)
112:
113: #define NEON_DO1 \
114: NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1);
115: #define NEON_DO2 \
116: NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \
117: NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2);
118: #define NEON_DO4 \
119: NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \
120: NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \
121: NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \
122: NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4);
123:
124: #define NEON_VOP(name, vtype, n) \
125: NEON_OP(name) \
126: { \
127: vtype vsrc1; \
128: vtype vsrc2; \
129: vtype vdest; \
130: NEON_UNPACK(vtype, vsrc1, T0); \
131: NEON_UNPACK(vtype, vsrc2, T1); \
132: NEON_DO##n; \
133: NEON_PACK(vtype, T0, vdest); \
134: FORCE_RET(); \
135: }
136:
137: #define NEON_VOP1(name, vtype, n) \
138: NEON_OP(name) \
139: { \
140: vtype vsrc1; \
141: vtype vdest; \
142: NEON_UNPACK(vtype, vsrc1, T0); \
143: NEON_DO##n; \
144: NEON_PACK(vtype, T0, vdest); \
145: FORCE_RET(); \
146: }
147:
148: /* Pairwise operations. */
149: /* For 32-bit elements each segment only contains a single element, so
150: the elementwise and pairwise operations are the same. */
151: #define NEON_PDO2 \
152: NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \
153: NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2);
154: #define NEON_PDO4 \
155: NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \
156: NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \
157: NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \
158: NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \
159:
160: #define NEON_POP(name, vtype, n) \
161: NEON_OP(name) \
162: { \
163: vtype vsrc1; \
164: vtype vsrc2; \
165: vtype vdest; \
166: NEON_UNPACK(vtype, vsrc1, T0); \
167: NEON_UNPACK(vtype, vsrc2, T1); \
168: NEON_PDO##n; \
169: NEON_PACK(vtype, T0, vdest); \
170: FORCE_RET(); \
171: }
172:
173: #define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1
174: NEON_VOP(hadd_s8, neon_s8, 4)
175: NEON_VOP(hadd_u8, neon_u8, 4)
176: NEON_VOP(hadd_s16, neon_s16, 2)
177: NEON_VOP(hadd_u16, neon_u16, 2)
178: #undef NEON_FN
179:
180: NEON_OP(hadd_s32)
181: {
182: int32_t src1 = T0;
183: int32_t src2 = T1;
184: int32_t dest;
185:
186: dest = (src1 >> 1) + (src2 >> 1);
187: if (src1 & src2 & 1)
188: dest++;
189: T0 = dest;
190: FORCE_RET();
191: }
192:
193: NEON_OP(hadd_u32)
194: {
195: uint32_t src1 = T0;
196: uint32_t src2 = T1;
197: uint32_t dest;
198:
199: dest = (src1 >> 1) + (src2 >> 1);
200: if (src1 & src2 & 1)
201: dest++;
202: T0 = dest;
203: FORCE_RET();
204: }
205:
206: #define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1
207: NEON_VOP(rhadd_s8, neon_s8, 4)
208: NEON_VOP(rhadd_u8, neon_u8, 4)
209: NEON_VOP(rhadd_s16, neon_s16, 2)
210: NEON_VOP(rhadd_u16, neon_u16, 2)
211: #undef NEON_FN
212:
213: NEON_OP(rhadd_s32)
214: {
215: int32_t src1 = T0;
216: int32_t src2 = T1;
217: int32_t dest;
218:
219: dest = (src1 >> 1) + (src2 >> 1);
220: if ((src1 | src2) & 1)
221: dest++;
222: T0 = dest;
223: FORCE_RET();
224: }
225:
226: NEON_OP(rhadd_u32)
227: {
228: uint32_t src1 = T0;
229: uint32_t src2 = T1;
230: uint32_t dest;
231:
232: dest = (src1 >> 1) + (src2 >> 1);
233: if ((src1 | src2) & 1)
234: dest++;
235: T0 = dest;
236: FORCE_RET();
237: }
238:
239: #define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1
240: NEON_VOP(hsub_s8, neon_s8, 4)
241: NEON_VOP(hsub_u8, neon_u8, 4)
242: NEON_VOP(hsub_s16, neon_s16, 2)
243: NEON_VOP(hsub_u16, neon_u16, 2)
244: #undef NEON_FN
245:
246: NEON_OP(hsub_s32)
247: {
248: int32_t src1 = T0;
249: int32_t src2 = T1;
250: int32_t dest;
251:
252: dest = (src1 >> 1) - (src2 >> 1);
253: if ((~src1) & src2 & 1)
254: dest--;
255: T0 = dest;
256: FORCE_RET();
257: }
258:
259: NEON_OP(hsub_u32)
260: {
261: uint32_t src1 = T0;
262: uint32_t src2 = T1;
263: uint32_t dest;
264:
265: dest = (src1 >> 1) - (src2 >> 1);
266: if ((~src1) & src2 & 1)
267: dest--;
268: T0 = dest;
269: FORCE_RET();
270: }
271:
272: /* ??? bsl, bif and bit are all the same op, just with the oparands in a
273: differnet order. It's currently easier to have 3 differnt ops than
274: rearange the operands. */
275:
276: /* Bitwise Select. */
277: NEON_OP(bsl)
278: {
279: T0 = (T0 & T2) | (T1 & ~T2);
280: }
281:
282: /* Bitwise Insert If True. */
283: NEON_OP(bit)
284: {
285: T0 = (T0 & T1) | (T2 & ~T1);
286: }
287:
288: /* Bitwise Insert If False. */
289: NEON_OP(bif)
290: {
291: T0 = (T2 & T1) | (T0 & ~T1);
292: }
293:
294: #define NEON_USAT(dest, src1, src2, type) do { \
295: uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \
296: if (tmp != (type)tmp) { \
297: env->QF = 1; \
298: dest = ~0; \
299: } else { \
300: dest = tmp; \
301: }} while(0)
302: #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t)
303: NEON_VOP(qadd_u8, neon_u8, 4)
304: #undef NEON_FN
305: #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t)
306: NEON_VOP(qadd_u16, neon_u16, 2)
307: #undef NEON_FN
308: #undef NEON_USAT
309:
310: #define NEON_SSAT(dest, src1, src2, type) do { \
311: int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \
312: if (tmp != (type)tmp) { \
313: env->QF = 1; \
314: if (src2 > 0) { \
315: tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \
316: } else { \
317: tmp = 1 << (sizeof(type) * 8 - 1); \
318: } \
319: } \
320: dest = tmp; \
321: } while(0)
322: #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t)
323: NEON_VOP(qadd_s8, neon_s8, 4)
324: #undef NEON_FN
325: #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t)
326: NEON_VOP(qadd_s16, neon_s16, 2)
327: #undef NEON_FN
328: #undef NEON_SSAT
329:
330: #define NEON_USAT(dest, src1, src2, type) do { \
331: uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
332: if (tmp != (type)tmp) { \
333: env->QF = 1; \
334: dest = 0; \
335: } else { \
336: dest = tmp; \
337: }} while(0)
338: #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t)
339: NEON_VOP(qsub_u8, neon_u8, 4)
340: #undef NEON_FN
341: #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t)
342: NEON_VOP(qsub_u16, neon_u16, 2)
343: #undef NEON_FN
344: #undef NEON_USAT
345:
346: #define NEON_SSAT(dest, src1, src2, type) do { \
347: int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
348: if (tmp != (type)tmp) { \
349: env->QF = 1; \
350: if (src2 < 0) { \
351: tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \
352: } else { \
353: tmp = 1 << (sizeof(type) * 8 - 1); \
354: } \
355: } \
356: dest = tmp; \
357: } while(0)
358: #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t)
359: NEON_VOP(qsub_s8, neon_s8, 4)
360: #undef NEON_FN
361: #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t)
362: NEON_VOP(qsub_s16, neon_s16, 2)
363: #undef NEON_FN
364: #undef NEON_SSAT
365:
366: #define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0
367: NEON_VOP(cgt_s8, neon_s8, 4)
368: NEON_VOP(cgt_u8, neon_u8, 4)
369: NEON_VOP(cgt_s16, neon_s16, 2)
370: NEON_VOP(cgt_u16, neon_u16, 2)
371: NEON_VOP(cgt_s32, neon_s32, 1)
372: NEON_VOP(cgt_u32, neon_u32, 1)
373: #undef NEON_FN
374:
375: #define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0
376: NEON_VOP(cge_s8, neon_s8, 4)
377: NEON_VOP(cge_u8, neon_u8, 4)
378: NEON_VOP(cge_s16, neon_s16, 2)
379: NEON_VOP(cge_u16, neon_u16, 2)
380: NEON_VOP(cge_s32, neon_s32, 1)
381: NEON_VOP(cge_u32, neon_u32, 1)
382: #undef NEON_FN
383:
384: #define NEON_FN(dest, src1, src2) do { \
385: int8_t tmp; \
386: tmp = (int8_t)src2; \
387: if (tmp < 0) { \
388: dest = src1 >> -tmp; \
389: } else { \
390: dest = src1 << tmp; \
391: }} while (0)
392: NEON_VOP(shl_s8, neon_s8, 4)
393: NEON_VOP(shl_u8, neon_u8, 4)
394: NEON_VOP(shl_s16, neon_s16, 2)
395: NEON_VOP(shl_u16, neon_u16, 2)
396: NEON_VOP(shl_s32, neon_s32, 1)
397: NEON_VOP(shl_u32, neon_u32, 1)
398: #undef NEON_FN
399:
400: NEON_OP(shl_u64)
401: {
402: int8_t shift = T2;
403: uint64_t val = T0 | ((uint64_t)T1 << 32);
404: if (shift < 0) {
405: val >>= -shift;
406: } else {
407: val <<= shift;
408: }
409: T0 = val;
410: T1 = val >> 32;
411: FORCE_RET();
412: }
413:
414: NEON_OP(shl_s64)
415: {
416: int8_t shift = T2;
417: int64_t val = T0 | ((uint64_t)T1 << 32);
418: if (shift < 0) {
419: val >>= -shift;
420: } else {
421: val <<= shift;
422: }
423: T0 = val;
424: T1 = val >> 32;
425: FORCE_RET();
426: }
427:
428: #define NEON_FN(dest, src1, src2) do { \
429: int8_t tmp; \
430: tmp = (int8_t)src1; \
431: if (tmp < 0) { \
432: dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \
433: } else { \
434: dest = src2 << tmp; \
435: }} while (0)
436:
437: NEON_VOP(rshl_s8, neon_s8, 4)
438: NEON_VOP(rshl_u8, neon_u8, 4)
439: NEON_VOP(rshl_s16, neon_s16, 2)
440: NEON_VOP(rshl_u16, neon_u16, 2)
441: NEON_VOP(rshl_s32, neon_s32, 1)
442: NEON_VOP(rshl_u32, neon_u32, 1)
443: #undef NEON_FN
444:
445: NEON_OP(rshl_u64)
446: {
447: int8_t shift = T2;
448: uint64_t val = T0 | ((uint64_t)T1 << 32);
449: if (shift < 0) {
450: val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift;
451: val >>= -shift;
452: } else {
453: val <<= shift;
454: }
455: T0 = val;
456: T1 = val >> 32;
457: FORCE_RET();
458: }
459:
460: NEON_OP(rshl_s64)
461: {
462: int8_t shift = T2;
463: int64_t val = T0 | ((uint64_t)T1 << 32);
464: if (shift < 0) {
465: val = (val + ((int64_t)1 << (-1 - shift))) >> -shift;
466: } else {
467: val <<= shift;
468: }
469: T0 = val;
470: T1 = val >> 32;
471: FORCE_RET();
472: }
473:
474: #define NEON_FN(dest, src1, src2) do { \
475: int8_t tmp; \
476: tmp = (int8_t)src1; \
477: if (tmp < 0) { \
478: dest = src2 >> -tmp; \
479: } else { \
480: dest = src2 << tmp; \
481: if ((dest >> tmp) != src2) { \
482: env->QF = 1; \
483: dest = ~0; \
484: } \
485: }} while (0)
486: NEON_VOP(qshl_s8, neon_s8, 4)
487: NEON_VOP(qshl_s16, neon_s16, 2)
488: NEON_VOP(qshl_s32, neon_s32, 1)
489: #undef NEON_FN
490:
491: NEON_OP(qshl_s64)
492: {
493: int8_t shift = T2;
494: int64_t val = T0 | ((uint64_t)T1 << 32);
495: if (shift < 0) {
496: val >>= -shift;
497: } else {
498: int64_t tmp = val;
499: val <<= shift;
500: if ((val >> shift) != tmp) {
501: env->QF = 1;
502: val = (tmp >> 63) ^ 0x7fffffffffffffffULL;
503: }
504: }
505: T0 = val;
506: T1 = val >> 32;
507: FORCE_RET();
508: }
509:
510: #define NEON_FN(dest, src1, src2) do { \
511: int8_t tmp; \
512: tmp = (int8_t)src1; \
513: if (tmp < 0) { \
514: dest = src2 >> -tmp; \
515: } else { \
516: dest = src2 << tmp; \
517: if ((dest >> tmp) != src2) { \
518: env->QF = 1; \
519: dest = src2 >> 31; \
520: } \
521: }} while (0)
522: NEON_VOP(qshl_u8, neon_u8, 4)
523: NEON_VOP(qshl_u16, neon_u16, 2)
524: NEON_VOP(qshl_u32, neon_u32, 1)
525: #undef NEON_FN
526:
527: NEON_OP(qshl_u64)
528: {
529: int8_t shift = T2;
530: uint64_t val = T0 | ((uint64_t)T1 << 32);
531: if (shift < 0) {
532: val >>= -shift;
533: } else {
534: uint64_t tmp = val;
535: val <<= shift;
536: if ((val >> shift) != tmp) {
537: env->QF = 1;
538: val = ~(uint64_t)0;
539: }
540: }
541: T0 = val;
542: T1 = val >> 32;
543: FORCE_RET();
544: }
545:
546: #define NEON_FN(dest, src1, src2) do { \
547: int8_t tmp; \
548: tmp = (int8_t)src1; \
549: if (tmp < 0) { \
550: dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \
551: } else { \
552: dest = src2 << tmp; \
553: if ((dest >> tmp) != src2) { \
554: dest = ~0; \
555: } \
556: }} while (0)
557: NEON_VOP(qrshl_s8, neon_s8, 4)
558: NEON_VOP(qrshl_s16, neon_s16, 2)
559: NEON_VOP(qrshl_s32, neon_s32, 1)
560: #undef NEON_FN
561:
562: #define NEON_FN(dest, src1, src2) do { \
563: int8_t tmp; \
564: tmp = (int8_t)src1; \
565: if (tmp < 0) { \
566: dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \
567: } else { \
568: dest = src2 << tmp; \
569: if ((dest >> tmp) != src2) { \
570: env->QF = 1; \
571: dest = src2 >> 31; \
572: } \
573: }} while (0)
574: NEON_VOP(qrshl_u8, neon_u8, 4)
575: NEON_VOP(qrshl_u16, neon_u16, 2)
576: NEON_VOP(qrshl_u32, neon_u32, 1)
577: #undef NEON_FN
578:
579: #define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2
580: NEON_VOP(max_s8, neon_s8, 4)
581: NEON_VOP(max_u8, neon_u8, 4)
582: NEON_VOP(max_s16, neon_s16, 2)
583: NEON_VOP(max_u16, neon_u16, 2)
584: NEON_VOP(max_s32, neon_s32, 1)
585: NEON_VOP(max_u32, neon_u32, 1)
586: NEON_POP(pmax_s8, neon_s8, 4)
587: NEON_POP(pmax_u8, neon_u8, 4)
588: NEON_POP(pmax_s16, neon_s16, 2)
589: NEON_POP(pmax_u16, neon_u16, 2)
590: #undef NEON_FN
591:
592: NEON_OP(max_f32)
593: {
594: float32 f0 = vfp_itos(T0);
595: float32 f1 = vfp_itos(T1);
596: T0 = (float32_compare_quiet(f0, f1, NFS) == 1) ? T0 : T1;
597: FORCE_RET();
598: }
599:
600: #define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2
601: NEON_VOP(min_s8, neon_s8, 4)
602: NEON_VOP(min_u8, neon_u8, 4)
603: NEON_VOP(min_s16, neon_s16, 2)
604: NEON_VOP(min_u16, neon_u16, 2)
605: NEON_VOP(min_s32, neon_s32, 1)
606: NEON_VOP(min_u32, neon_u32, 1)
607: NEON_POP(pmin_s8, neon_s8, 4)
608: NEON_POP(pmin_u8, neon_u8, 4)
609: NEON_POP(pmin_s16, neon_s16, 2)
610: NEON_POP(pmin_u16, neon_u16, 2)
611: #undef NEON_FN
612:
613: NEON_OP(min_f32)
614: {
615: float32 f0 = vfp_itos(T0);
616: float32 f1 = vfp_itos(T1);
617: T0 = (float32_compare_quiet(f0, f1, NFS) == -1) ? T0 : T1;
618: FORCE_RET();
619: }
620:
621: #define NEON_FN(dest, src1, src2) \
622: dest = (src1 > src2) ? (src1 - src2) : (src2 - src1)
623: NEON_VOP(abd_s8, neon_s8, 4)
624: NEON_VOP(abd_u8, neon_u8, 4)
625: NEON_VOP(abd_s16, neon_s16, 2)
626: NEON_VOP(abd_u16, neon_u16, 2)
627: NEON_VOP(abd_s32, neon_s32, 1)
628: NEON_VOP(abd_u32, neon_u32, 1)
629: #undef NEON_FN
630:
631: NEON_OP(abd_f32)
632: {
633: float32 f0 = vfp_itos(T0);
634: float32 f1 = vfp_itos(T1);
635: T0 = vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1)
636: ? float32_sub(f0, f1, NFS)
637: : float32_sub(f1, f0, NFS));
638: FORCE_RET();
639: }
640:
641: #define NEON_FN(dest, src1, src2) dest = src1 + src2
642: NEON_VOP(add_u8, neon_u8, 4)
643: NEON_VOP(add_u16, neon_u16, 2)
644: NEON_POP(padd_u8, neon_u8, 4)
645: NEON_POP(padd_u16, neon_u16, 2)
646: #undef NEON_FN
647:
648: NEON_OP(add_f32)
649: {
650: T0 = vfp_stoi(float32_add(vfp_itos(T0), vfp_itos(T1), NFS));
651: FORCE_RET();
652: }
653:
654: #define NEON_FN(dest, src1, src2) dest = src1 - src2
655: NEON_VOP(sub_u8, neon_u8, 4)
656: NEON_VOP(sub_u16, neon_u16, 2)
657: #undef NEON_FN
658:
659: NEON_OP(sub_f32)
660: {
661: T0 = vfp_stoi(float32_sub(vfp_itos(T0), vfp_itos(T1), NFS));
662: FORCE_RET();
663: }
664:
665: #define NEON_FN(dest, src1, src2) dest = src2 - src1
666: NEON_VOP(rsb_u8, neon_u8, 4)
667: NEON_VOP(rsb_u16, neon_u16, 2)
668: #undef NEON_FN
669:
670: NEON_OP(rsb_f32)
671: {
672: T0 = vfp_stoi(float32_sub(vfp_itos(T1), vfp_itos(T0), NFS));
673: FORCE_RET();
674: }
675:
676: #define NEON_FN(dest, src1, src2) dest = src1 * src2
677: NEON_VOP(mul_u8, neon_u8, 4)
678: NEON_VOP(mul_u16, neon_u16, 2)
679: #undef NEON_FN
680:
681: NEON_OP(mul_f32)
682: {
683: T0 = vfp_stoi(float32_mul(vfp_itos(T0), vfp_itos(T1), NFS));
684: FORCE_RET();
685: }
686:
687: NEON_OP(mul_p8)
688: {
689: T0 = helper_neon_mul_p8(T0, T1);
690: }
691:
692: #define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0
693: NEON_VOP(tst_u8, neon_u8, 4)
694: NEON_VOP(tst_u16, neon_u16, 2)
695: NEON_VOP(tst_u32, neon_u32, 1)
696: #undef NEON_FN
697:
698: #define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0
699: NEON_VOP(ceq_u8, neon_u8, 4)
700: NEON_VOP(ceq_u16, neon_u16, 2)
701: NEON_VOP(ceq_u32, neon_u32, 1)
702: #undef NEON_FN
703:
704: #define NEON_QDMULH16(dest, src1, src2, round) do { \
705: uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \
706: if ((tmp ^ (tmp << 1)) & SIGNBIT) { \
707: env->QF = 1; \
708: tmp = (tmp >> 31) ^ ~SIGNBIT; \
709: } \
710: tmp <<= 1; \
711: if (round) { \
712: int32_t old = tmp; \
713: tmp += 1 << 15; \
714: if ((int32_t)tmp < old) { \
715: env->QF = 1; \
716: tmp = SIGNBIT - 1; \
717: } \
718: } \
719: dest = tmp >> 16; \
720: } while(0)
721: #define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0)
722: NEON_VOP(qdmulh_s16, neon_s16, 2)
723: #undef NEON_FN
724: #define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1)
725: NEON_VOP(qrdmulh_s16, neon_s16, 2)
726: #undef NEON_FN
727: #undef NEON_QDMULH16
728:
729: #define SIGNBIT64 ((uint64_t)1 << 63)
730: #define NEON_QDMULH32(dest, src1, src2, round) do { \
731: uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \
732: if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \
733: env->QF = 1; \
734: tmp = (tmp >> 63) ^ ~SIGNBIT64; \
735: } else { \
736: tmp <<= 1; \
737: } \
738: if (round) { \
739: int64_t old = tmp; \
740: tmp += (int64_t)1 << 31; \
741: if ((int64_t)tmp < old) { \
742: env->QF = 1; \
743: tmp = SIGNBIT64 - 1; \
744: } \
745: } \
746: dest = tmp >> 32; \
747: } while(0)
748: #define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0)
749: NEON_VOP(qdmulh_s32, neon_s32, 1)
750: #undef NEON_FN
751: #define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1)
752: NEON_VOP(qrdmulh_s32, neon_s32, 1)
753: #undef NEON_FN
754: #undef NEON_QDMULH32
755:
756: NEON_OP(recps_f32)
757: {
758: T0 = vfp_stoi(helper_recps_f32(vfp_itos(T0), vfp_itos(T1)));
759: FORCE_RET();
760: }
761:
762: NEON_OP(rsqrts_f32)
763: {
764: T0 = vfp_stoi(helper_rsqrts_f32(vfp_itos(T0), vfp_itos(T1)));
765: FORCE_RET();
766: }
767:
768: /* Floating point comparisons produce an integer result. */
769: #define NEON_VOP_FCMP(name, cmp) \
770: NEON_OP(name) \
771: { \
772: if (float32_compare_quiet(vfp_itos(T0), vfp_itos(T1), NFS) cmp 0) \
773: T0 = -1; \
774: else \
775: T0 = 0; \
776: FORCE_RET(); \
777: }
778:
779: NEON_VOP_FCMP(ceq_f32, ==)
780: NEON_VOP_FCMP(cge_f32, >=)
781: NEON_VOP_FCMP(cgt_f32, >)
782:
783: NEON_OP(acge_f32)
784: {
785: float32 f0 = float32_abs(vfp_itos(T0));
786: float32 f1 = float32_abs(vfp_itos(T1));
787: T0 = (float32_compare_quiet(f0, f1,NFS) >= 0) ? -1 : 0;
788: FORCE_RET();
789: }
790:
791: NEON_OP(acgt_f32)
792: {
793: float32 f0 = float32_abs(vfp_itos(T0));
794: float32 f1 = float32_abs(vfp_itos(T1));
795: T0 = (float32_compare_quiet(f0, f1, NFS) > 0) ? -1 : 0;
796: FORCE_RET();
797: }
798:
799: /* Narrowing instructions. The named type is the destination type. */
800: NEON_OP(narrow_u8)
801: {
802: T0 = (T0 & 0xff) | ((T0 >> 8) & 0xff00)
803: | ((T1 << 16) & 0xff0000) | (T1 << 24);
804: FORCE_RET();
805: }
806:
807: NEON_OP(narrow_sat_u8)
808: {
809: neon_u16 src;
810: neon_u8 dest;
811: #define SAT8(d, s) \
812: if (s > 0xff) { \
813: d = 0xff; \
814: env->QF = 1; \
815: } else { \
816: d = s; \
817: }
818:
819: NEON_UNPACK(neon_u16, src, T0);
820: SAT8(dest.v1, src.v1);
821: SAT8(dest.v2, src.v2);
822: NEON_UNPACK(neon_u16, src, T1);
823: SAT8(dest.v3, src.v1);
824: SAT8(dest.v4, src.v2);
825: NEON_PACK(neon_u8, T0, dest);
826: FORCE_RET();
827: #undef SAT8
828: }
829:
830: NEON_OP(narrow_sat_s8)
831: {
832: neon_s16 src;
833: neon_s8 dest;
834: #define SAT8(d, s) \
835: if (s != (uint8_t)s) { \
836: d = (s >> 15) ^ 0x7f; \
837: env->QF = 1; \
838: } else { \
839: d = s; \
840: }
841:
842: NEON_UNPACK(neon_s16, src, T0);
843: SAT8(dest.v1, src.v1);
844: SAT8(dest.v2, src.v2);
845: NEON_UNPACK(neon_s16, src, T1);
846: SAT8(dest.v3, src.v1);
847: SAT8(dest.v4, src.v2);
848: NEON_PACK(neon_s8, T0, dest);
849: FORCE_RET();
850: #undef SAT8
851: }
852:
853: NEON_OP(narrow_u16)
854: {
855: T0 = (T0 & 0xffff) | (T1 << 16);
856: }
857:
858: NEON_OP(narrow_sat_u16)
859: {
860: if (T0 > 0xffff) {
861: T0 = 0xffff;
862: env->QF = 1;
863: }
864: if (T1 > 0xffff) {
865: T1 = 0xffff;
866: env->QF = 1;
867: }
868: T0 |= T1 << 16;
869: FORCE_RET();
870: }
871:
872: NEON_OP(narrow_sat_s16)
873: {
874: if ((int32_t)T0 != (int16_t)T0) {
875: T0 = ((int32_t)T0 >> 31) ^ 0x7fff;
876: env->QF = 1;
877: }
878: if ((int32_t)T1 != (int16_t) T1) {
879: T1 = ((int32_t)T1 >> 31) ^ 0x7fff;
880: env->QF = 1;
881: }
882: T0 = (uint16_t)T0 | (T1 << 16);
883: FORCE_RET();
884: }
885:
886: NEON_OP(narrow_sat_u32)
887: {
888: if (T1) {
889: T0 = 0xffffffffu;
890: env->QF = 1;
891: }
892: FORCE_RET();
893: }
894:
895: NEON_OP(narrow_sat_s32)
896: {
897: int32_t sign = (int32_t)T1 >> 31;
898:
899: if ((int32_t)T1 != sign) {
900: T0 = sign ^ 0x7fffffff;
901: env->QF = 1;
902: }
903: FORCE_RET();
904: }
905:
906: /* Narrowing instructions. Named type is the narrow type. */
907: NEON_OP(narrow_high_u8)
908: {
909: T0 = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00)
910: | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000);
911: FORCE_RET();
912: }
913:
914: NEON_OP(narrow_high_u16)
915: {
916: T0 = (T0 >> 16) | (T1 & 0xffff0000);
917: FORCE_RET();
918: }
919:
920: NEON_OP(narrow_high_round_u8)
921: {
922: T0 = (((T0 + 0x80) >> 8) & 0xff) | (((T0 + 0x800000) >> 16) & 0xff00)
923: | (((T1 + 0x80) << 8) & 0xff0000) | ((T1 + 0x800000) & 0xff000000);
924: FORCE_RET();
925: }
926:
927: NEON_OP(narrow_high_round_u16)
928: {
929: T0 = ((T0 + 0x8000) >> 16) | ((T1 + 0x8000) & 0xffff0000);
930: FORCE_RET();
931: }
932:
933: NEON_OP(narrow_high_round_u32)
934: {
935: if (T0 >= 0x80000000u)
936: T0 = T1 + 1;
937: else
938: T0 = T1;
939: FORCE_RET();
940: }
941:
942: /* Widening instructions. Named type is source type. */
943: NEON_OP(widen_s8)
944: {
945: uint32_t src;
946:
947: src = T0;
948: T0 = (uint16_t)(int8_t)src | ((int8_t)(src >> 8) << 16);
949: T1 = (uint16_t)(int8_t)(src >> 16) | ((int8_t)(src >> 24) << 16);
950: }
951:
952: NEON_OP(widen_u8)
953: {
954: T1 = ((T0 >> 8) & 0xff0000) | ((T0 >> 16) & 0xff);
955: T0 = ((T0 << 8) & 0xff0000) | (T0 & 0xff);
956: }
957:
958: NEON_OP(widen_s16)
959: {
960: int32_t src;
961:
962: src = T0;
963: T0 = (int16_t)src;
964: T1 = src >> 16;
965: }
966:
967: NEON_OP(widen_u16)
968: {
969: T1 = T0 >> 16;
970: T0 &= 0xffff;
971: }
972:
973: NEON_OP(widen_s32)
974: {
975: T1 = (int32_t)T0 >> 31;
976: FORCE_RET();
977: }
978:
979: NEON_OP(widen_high_u8)
980: {
981: T1 = (T0 & 0xff000000) | ((T0 >> 8) & 0xff00);
982: T0 = ((T0 << 16) & 0xff000000) | ((T0 << 8) & 0xff00);
983: }
984:
985: NEON_OP(widen_high_u16)
986: {
987: T1 = T0 & 0xffff0000;
988: T0 <<= 16;
989: }
990:
991: /* Long operations. The type is the wide type. */
992: NEON_OP(shll_u16)
993: {
994: int shift = PARAM1;
995: uint32_t mask;
996:
997: mask = 0xffff >> (16 - shift);
998: mask |= mask << 16;
999: mask = ~mask;
1000:
1001: T0 = (T0 << shift) & mask;
1002: T1 = (T1 << shift) & mask;
1003: FORCE_RET();
1004: }
1005:
1006: NEON_OP(shll_u64)
1007: {
1008: int shift = PARAM1;
1009:
1010: T1 <<= shift;
1011: T1 |= T0 >> (32 - shift);
1012: T0 <<= shift;
1013: FORCE_RET();
1014: }
1015:
1016: NEON_OP(addl_u16)
1017: {
1018: uint32_t tmp;
1019: uint32_t high;
1020:
1021: tmp = env->vfp.scratch[0];
1022: high = (T0 >> 16) + (tmp >> 16);
1023: T0 = (uint16_t)(T0 + tmp);
1024: T0 |= (high << 16);
1025: tmp = env->vfp.scratch[1];
1026: high = (T1 >> 16) + (tmp >> 16);
1027: T1 = (uint16_t)(T1 + tmp);
1028: T1 |= (high << 16);
1029: FORCE_RET();
1030: }
1031:
1032: NEON_OP(addl_u32)
1033: {
1034: T0 += env->vfp.scratch[0];
1035: T1 += env->vfp.scratch[1];
1036: FORCE_RET();
1037: }
1038:
1039: NEON_OP(addl_u64)
1040: {
1041: uint64_t tmp;
1042: tmp = T0 | ((uint64_t)T1 << 32);
1043: tmp += env->vfp.scratch[0];
1044: tmp += (uint64_t)env->vfp.scratch[1] << 32;
1045: T0 = tmp;
1046: T1 = tmp >> 32;
1047: FORCE_RET();
1048: }
1049:
1050: NEON_OP(subl_u16)
1051: {
1052: uint32_t tmp;
1053: uint32_t high;
1054:
1055: tmp = env->vfp.scratch[0];
1056: high = (T0 >> 16) - (tmp >> 16);
1057: T0 = (uint16_t)(T0 - tmp);
1058: T0 |= (high << 16);
1059: tmp = env->vfp.scratch[1];
1060: high = (T1 >> 16) - (tmp >> 16);
1061: T1 = (uint16_t)(T1 - tmp);
1062: T1 |= (high << 16);
1063: FORCE_RET();
1064: }
1065:
1066: NEON_OP(subl_u32)
1067: {
1068: T0 -= env->vfp.scratch[0];
1069: T1 -= env->vfp.scratch[1];
1070: FORCE_RET();
1071: }
1072:
1073: NEON_OP(subl_u64)
1074: {
1075: uint64_t tmp;
1076: tmp = T0 | ((uint64_t)T1 << 32);
1077: tmp -= env->vfp.scratch[0];
1078: tmp -= (uint64_t)env->vfp.scratch[1] << 32;
1079: T0 = tmp;
1080: T1 = tmp >> 32;
1081: FORCE_RET();
1082: }
1083:
1084: #define DO_ABD(dest, x, y, type) do { \
1085: type tmp_x = x; \
1086: type tmp_y = y; \
1087: dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \
1088: } while(0)
1089:
1090: NEON_OP(abdl_u16)
1091: {
1092: uint32_t tmp;
1093: uint32_t low;
1094: uint32_t high;
1095:
1096: DO_ABD(low, T0, T1, uint8_t);
1097: DO_ABD(tmp, T0 >> 8, T1 >> 8, uint8_t);
1098: low |= tmp << 16;
1099: DO_ABD(high, T0 >> 16, T1 >> 16, uint8_t);
1100: DO_ABD(tmp, T0 >> 24, T1 >> 24, uint8_t);
1101: high |= tmp << 16;
1102: T0 = low;
1103: T1 = high;
1104: FORCE_RET();
1105: }
1106:
1107: NEON_OP(abdl_s16)
1108: {
1109: uint32_t tmp;
1110: uint32_t low;
1111: uint32_t high;
1112:
1113: DO_ABD(low, T0, T1, int8_t);
1114: DO_ABD(tmp, T0 >> 8, T1 >> 8, int8_t);
1115: low |= tmp << 16;
1116: DO_ABD(high, T0 >> 16, T1 >> 16, int8_t);
1117: DO_ABD(tmp, T0 >> 24, T1 >> 24, int8_t);
1118: high |= tmp << 16;
1119: T0 = low;
1120: T1 = high;
1121: FORCE_RET();
1122: }
1123:
1124: NEON_OP(abdl_u32)
1125: {
1126: uint32_t low;
1127: uint32_t high;
1128:
1129: DO_ABD(low, T0, T1, uint16_t);
1130: DO_ABD(high, T0 >> 16, T1 >> 16, uint16_t);
1131: T0 = low;
1132: T1 = high;
1133: FORCE_RET();
1134: }
1135:
1136: NEON_OP(abdl_s32)
1137: {
1138: uint32_t low;
1139: uint32_t high;
1140:
1141: DO_ABD(low, T0, T1, int16_t);
1142: DO_ABD(high, T0 >> 16, T1 >> 16, int16_t);
1143: T0 = low;
1144: T1 = high;
1145: FORCE_RET();
1146: }
1147:
1148: NEON_OP(abdl_u64)
1149: {
1150: DO_ABD(T0, T0, T1, uint32_t);
1151: T1 = 0;
1152: }
1153:
1154: NEON_OP(abdl_s64)
1155: {
1156: DO_ABD(T0, T0, T1, int32_t);
1157: T1 = 0;
1158: }
1159: #undef DO_ABD
1160:
1161: /* Widening multiple. Named type is the source type. */
1162: #define DO_MULL(dest, x, y, type1, type2) do { \
1163: type1 tmp_x = x; \
1164: type1 tmp_y = y; \
1165: dest = (type2)((type2)tmp_x * (type2)tmp_y); \
1166: } while(0)
1167:
1168: NEON_OP(mull_u8)
1169: {
1170: uint32_t tmp;
1171: uint32_t low;
1172: uint32_t high;
1173:
1174: DO_MULL(low, T0, T1, uint8_t, uint16_t);
1175: DO_MULL(tmp, T0 >> 8, T1 >> 8, uint8_t, uint16_t);
1176: low |= tmp << 16;
1177: DO_MULL(high, T0 >> 16, T1 >> 16, uint8_t, uint16_t);
1178: DO_MULL(tmp, T0 >> 24, T1 >> 24, uint8_t, uint16_t);
1179: high |= tmp << 16;
1180: T0 = low;
1181: T1 = high;
1182: FORCE_RET();
1183: }
1184:
1185: NEON_OP(mull_s8)
1186: {
1187: uint32_t tmp;
1188: uint32_t low;
1189: uint32_t high;
1190:
1191: DO_MULL(low, T0, T1, int8_t, uint16_t);
1192: DO_MULL(tmp, T0 >> 8, T1 >> 8, int8_t, uint16_t);
1193: low |= tmp << 16;
1194: DO_MULL(high, T0 >> 16, T1 >> 16, int8_t, uint16_t);
1195: DO_MULL(tmp, T0 >> 24, T1 >> 24, int8_t, uint16_t);
1196: high |= tmp << 16;
1197: T0 = low;
1198: T1 = high;
1199: FORCE_RET();
1200: }
1201:
1202: NEON_OP(mull_u16)
1203: {
1204: uint32_t low;
1205: uint32_t high;
1206:
1207: DO_MULL(low, T0, T1, uint16_t, uint32_t);
1208: DO_MULL(high, T0 >> 16, T1 >> 16, uint16_t, uint32_t);
1209: T0 = low;
1210: T1 = high;
1211: FORCE_RET();
1212: }
1213:
1214: NEON_OP(mull_s16)
1215: {
1216: uint32_t low;
1217: uint32_t high;
1218:
1219: DO_MULL(low, T0, T1, int16_t, uint32_t);
1220: DO_MULL(high, T0 >> 16, T1 >> 16, int16_t, uint32_t);
1221: T0 = low;
1222: T1 = high;
1223: FORCE_RET();
1224: }
1225:
1226: NEON_OP(addl_saturate_s32)
1227: {
1228: uint32_t tmp;
1229: uint32_t res;
1230:
1231: tmp = env->vfp.scratch[0];
1232: res = T0 + tmp;
1233: if (((res ^ T0) & SIGNBIT) && !((T0 ^ tmp) & SIGNBIT)) {
1234: env->QF = 1;
1235: T0 = (T0 >> 31) ^ 0x7fffffff;
1236: } else {
1237: T0 = res;
1238: }
1239: tmp = env->vfp.scratch[1];
1240: res = T1 + tmp;
1241: if (((res ^ T1) & SIGNBIT) && !((T1 ^ tmp) & SIGNBIT)) {
1242: env->QF = 1;
1243: T1 = (T1 >> 31) ^ 0x7fffffff;
1244: } else {
1245: T1 = res;
1246: }
1247: FORCE_RET();
1248: }
1249:
1250: NEON_OP(addl_saturate_s64)
1251: {
1252: uint64_t src1;
1253: uint64_t src2;
1254: uint64_t res;
1255:
1256: src1 = T0 + ((uint64_t)T1 << 32);
1257: src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32);
1258: res = src1 + src2;
1259: if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
1260: env->QF = 1;
1261: T0 = ~(int64_t)src1 >> 63;
1262: T1 = T0 ^ 0x80000000;
1263: } else {
1264: T0 = res;
1265: T1 = res >> 32;
1266: }
1267: FORCE_RET();
1268: }
1269:
1270: NEON_OP(addl_saturate_u64)
1271: {
1272: uint64_t src1;
1273: uint64_t src2;
1274: uint64_t res;
1275:
1276: src1 = T0 + ((uint64_t)T1 << 32);
1277: src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32);
1278: res = src1 + src2;
1279: if (res < src1) {
1280: env->QF = 1;
1281: T0 = 0xffffffff;
1282: T1 = 0xffffffff;
1283: } else {
1284: T0 = res;
1285: T1 = res >> 32;
1286: }
1287: FORCE_RET();
1288: }
1289:
1290: NEON_OP(subl_saturate_s64)
1291: {
1292: uint64_t src1;
1293: uint64_t src2;
1294: uint64_t res;
1295:
1296: src1 = T0 + ((uint64_t)T1 << 32);
1297: src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32);
1298: res = src1 - src2;
1299: if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
1300: env->QF = 1;
1301: T0 = ~(int64_t)src1 >> 63;
1302: T1 = T0 ^ 0x80000000;
1303: } else {
1304: T0 = res;
1305: T1 = res >> 32;
1306: }
1307: FORCE_RET();
1308: }
1309:
1310: NEON_OP(subl_saturate_u64)
1311: {
1312: uint64_t src1;
1313: uint64_t src2;
1314: uint64_t res;
1315:
1316: src1 = T0 + ((uint64_t)T1 << 32);
1317: src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32);
1318: if (src1 < src2) {
1319: env->QF = 1;
1320: T0 = 0;
1321: T1 = 0;
1322: } else {
1323: res = src1 - src2;
1324: T0 = res;
1325: T1 = res >> 32;
1326: }
1327: FORCE_RET();
1328: }
1329:
1330: NEON_OP(negl_u16)
1331: {
1332: uint32_t tmp;
1333: tmp = T0 >> 16;
1334: tmp = -tmp;
1335: T0 = (-T0 & 0xffff) | (tmp << 16);
1336: tmp = T1 >> 16;
1337: tmp = -tmp;
1338: T1 = (-T1 & 0xffff) | (tmp << 16);
1339: FORCE_RET();
1340: }
1341:
1342: NEON_OP(negl_u32)
1343: {
1344: T0 = -T0;
1345: T1 = -T1;
1346: FORCE_RET();
1347: }
1348:
1349: NEON_OP(negl_u64)
1350: {
1351: uint64_t val;
1352:
1353: val = T0 | ((uint64_t)T1 << 32);
1354: val = -val;
1355: T0 = val;
1356: T1 = val >> 32;
1357: FORCE_RET();
1358: }
1359:
1360: /* Scalar operations. */
1361: NEON_OP(dup_low16)
1362: {
1363: T0 = (T0 & 0xffff) | (T0 << 16);
1364: FORCE_RET();
1365: }
1366:
1367: NEON_OP(dup_high16)
1368: {
1369: T0 = (T0 >> 16) | (T0 & 0xffff0000);
1370: FORCE_RET();
1371: }
1372:
1373: /* Helper for VEXT */
1374: NEON_OP(extract)
1375: {
1376: int shift = PARAM1;
1377: T0 = (T0 >> shift) | (T1 << (32 - shift));
1378: FORCE_RET();
1379: }
1380:
1381: /* Pairwise add long. Named type is source type. */
1382: NEON_OP(paddl_s8)
1383: {
1384: int8_t src1;
1385: int8_t src2;
1386: uint16_t result;
1387: src1 = T0 >> 24;
1388: src2 = T0 >> 16;
1389: result = (uint16_t)src1 + src2;
1390: src1 = T0 >> 8;
1391: src2 = T0;
1392: T0 = (uint16_t)((uint16_t)src1 + src2) | ((uint32_t)result << 16);
1393: FORCE_RET();
1394: }
1395:
1396: NEON_OP(paddl_u8)
1397: {
1398: uint8_t src1;
1399: uint8_t src2;
1400: uint16_t result;
1401: src1 = T0 >> 24;
1402: src2 = T0 >> 16;
1403: result = (uint16_t)src1 + src2;
1404: src1 = T0 >> 8;
1405: src2 = T0;
1406: T0 = (uint16_t)((uint16_t)src1 + src2) | ((uint32_t)result << 16);
1407: FORCE_RET();
1408: }
1409:
1410: NEON_OP(paddl_s16)
1411: {
1412: T0 = (uint32_t)(int16_t)T0 + (uint32_t)(int16_t)(T0 >> 16);
1413: FORCE_RET();
1414: }
1415:
1416: NEON_OP(paddl_u16)
1417: {
1418: T0 = (uint32_t)(uint16_t)T0 + (uint32_t)(uint16_t)(T0 >> 16);
1419: FORCE_RET();
1420: }
1421:
1422: NEON_OP(paddl_s32)
1423: {
1424: int64_t tmp;
1425: tmp = (int64_t)(int32_t)T0 + (int64_t)(int32_t)T1;
1426: T0 = tmp;
1427: T1 = tmp >> 32;
1428: FORCE_RET();
1429: }
1430:
1431: NEON_OP(paddl_u32)
1432: {
1433: uint64_t tmp;
1434: tmp = (uint64_t)T0 + (uint64_t)T1;
1435: T0 = tmp;
1436: T1 = tmp >> 32;
1437: FORCE_RET();
1438: }
1439:
1440: /* Count Leading Sign/Zero Bits. */
1441: static inline int do_clz8(uint8_t x)
1442: {
1443: int n;
1444: for (n = 8; x; n--)
1445: x >>= 1;
1446: return n;
1447: }
1448:
1449: static inline int do_clz16(uint16_t x)
1450: {
1451: int n;
1452: for (n = 16; x; n--)
1453: x >>= 1;
1454: return n;
1455: }
1456:
1457: NEON_OP(clz_u8)
1458: {
1459: uint32_t result;
1460: uint32_t tmp;
1461:
1462: tmp = T0;
1463: result = do_clz8(tmp);
1464: result |= do_clz8(tmp >> 8) << 8;
1465: result |= do_clz8(tmp >> 16) << 16;
1466: result |= do_clz8(tmp >> 24) << 24;
1467: T0 = result;
1468: FORCE_RET();
1469: }
1470:
1471: NEON_OP(clz_u16)
1472: {
1473: uint32_t result;
1474: uint32_t tmp;
1475: tmp = T0;
1476: result = do_clz16(tmp);
1477: result |= do_clz16(tmp >> 16) << 16;
1478: T0 = result;
1479: FORCE_RET();
1480: }
1481:
1482: NEON_OP(cls_s8)
1483: {
1484: uint32_t result;
1485: int8_t tmp;
1486: tmp = T0;
1487: result = do_clz8((tmp < 0) ? ~tmp : tmp) - 1;
1488: tmp = T0 >> 8;
1489: result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 8;
1490: tmp = T0 >> 16;
1491: result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 16;
1492: tmp = T0 >> 24;
1493: result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 24;
1494: T0 = result;
1495: FORCE_RET();
1496: }
1497:
1498: NEON_OP(cls_s16)
1499: {
1500: uint32_t result;
1501: int16_t tmp;
1502: tmp = T0;
1503: result = do_clz16((tmp < 0) ? ~tmp : tmp) - 1;
1504: tmp = T0 >> 16;
1505: result |= (do_clz16((tmp < 0) ? ~tmp : tmp) - 1) << 16;
1506: T0 = result;
1507: FORCE_RET();
1508: }
1509:
1510: NEON_OP(cls_s32)
1511: {
1512: int count;
1513: if ((int32_t)T0 < 0)
1514: T0 = ~T0;
1515: for (count = 32; T0 > 0; count--)
1516: T0 = T0 >> 1;
1517: T0 = count - 1;
1518: FORCE_RET();
1519: }
1520:
1521: /* Bit count. */
1522: NEON_OP(cnt_u8)
1523: {
1524: T0 = (T0 & 0x55555555) + ((T0 >> 1) & 0x55555555);
1525: T0 = (T0 & 0x33333333) + ((T0 >> 2) & 0x33333333);
1526: T0 = (T0 & 0x0f0f0f0f) + ((T0 >> 4) & 0x0f0f0f0f);
1527: FORCE_RET();
1528: }
1529:
1530: /* Saturnating negation. */
1531: /* ??? Make these use NEON_VOP1 */
1532: #define DO_QABS8(x) do { \
1533: if (x == (int8_t)0x80) { \
1534: x = 0x7f; \
1535: env->QF = 1; \
1536: } else if (x < 0) { \
1537: x = -x; \
1538: }} while (0)
1539: NEON_OP(qabs_s8)
1540: {
1541: neon_s8 vec;
1542: NEON_UNPACK(neon_s8, vec, T0);
1543: DO_QABS8(vec.v1);
1544: DO_QABS8(vec.v2);
1545: DO_QABS8(vec.v3);
1546: DO_QABS8(vec.v4);
1547: NEON_PACK(neon_s8, T0, vec);
1548: FORCE_RET();
1549: }
1550: #undef DO_QABS8
1551:
1552: #define DO_QNEG8(x) do { \
1553: if (x == (int8_t)0x80) { \
1554: x = 0x7f; \
1555: env->QF = 1; \
1556: } else { \
1557: x = -x; \
1558: }} while (0)
1559: NEON_OP(qneg_s8)
1560: {
1561: neon_s8 vec;
1562: NEON_UNPACK(neon_s8, vec, T0);
1563: DO_QNEG8(vec.v1);
1564: DO_QNEG8(vec.v2);
1565: DO_QNEG8(vec.v3);
1566: DO_QNEG8(vec.v4);
1567: NEON_PACK(neon_s8, T0, vec);
1568: FORCE_RET();
1569: }
1570: #undef DO_QNEG8
1571:
1572: #define DO_QABS16(x) do { \
1573: if (x == (int16_t)0x8000) { \
1574: x = 0x7fff; \
1575: env->QF = 1; \
1576: } else if (x < 0) { \
1577: x = -x; \
1578: }} while (0)
1579: NEON_OP(qabs_s16)
1580: {
1581: neon_s16 vec;
1582: NEON_UNPACK(neon_s16, vec, T0);
1583: DO_QABS16(vec.v1);
1584: DO_QABS16(vec.v2);
1585: NEON_PACK(neon_s16, T0, vec);
1586: FORCE_RET();
1587: }
1588: #undef DO_QABS16
1589:
1590: #define DO_QNEG16(x) do { \
1591: if (x == (int16_t)0x8000) { \
1592: x = 0x7fff; \
1593: env->QF = 1; \
1594: } else { \
1595: x = -x; \
1596: }} while (0)
1597: NEON_OP(qneg_s16)
1598: {
1599: neon_s16 vec;
1600: NEON_UNPACK(neon_s16, vec, T0);
1601: DO_QNEG16(vec.v1);
1602: DO_QNEG16(vec.v2);
1603: NEON_PACK(neon_s16, T0, vec);
1604: FORCE_RET();
1605: }
1606: #undef DO_QNEG16
1607:
1608: NEON_OP(qabs_s32)
1609: {
1610: if (T0 == 0x80000000) {
1611: T0 = 0x7fffffff;
1612: env->QF = 1;
1613: } else if ((int32_t)T0 < 0) {
1614: T0 = -T0;
1615: }
1616: FORCE_RET();
1617: }
1618:
1619: NEON_OP(qneg_s32)
1620: {
1621: if (T0 == 0x80000000) {
1622: T0 = 0x7fffffff;
1623: env->QF = 1;
1624: } else {
1625: T0 = -T0;
1626: }
1627: FORCE_RET();
1628: }
1629:
1630: /* Unary opperations */
1631: #define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src
1632: NEON_VOP1(abs_s8, neon_s8, 4)
1633: NEON_VOP1(abs_s16, neon_s16, 2)
1634: NEON_OP(abs_s32)
1635: {
1636: if ((int32_t)T0 < 0)
1637: T0 = -T0;
1638: FORCE_RET();
1639: }
1640: #undef NEON_FN
1641:
1642: /* Transpose. Argument order is rather strange to avoid special casing
1643: the tranlation code.
1644: On input T0 = rm, T1 = rd. On output T0 = rd, T1 = rm */
1645: NEON_OP(trn_u8)
1646: {
1647: uint32_t rd;
1648: uint32_t rm;
1649: rd = ((T0 & 0x00ff00ff) << 8) | (T1 & 0x00ff00ff);
1650: rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00);
1651: T0 = rd;
1652: T1 = rm;
1653: FORCE_RET();
1654: }
1655:
1656: NEON_OP(trn_u16)
1657: {
1658: uint32_t rd;
1659: uint32_t rm;
1660: rd = (T0 << 16) | (T1 & 0xffff);
1661: rm = (T1 >> 16) | (T0 & 0xffff0000);
1662: T0 = rd;
1663: T1 = rm;
1664: FORCE_RET();
1665: }
1666:
1667: /* Worker routines for zip and unzip. */
1668: NEON_OP(unzip_u8)
1669: {
1670: uint32_t rd;
1671: uint32_t rm;
1672: rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00)
1673: | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000);
1674: rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00)
1675: | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000);
1676: T0 = rd;
1677: T1 = rm;
1678: FORCE_RET();
1679: }
1680:
1681: NEON_OP(zip_u8)
1682: {
1683: uint32_t rd;
1684: uint32_t rm;
1685: rd = (T0 & 0xff) | ((T1 << 8) & 0xff00)
1686: | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000);
1687: rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00)
1688: | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000);
1689: T0 = rd;
1690: T1 = rm;
1691: FORCE_RET();
1692: }
1693:
1694: NEON_OP(zip_u16)
1695: {
1696: uint32_t tmp;
1697:
1698: tmp = (T0 & 0xffff) | (T1 << 16);
1699: T1 = (T1 & 0xffff0000) | (T0 >> 16);
1700: T0 = tmp;
1701: FORCE_RET();
1702: }
1703:
1704: /* Reciprocal/root estimate. */
1705: NEON_OP(recpe_u32)
1706: {
1707: T0 = helper_recpe_u32(T0);
1708: }
1709:
1710: NEON_OP(rsqrte_u32)
1711: {
1712: T0 = helper_rsqrte_u32(T0);
1713: }
1714:
1715: NEON_OP(recpe_f32)
1716: {
1717: FT0s = helper_recpe_f32(FT0s);
1718: }
1719:
1720: NEON_OP(rsqrte_f32)
1721: {
1722: FT0s = helper_rsqrte_f32(FT0s);
1723: }
1724:
1725: /* Table lookup. This accessed the register file directly. */
1726: NEON_OP(tbl)
1727: {
1728: helper_neon_tbl(PARAM1, PARAM2);
1729: }
1730:
1731: NEON_OP(dup_u8)
1732: {
1733: T0 = (T0 >> PARAM1) & 0xff;
1734: T0 |= T0 << 8;
1735: T0 |= T0 << 16;
1736: FORCE_RET();
1737: }
1738:
1739: /* Helpers for element load/store. */
1740: NEON_OP(insert_elt)
1741: {
1742: int shift = PARAM1;
1743: uint32_t mask = PARAM2;
1744: T2 = (T2 & mask) | (T0 << shift);
1745: FORCE_RET();
1746: }
1747:
1748: NEON_OP(extract_elt)
1749: {
1750: int shift = PARAM1;
1751: uint32_t mask = PARAM2;
1752: T0 = (T2 & mask) >> shift;
1753: FORCE_RET();
1754: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.