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