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