2017-11-29 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libhsail-rt / rt / arithmetic.c
blob80852d5883327da1b2cecc4be9020a89242c02c0
1 /* arithmetic.c -- Builtins for HSAIL arithmetic instructions for which
2 there is no feasible direct gcc GENERIC expression.
4 Copyright (C) 2015-2017 Free Software Foundation, Inc.
5 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
6 for General Processor Tech.
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files
10 (the "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
16 The above copyright notice and this permission notice shall be included
17 in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <limits.h>
31 #include <math.h>
32 #include <float.h>
34 /* HSAIL defines INT_MIN % -1 to be 0 while with C it's undefined,
35 and causes an overflow exception at least with gcc and C on IA-32. */
37 int32_t
38 __hsail_rem_s32 (int32_t dividend, int32_t divisor)
40 if (dividend == INT_MIN && divisor == -1)
41 return 0;
42 else
43 return dividend % divisor;
46 int64_t
47 __hsail_rem_s64 (int64_t dividend, int64_t divisor)
49 if (dividend == INT64_MIN && divisor == -1)
50 return 0;
51 else
52 return dividend % divisor;
55 /* HSAIL has defined behavior for min and max when one of the operands is
56 NaN: in that case the other operand is returned. In C and with gcc's
57 MIN_EXPR/MAX_EXPR, the returned operand is undefined. */
59 float
60 __hsail_min_f32 (float a, float b)
62 if (isnan (a))
63 return b;
64 else if (isnan (b))
65 return a;
66 else if (a == 0.0f && b == 0.0f)
67 return signbit (a) ? a : b;
68 else if (a > b)
69 return b;
70 else
71 return a;
74 double
75 __hsail_min_f64 (double a, double b)
77 if (isnan (a))
78 return b;
79 else if (isnan (b))
80 return a;
81 else if (a > b)
82 return b;
83 else
84 return a;
87 float
88 __hsail_max_f32 (float a, float b)
90 if (isnan (a))
91 return b;
92 else if (isnan (b))
93 return a;
94 else if (a == 0.0f && b == 0.0f && signbit (a))
95 return b;
96 else if (a < b)
97 return b;
98 else
99 return a;
102 double
103 __hsail_max_f64 (double a, double b)
105 if (isnan (a))
106 return b;
107 else if (isnan (b))
108 return a;
109 else if (a == 0.0 && b == 0.0 && signbit (a))
110 return b;
111 else if (a < b)
112 return b;
113 else
114 return a;
117 uint8_t
118 __hsail_cvt_zeroi_sat_u8_f32 (float a)
120 if (isnan (a))
121 return 0;
122 if (a >= (float) UINT8_MAX)
123 return UINT8_MAX;
124 else if (a <= 0.0f)
125 return 0;
126 return (uint8_t) a;
129 int8_t
130 __hsail_cvt_zeroi_sat_s8_f32 (float a)
132 if (isnan (a))
133 return 0;
134 if (a >= (float) INT8_MAX)
135 return INT8_MAX;
136 if (a <= (float) INT8_MIN)
137 return INT8_MIN;
138 return (int8_t) a;
141 uint16_t
142 __hsail_cvt_zeroi_sat_u16_f32 (float a)
144 if (isnan (a))
145 return 0;
146 if (a >= (float) UINT16_MAX)
147 return UINT16_MAX;
148 else if (a <= 0.0f)
149 return 0;
150 return (uint16_t) a;
153 int16_t
154 __hsail_cvt_zeroi_sat_s16_f32 (float a)
156 if (isnan (a))
157 return 0;
158 if (a >= (float) INT16_MAX)
159 return INT16_MAX;
160 if (a <= (float) INT16_MIN)
161 return INT16_MIN;
162 return (int16_t) a;
165 uint32_t
166 __hsail_cvt_zeroi_sat_u32_f32 (float a)
168 if (isnan (a))
169 return 0;
170 if (a >= (float) UINT32_MAX)
171 return UINT32_MAX;
172 else if (a <= 0.0f)
173 return 0;
174 return (uint32_t) a;
177 int32_t
178 __hsail_cvt_zeroi_sat_s32_f32 (float a)
180 if (isnan (a))
181 return 0;
182 if (a >= (float) INT32_MAX)
183 return INT32_MAX;
184 if (a <= (float) INT32_MIN)
185 return INT32_MIN;
186 return (int32_t) a;
189 uint64_t
190 __hsail_cvt_zeroi_sat_u64_f32 (float a)
192 if (isnan (a))
193 return 0;
194 if (a >= (float) UINT64_MAX)
195 return UINT64_MAX;
196 else if (a <= 0.0f)
197 return 0;
198 return (uint64_t) a;
201 int64_t
202 __hsail_cvt_zeroi_sat_s64_f32 (float a)
204 if (isnan (a))
205 return 0;
206 if (a >= (float) INT64_MAX)
207 return INT64_MAX;
208 if (a <= (float) INT64_MIN)
209 return INT64_MIN;
210 return (int64_t) a;
213 uint8_t
214 __hsail_cvt_zeroi_sat_u8_f64 (double a)
216 if (isnan (a))
217 return 0;
218 if (a >= (double) UINT8_MAX)
219 return UINT8_MAX;
220 else if (a <= 0.0f)
221 return 0;
222 return (uint8_t) a;
225 int8_t
226 __hsail_cvt_zeroi_sat_s8_f64 (double a)
228 if (isnan (a))
229 return 0;
230 if (a >= (double) INT8_MAX)
231 return INT8_MAX;
232 if (a <= (double) INT8_MIN)
233 return INT8_MIN;
234 return (int8_t) a;
237 uint16_t
238 __hsail_cvt_zeroi_sat_u16_f64 (double a)
240 if (isnan (a))
241 return 0;
242 if (a >= (double) UINT16_MAX)
243 return UINT16_MAX;
244 else if (a <= 0.0f)
245 return 0;
246 return (uint16_t) a;
249 int16_t
250 __hsail_cvt_zeroi_sat_s16_f64 (double a)
252 if (isnan (a))
253 return 0;
254 if (a >= (double) INT16_MAX)
255 return INT16_MAX;
256 if (a <= (double) INT16_MIN)
257 return INT16_MIN;
258 return (int16_t) a;
261 uint32_t
262 __hsail_cvt_zeroi_sat_u32_f64 (double a)
264 if (isnan (a))
265 return 0;
266 if (a >= (double) UINT32_MAX)
267 return UINT32_MAX;
268 else if (a <= 0.0f)
269 return 0;
270 return (uint32_t) a;
273 int32_t
274 __hsail_cvt_zeroi_sat_s32_f64 (double a)
276 if (isnan (a))
277 return 0;
278 if (a >= (double) INT32_MAX)
279 return INT32_MAX;
280 if (a <= (double) INT32_MIN)
281 return INT32_MIN;
282 return (int32_t) a;
285 uint64_t
286 __hsail_cvt_zeroi_sat_u64_f64 (double a)
288 if (isnan (a))
289 return 0;
290 if (a >= (double) UINT64_MAX)
291 return UINT64_MAX;
292 else if (a <= 0.0f)
293 return 0;
294 return (uint64_t) a;
297 int64_t
298 __hsail_cvt_zeroi_sat_s64_f64 (double a)
300 if (isnan (a))
301 return 0;
302 if (a >= (double) INT64_MAX)
303 return INT64_MAX;
304 if (a <= (double) INT64_MIN)
305 return INT64_MIN;
306 return (int64_t) a;
310 /* Flush the operand to zero in case it's a denormalized number.
311 Do not cause any exceptions in case of NaNs. */
313 float
314 __hsail_ftz_f32 (float a)
316 if (isnan (a) || isinf (a) || a == 0.0f)
317 return a;
319 if (a < 0.0f)
321 if (-a < FLT_MIN)
322 return -0.0f;
324 else
326 if (a < FLT_MIN)
327 return 0.0f;
329 return a;
332 #define F16_MIN (6.10e-5)
334 /* Flush the single precision operand to zero in case it's considered
335 a denormalized number in case it was a f16. Do not cause any exceptions
336 in case of NaNs. */
338 float
339 __hsail_ftz_f32_f16 (float a)
341 if (isnan (a) || isinf (a) || a == 0.0f)
342 return a;
344 if (a < 0.0f)
346 if (-a < F16_MIN)
347 return -0.0f;
349 else
351 if (a < F16_MIN)
352 return 0.0f;
354 return a;
357 double
358 __hsail_ftz_f64 (double a)
360 if (isnan (a) || isinf (a) || a == 0.0d)
361 return a;
363 if (a < 0.0d)
365 if (-a < DBL_MIN)
366 return -0.0d;
368 else
370 if (a < DBL_MIN)
371 return 0.0d;
373 return a;
376 uint32_t
377 __hsail_borrow_u32 (uint32_t a, uint32_t b)
379 return __builtin_sub_overflow_p (a, b, a);
382 uint64_t
383 __hsail_borrow_u64 (uint64_t a, uint64_t b)
385 return __builtin_sub_overflow_p (a, b, a);
388 uint32_t
389 __hsail_carry_u32 (uint32_t a, uint32_t b)
391 return __builtin_add_overflow_p (a, b, a);
394 uint64_t
395 __hsail_carry_u64 (uint64_t a, uint64_t b)
397 return __builtin_add_overflow_p (a, b, a);
400 float
401 __hsail_fract_f32 (float a)
403 int exp;
404 if (isinf (a))
405 return signbit (a) == 0 ? 0.0f : -0.0f;
406 if (isnan (a) || a == 0.0f)
407 return a;
408 else
409 return fminf (a - floorf (a), 0x1.fffffep-1f);
412 double
413 __hsail_fract_f64 (double a)
415 int exp;
416 if (isinf (a))
417 return 0.0f * isinf (a);
418 if (isnan (a) || a == 0.0f)
419 return a;
420 else
421 return fmin (a - floor (a), 0x1.fffffffffffffp-1d);
424 uint32_t
425 __hsail_class_f32 (float a, uint32_t flags)
427 return (flags & 0x0001 && isnan (a) && !(*(uint32_t *) &a & (1ul << 22)))
428 || (flags & 0x0002 && isnan (a) && (*(uint32_t *) &a & (1ul << 22)))
429 || (flags & 0x0004 && isinf (a) && a < 0.0f)
430 || (flags & 0x0008 && isnormal (a) && signbit (a))
431 || (flags & 0x0010 && a < 0.0f && a > -FLT_MIN)
432 || (flags & 0x0020 && a == 0.0f && signbit (a))
433 || (flags & 0x0040 && a == 0.0f && !signbit (a))
434 || (flags & 0x0080 && a > 0.0f && a < FLT_MIN)
435 || (flags & 0x0100 && isnormal (a) && !signbit (a))
436 || (flags & 0x0200 && isinf (a) && a >= 0.0f);
439 uint32_t
440 __hsail_class_f64 (double a, uint32_t flags)
442 return (flags & 0x0001 && isnan (a) && !(*(uint64_t *) &a & (1ul << 51)))
443 || (flags & 0x0002 && isnan (a) && (*(uint64_t *) &a & (1ul << 51)))
444 || (flags & 0x0004 && isinf (a) && a < 0.0f)
445 || (flags & 0x0008 && isnormal (a) && signbit (a))
446 || (flags & 0x0010 && a < 0.0f && a > -FLT_MIN)
447 || (flags & 0x0020 && a == 0.0f && signbit (a))
448 || (flags & 0x0040 && a == 0.0f && !signbit (a))
449 || (flags & 0x0080 && a > 0.0f && a < FLT_MIN)
450 || (flags & 0x0100 && isnormal (a) && !signbit (a))
451 || (flags & 0x0200 && isinf (a) && a >= 0.0f);
455 /* 'class' for a f32-converted f16 which should otherwise be treated like f32
456 except for its limits. */
458 uint32_t
459 __hsail_class_f32_f16 (float a, uint32_t flags)
461 return (flags & 0x0001 && isnan (a) && !(*(uint32_t *) &a & 0x40000000))
462 || (flags & 0x0002 && isnan (a) && (*(uint32_t *) &a & 0x40000000))
463 || (flags & 0x0004 && isinf (a) && a < 0.0f)
464 || (flags & 0x0008 && a != 0.0f && !isinf (a) && !isnan (a)
465 && a <= -F16_MIN)
466 || (flags & 0x0010 && a != 0.0f && !isinf (a) && !isnan (a) && a < 0.0f
467 && a > -F16_MIN)
468 || (flags & 0x0020 && a == 0.0f && signbit (a))
469 || (flags & 0x0040 && a == 0.0f && !signbit (a))
470 || (flags & 0x0080 && a != 0.0f && !isinf (a) && !isnan (a) && a > 0.0f
471 && a < F16_MIN)
472 || (flags & 0x0100 && a != 0.0f && !isinf (a) && !isnan (a)
473 && a >= F16_MIN)
474 || (flags & 0x0200 && isinf (a) && a >= 0.0f);