xref: /qemu/target/arm/tcg/arith_helper.c (revision 538b764d3417b9295cf7f8b617eb7bc90cbc4ad6)
1*538b764dSPeter Maydell /*
2*538b764dSPeter Maydell  * ARM generic helpers for various arithmetical operations.
3*538b764dSPeter Maydell  *
4*538b764dSPeter Maydell  * This code is licensed under the GNU GPL v2 or later.
5*538b764dSPeter Maydell  *
6*538b764dSPeter Maydell  * SPDX-License-Identifier: GPL-2.0-or-later
7*538b764dSPeter Maydell  */
8*538b764dSPeter Maydell #include "qemu/osdep.h"
9*538b764dSPeter Maydell #include "cpu.h"
10*538b764dSPeter Maydell #include "exec/helper-proto.h"
11*538b764dSPeter Maydell #include "qemu/crc32c.h"
12*538b764dSPeter Maydell #include <zlib.h> /* for crc32 */
13*538b764dSPeter Maydell 
14*538b764dSPeter Maydell /*
15*538b764dSPeter Maydell  * Note that signed overflow is undefined in C.  The following routines are
16*538b764dSPeter Maydell  * careful to use unsigned types where modulo arithmetic is required.
17*538b764dSPeter Maydell  * Failure to do so _will_ break on newer gcc.
18*538b764dSPeter Maydell  */
19*538b764dSPeter Maydell 
20*538b764dSPeter Maydell /* Signed saturating arithmetic.  */
21*538b764dSPeter Maydell 
22*538b764dSPeter Maydell /* Perform 16-bit signed saturating addition.  */
23*538b764dSPeter Maydell static inline uint16_t add16_sat(uint16_t a, uint16_t b)
24*538b764dSPeter Maydell {
25*538b764dSPeter Maydell     uint16_t res;
26*538b764dSPeter Maydell 
27*538b764dSPeter Maydell     res = a + b;
28*538b764dSPeter Maydell     if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
29*538b764dSPeter Maydell         if (a & 0x8000) {
30*538b764dSPeter Maydell             res = 0x8000;
31*538b764dSPeter Maydell         } else {
32*538b764dSPeter Maydell             res = 0x7fff;
33*538b764dSPeter Maydell         }
34*538b764dSPeter Maydell     }
35*538b764dSPeter Maydell     return res;
36*538b764dSPeter Maydell }
37*538b764dSPeter Maydell 
38*538b764dSPeter Maydell /* Perform 8-bit signed saturating addition.  */
39*538b764dSPeter Maydell static inline uint8_t add8_sat(uint8_t a, uint8_t b)
40*538b764dSPeter Maydell {
41*538b764dSPeter Maydell     uint8_t res;
42*538b764dSPeter Maydell 
43*538b764dSPeter Maydell     res = a + b;
44*538b764dSPeter Maydell     if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
45*538b764dSPeter Maydell         if (a & 0x80) {
46*538b764dSPeter Maydell             res = 0x80;
47*538b764dSPeter Maydell         } else {
48*538b764dSPeter Maydell             res = 0x7f;
49*538b764dSPeter Maydell         }
50*538b764dSPeter Maydell     }
51*538b764dSPeter Maydell     return res;
52*538b764dSPeter Maydell }
53*538b764dSPeter Maydell 
54*538b764dSPeter Maydell /* Perform 16-bit signed saturating subtraction.  */
55*538b764dSPeter Maydell static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
56*538b764dSPeter Maydell {
57*538b764dSPeter Maydell     uint16_t res;
58*538b764dSPeter Maydell 
59*538b764dSPeter Maydell     res = a - b;
60*538b764dSPeter Maydell     if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
61*538b764dSPeter Maydell         if (a & 0x8000) {
62*538b764dSPeter Maydell             res = 0x8000;
63*538b764dSPeter Maydell         } else {
64*538b764dSPeter Maydell             res = 0x7fff;
65*538b764dSPeter Maydell         }
66*538b764dSPeter Maydell     }
67*538b764dSPeter Maydell     return res;
68*538b764dSPeter Maydell }
69*538b764dSPeter Maydell 
70*538b764dSPeter Maydell /* Perform 8-bit signed saturating subtraction.  */
71*538b764dSPeter Maydell static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
72*538b764dSPeter Maydell {
73*538b764dSPeter Maydell     uint8_t res;
74*538b764dSPeter Maydell 
75*538b764dSPeter Maydell     res = a - b;
76*538b764dSPeter Maydell     if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
77*538b764dSPeter Maydell         if (a & 0x80) {
78*538b764dSPeter Maydell             res = 0x80;
79*538b764dSPeter Maydell         } else {
80*538b764dSPeter Maydell             res = 0x7f;
81*538b764dSPeter Maydell         }
82*538b764dSPeter Maydell     }
83*538b764dSPeter Maydell     return res;
84*538b764dSPeter Maydell }
85*538b764dSPeter Maydell 
86*538b764dSPeter Maydell #define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
87*538b764dSPeter Maydell #define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
88*538b764dSPeter Maydell #define ADD8(a, b, n)  RESULT(add8_sat(a, b), n, 8);
89*538b764dSPeter Maydell #define SUB8(a, b, n)  RESULT(sub8_sat(a, b), n, 8);
90*538b764dSPeter Maydell #define PFX q
91*538b764dSPeter Maydell 
92*538b764dSPeter Maydell #include "op_addsub.c.inc"
93*538b764dSPeter Maydell 
94*538b764dSPeter Maydell /* Unsigned saturating arithmetic.  */
95*538b764dSPeter Maydell static inline uint16_t add16_usat(uint16_t a, uint16_t b)
96*538b764dSPeter Maydell {
97*538b764dSPeter Maydell     uint16_t res;
98*538b764dSPeter Maydell     res = a + b;
99*538b764dSPeter Maydell     if (res < a) {
100*538b764dSPeter Maydell         res = 0xffff;
101*538b764dSPeter Maydell     }
102*538b764dSPeter Maydell     return res;
103*538b764dSPeter Maydell }
104*538b764dSPeter Maydell 
105*538b764dSPeter Maydell static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
106*538b764dSPeter Maydell {
107*538b764dSPeter Maydell     if (a > b) {
108*538b764dSPeter Maydell         return a - b;
109*538b764dSPeter Maydell     } else {
110*538b764dSPeter Maydell         return 0;
111*538b764dSPeter Maydell     }
112*538b764dSPeter Maydell }
113*538b764dSPeter Maydell 
114*538b764dSPeter Maydell static inline uint8_t add8_usat(uint8_t a, uint8_t b)
115*538b764dSPeter Maydell {
116*538b764dSPeter Maydell     uint8_t res;
117*538b764dSPeter Maydell     res = a + b;
118*538b764dSPeter Maydell     if (res < a) {
119*538b764dSPeter Maydell         res = 0xff;
120*538b764dSPeter Maydell     }
121*538b764dSPeter Maydell     return res;
122*538b764dSPeter Maydell }
123*538b764dSPeter Maydell 
124*538b764dSPeter Maydell static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
125*538b764dSPeter Maydell {
126*538b764dSPeter Maydell     if (a > b) {
127*538b764dSPeter Maydell         return a - b;
128*538b764dSPeter Maydell     } else {
129*538b764dSPeter Maydell         return 0;
130*538b764dSPeter Maydell     }
131*538b764dSPeter Maydell }
132*538b764dSPeter Maydell 
133*538b764dSPeter Maydell #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
134*538b764dSPeter Maydell #define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
135*538b764dSPeter Maydell #define ADD8(a, b, n)  RESULT(add8_usat(a, b), n, 8);
136*538b764dSPeter Maydell #define SUB8(a, b, n)  RESULT(sub8_usat(a, b), n, 8);
137*538b764dSPeter Maydell #define PFX uq
138*538b764dSPeter Maydell 
139*538b764dSPeter Maydell #include "op_addsub.c.inc"
140*538b764dSPeter Maydell 
141*538b764dSPeter Maydell /* Signed modulo arithmetic.  */
142*538b764dSPeter Maydell #define SARITH16(a, b, n, op) do { \
143*538b764dSPeter Maydell     int32_t sum; \
144*538b764dSPeter Maydell     sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
145*538b764dSPeter Maydell     RESULT(sum, n, 16); \
146*538b764dSPeter Maydell     if (sum >= 0) \
147*538b764dSPeter Maydell         ge |= 3 << (n * 2); \
148*538b764dSPeter Maydell     } while (0)
149*538b764dSPeter Maydell 
150*538b764dSPeter Maydell #define SARITH8(a, b, n, op) do { \
151*538b764dSPeter Maydell     int32_t sum; \
152*538b764dSPeter Maydell     sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
153*538b764dSPeter Maydell     RESULT(sum, n, 8); \
154*538b764dSPeter Maydell     if (sum >= 0) \
155*538b764dSPeter Maydell         ge |= 1 << n; \
156*538b764dSPeter Maydell     } while (0)
157*538b764dSPeter Maydell 
158*538b764dSPeter Maydell 
159*538b764dSPeter Maydell #define ADD16(a, b, n) SARITH16(a, b, n, +)
160*538b764dSPeter Maydell #define SUB16(a, b, n) SARITH16(a, b, n, -)
161*538b764dSPeter Maydell #define ADD8(a, b, n)  SARITH8(a, b, n, +)
162*538b764dSPeter Maydell #define SUB8(a, b, n)  SARITH8(a, b, n, -)
163*538b764dSPeter Maydell #define PFX s
164*538b764dSPeter Maydell #define ARITH_GE
165*538b764dSPeter Maydell 
166*538b764dSPeter Maydell #include "op_addsub.c.inc"
167*538b764dSPeter Maydell 
168*538b764dSPeter Maydell /* Unsigned modulo arithmetic.  */
169*538b764dSPeter Maydell #define ADD16(a, b, n) do { \
170*538b764dSPeter Maydell     uint32_t sum; \
171*538b764dSPeter Maydell     sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
172*538b764dSPeter Maydell     RESULT(sum, n, 16); \
173*538b764dSPeter Maydell     if ((sum >> 16) == 1) \
174*538b764dSPeter Maydell         ge |= 3 << (n * 2); \
175*538b764dSPeter Maydell     } while (0)
176*538b764dSPeter Maydell 
177*538b764dSPeter Maydell #define ADD8(a, b, n) do { \
178*538b764dSPeter Maydell     uint32_t sum; \
179*538b764dSPeter Maydell     sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
180*538b764dSPeter Maydell     RESULT(sum, n, 8); \
181*538b764dSPeter Maydell     if ((sum >> 8) == 1) \
182*538b764dSPeter Maydell         ge |= 1 << n; \
183*538b764dSPeter Maydell     } while (0)
184*538b764dSPeter Maydell 
185*538b764dSPeter Maydell #define SUB16(a, b, n) do { \
186*538b764dSPeter Maydell     uint32_t sum; \
187*538b764dSPeter Maydell     sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
188*538b764dSPeter Maydell     RESULT(sum, n, 16); \
189*538b764dSPeter Maydell     if ((sum >> 16) == 0) \
190*538b764dSPeter Maydell         ge |= 3 << (n * 2); \
191*538b764dSPeter Maydell     } while (0)
192*538b764dSPeter Maydell 
193*538b764dSPeter Maydell #define SUB8(a, b, n) do { \
194*538b764dSPeter Maydell     uint32_t sum; \
195*538b764dSPeter Maydell     sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
196*538b764dSPeter Maydell     RESULT(sum, n, 8); \
197*538b764dSPeter Maydell     if ((sum >> 8) == 0) \
198*538b764dSPeter Maydell         ge |= 1 << n; \
199*538b764dSPeter Maydell     } while (0)
200*538b764dSPeter Maydell 
201*538b764dSPeter Maydell #define PFX u
202*538b764dSPeter Maydell #define ARITH_GE
203*538b764dSPeter Maydell 
204*538b764dSPeter Maydell #include "op_addsub.c.inc"
205*538b764dSPeter Maydell 
206*538b764dSPeter Maydell /* Halved signed arithmetic.  */
207*538b764dSPeter Maydell #define ADD16(a, b, n) \
208*538b764dSPeter Maydell   RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
209*538b764dSPeter Maydell #define SUB16(a, b, n) \
210*538b764dSPeter Maydell   RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
211*538b764dSPeter Maydell #define ADD8(a, b, n) \
212*538b764dSPeter Maydell   RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
213*538b764dSPeter Maydell #define SUB8(a, b, n) \
214*538b764dSPeter Maydell   RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
215*538b764dSPeter Maydell #define PFX sh
216*538b764dSPeter Maydell 
217*538b764dSPeter Maydell #include "op_addsub.c.inc"
218*538b764dSPeter Maydell 
219*538b764dSPeter Maydell /* Halved unsigned arithmetic.  */
220*538b764dSPeter Maydell #define ADD16(a, b, n) \
221*538b764dSPeter Maydell   RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
222*538b764dSPeter Maydell #define SUB16(a, b, n) \
223*538b764dSPeter Maydell   RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
224*538b764dSPeter Maydell #define ADD8(a, b, n) \
225*538b764dSPeter Maydell   RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
226*538b764dSPeter Maydell #define SUB8(a, b, n) \
227*538b764dSPeter Maydell   RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
228*538b764dSPeter Maydell #define PFX uh
229*538b764dSPeter Maydell 
230*538b764dSPeter Maydell #include "op_addsub.c.inc"
231*538b764dSPeter Maydell 
232*538b764dSPeter Maydell static inline uint8_t do_usad(uint8_t a, uint8_t b)
233*538b764dSPeter Maydell {
234*538b764dSPeter Maydell     if (a > b) {
235*538b764dSPeter Maydell         return a - b;
236*538b764dSPeter Maydell     } else {
237*538b764dSPeter Maydell         return b - a;
238*538b764dSPeter Maydell     }
239*538b764dSPeter Maydell }
240*538b764dSPeter Maydell 
241*538b764dSPeter Maydell /* Unsigned sum of absolute byte differences.  */
242*538b764dSPeter Maydell uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
243*538b764dSPeter Maydell {
244*538b764dSPeter Maydell     uint32_t sum;
245*538b764dSPeter Maydell     sum = do_usad(a, b);
246*538b764dSPeter Maydell     sum += do_usad(a >> 8, b >> 8);
247*538b764dSPeter Maydell     sum += do_usad(a >> 16, b >> 16);
248*538b764dSPeter Maydell     sum += do_usad(a >> 24, b >> 24);
249*538b764dSPeter Maydell     return sum;
250*538b764dSPeter Maydell }
251*538b764dSPeter Maydell 
252*538b764dSPeter Maydell /* For ARMv6 SEL instruction.  */
253*538b764dSPeter Maydell uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
254*538b764dSPeter Maydell {
255*538b764dSPeter Maydell     uint32_t mask;
256*538b764dSPeter Maydell 
257*538b764dSPeter Maydell     mask = 0;
258*538b764dSPeter Maydell     if (flags & 1) {
259*538b764dSPeter Maydell         mask |= 0xff;
260*538b764dSPeter Maydell     }
261*538b764dSPeter Maydell     if (flags & 2) {
262*538b764dSPeter Maydell         mask |= 0xff00;
263*538b764dSPeter Maydell     }
264*538b764dSPeter Maydell     if (flags & 4) {
265*538b764dSPeter Maydell         mask |= 0xff0000;
266*538b764dSPeter Maydell     }
267*538b764dSPeter Maydell     if (flags & 8) {
268*538b764dSPeter Maydell         mask |= 0xff000000;
269*538b764dSPeter Maydell     }
270*538b764dSPeter Maydell     return (a & mask) | (b & ~mask);
271*538b764dSPeter Maydell }
272*538b764dSPeter Maydell 
273*538b764dSPeter Maydell /*
274*538b764dSPeter Maydell  * CRC helpers.
275*538b764dSPeter Maydell  * The upper bytes of val (above the number specified by 'bytes') must have
276*538b764dSPeter Maydell  * been zeroed out by the caller.
277*538b764dSPeter Maydell  */
278*538b764dSPeter Maydell uint32_t HELPER(crc32)(uint32_t acc, uint32_t val, uint32_t bytes)
279*538b764dSPeter Maydell {
280*538b764dSPeter Maydell     uint8_t buf[4];
281*538b764dSPeter Maydell 
282*538b764dSPeter Maydell     stl_le_p(buf, val);
283*538b764dSPeter Maydell 
284*538b764dSPeter Maydell     /* zlib crc32 converts the accumulator and output to one's complement.  */
285*538b764dSPeter Maydell     return crc32(acc ^ 0xffffffff, buf, bytes) ^ 0xffffffff;
286*538b764dSPeter Maydell }
287*538b764dSPeter Maydell 
288*538b764dSPeter Maydell uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
289*538b764dSPeter Maydell {
290*538b764dSPeter Maydell     uint8_t buf[4];
291*538b764dSPeter Maydell 
292*538b764dSPeter Maydell     stl_le_p(buf, val);
293*538b764dSPeter Maydell 
294*538b764dSPeter Maydell     /* Linux crc32c converts the output to one's complement.  */
295*538b764dSPeter Maydell     return crc32c(acc, buf, bytes) ^ 0xffffffff;
296*538b764dSPeter Maydell }
297