1 /* arithmetic.c -- Builtins for HSAIL arithmetic instructions for which
2    there is no feasible direct gcc GENERIC expression.
3 
4    Copyright (C) 2015-2019 Free Software Foundation, Inc.
5    Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
6    for General Processor Tech.
7 
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:
15 
16    The above copyright notice and this permission notice shall be included
17    in all copies or substantial portions of the Software.
18 
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.
26 */
27 
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <limits.h>
31 #include <math.h>
32 #include <float.h>
33 
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.  */
36 
37 int32_t
__hsail_rem_s32(int32_t dividend,int32_t divisor)38 __hsail_rem_s32 (int32_t dividend, int32_t divisor)
39 {
40   if (dividend == INT_MIN && divisor == -1)
41     return 0;
42   else
43     return dividend % divisor;
44 }
45 
46 int64_t
__hsail_rem_s64(int64_t dividend,int64_t divisor)47 __hsail_rem_s64 (int64_t dividend, int64_t divisor)
48 {
49   if (dividend == INT64_MIN && divisor == -1)
50     return 0;
51   else
52     return dividend % divisor;
53 }
54 
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.  */
58 
59 float
__hsail_min_f32(float a,float b)60 __hsail_min_f32 (float a, float b)
61 {
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;
72 }
73 
74 double
__hsail_min_f64(double a,double b)75 __hsail_min_f64 (double a, double b)
76 {
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;
85 }
86 
87 float
__hsail_max_f32(float a,float b)88 __hsail_max_f32 (float a, float b)
89 {
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;
100 }
101 
102 double
__hsail_max_f64(double a,double b)103 __hsail_max_f64 (double a, double b)
104 {
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;
115 }
116 
117 uint8_t
__hsail_cvt_zeroi_sat_u8_f32(float a)118 __hsail_cvt_zeroi_sat_u8_f32 (float a)
119 {
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;
127 }
128 
129 int8_t
__hsail_cvt_zeroi_sat_s8_f32(float a)130 __hsail_cvt_zeroi_sat_s8_f32 (float a)
131 {
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;
139 }
140 
141 uint16_t
__hsail_cvt_zeroi_sat_u16_f32(float a)142 __hsail_cvt_zeroi_sat_u16_f32 (float a)
143 {
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;
151 }
152 
153 int16_t
__hsail_cvt_zeroi_sat_s16_f32(float a)154 __hsail_cvt_zeroi_sat_s16_f32 (float a)
155 {
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;
163 }
164 
165 uint32_t
__hsail_cvt_zeroi_sat_u32_f32(float a)166 __hsail_cvt_zeroi_sat_u32_f32 (float a)
167 {
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;
175 }
176 
177 int32_t
__hsail_cvt_zeroi_sat_s32_f32(float a)178 __hsail_cvt_zeroi_sat_s32_f32 (float a)
179 {
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;
187 }
188 
189 uint64_t
__hsail_cvt_zeroi_sat_u64_f32(float a)190 __hsail_cvt_zeroi_sat_u64_f32 (float a)
191 {
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;
199 }
200 
201 int64_t
__hsail_cvt_zeroi_sat_s64_f32(float a)202 __hsail_cvt_zeroi_sat_s64_f32 (float a)
203 {
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;
211 }
212 
213 uint8_t
__hsail_cvt_zeroi_sat_u8_f64(double a)214 __hsail_cvt_zeroi_sat_u8_f64 (double a)
215 {
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;
223 }
224 
225 int8_t
__hsail_cvt_zeroi_sat_s8_f64(double a)226 __hsail_cvt_zeroi_sat_s8_f64 (double a)
227 {
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;
235 }
236 
237 uint16_t
__hsail_cvt_zeroi_sat_u16_f64(double a)238 __hsail_cvt_zeroi_sat_u16_f64 (double a)
239 {
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;
247 }
248 
249 int16_t
__hsail_cvt_zeroi_sat_s16_f64(double a)250 __hsail_cvt_zeroi_sat_s16_f64 (double a)
251 {
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;
259 }
260 
261 uint32_t
__hsail_cvt_zeroi_sat_u32_f64(double a)262 __hsail_cvt_zeroi_sat_u32_f64 (double a)
263 {
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;
271 }
272 
273 int32_t
__hsail_cvt_zeroi_sat_s32_f64(double a)274 __hsail_cvt_zeroi_sat_s32_f64 (double a)
275 {
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;
283 }
284 
285 uint64_t
__hsail_cvt_zeroi_sat_u64_f64(double a)286 __hsail_cvt_zeroi_sat_u64_f64 (double a)
287 {
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;
295 }
296 
297 int64_t
__hsail_cvt_zeroi_sat_s64_f64(double a)298 __hsail_cvt_zeroi_sat_s64_f64 (double a)
299 {
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;
307 }
308 
309 
310 /* Flush the operand to zero in case it's a denormalized number.
311    Do not cause any exceptions in case of NaNs.  */
312 
313 float
__hsail_ftz_f32(float a)314 __hsail_ftz_f32 (float a)
315 {
316   if (isnan (a) || isinf (a) || a == 0.0f)
317     return a;
318 
319   if (a < 0.0f)
320     {
321       if (-a < FLT_MIN)
322 	return -0.0f;
323     }
324   else
325     {
326       if (a < FLT_MIN)
327 	return 0.0f;
328     }
329   return a;
330 }
331 
332 #define F16_MIN (6.10e-5)
333 
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.  */
337 
338 float
__hsail_ftz_f32_f16(float a)339 __hsail_ftz_f32_f16 (float a)
340 {
341   if (isnan (a) || isinf (a) || a == 0.0f)
342     return a;
343 
344   if (a < 0.0f)
345     {
346       if (-a < F16_MIN)
347 	return -0.0f;
348     }
349   else
350     {
351       if (a < F16_MIN)
352 	return 0.0f;
353     }
354   return a;
355 }
356 
357 double
__hsail_ftz_f64(double a)358 __hsail_ftz_f64 (double a)
359 {
360   if (isnan (a) || isinf (a) || a == 0.0d)
361     return a;
362 
363   if (a < 0.0d)
364     {
365       if (-a < DBL_MIN)
366 	return -0.0d;
367     }
368   else
369     {
370       if (a < DBL_MIN)
371 	return 0.0d;
372     }
373   return a;
374 }
375 
376 uint32_t
__hsail_borrow_u32(uint32_t a,uint32_t b)377 __hsail_borrow_u32 (uint32_t a, uint32_t b)
378 {
379   return __builtin_sub_overflow_p (a, b, a);
380 }
381 
382 uint64_t
__hsail_borrow_u64(uint64_t a,uint64_t b)383 __hsail_borrow_u64 (uint64_t a, uint64_t b)
384 {
385   return __builtin_sub_overflow_p (a, b, a);
386 }
387 
388 uint32_t
__hsail_carry_u32(uint32_t a,uint32_t b)389 __hsail_carry_u32 (uint32_t a, uint32_t b)
390 {
391   return __builtin_add_overflow_p (a, b, a);
392 }
393 
394 uint64_t
__hsail_carry_u64(uint64_t a,uint64_t b)395 __hsail_carry_u64 (uint64_t a, uint64_t b)
396 {
397   return __builtin_add_overflow_p (a, b, a);
398 }
399 
400 float
__hsail_fract_f32(float a)401 __hsail_fract_f32 (float a)
402 {
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);
410 }
411 
412 double
__hsail_fract_f64(double a)413 __hsail_fract_f64 (double a)
414 {
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);
422 }
423 
424 uint32_t
__hsail_class_f32(float a,uint32_t flags)425 __hsail_class_f32 (float a, uint32_t flags)
426 {
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);
437 }
438 
439 uint32_t
__hsail_class_f64(double a,uint32_t flags)440 __hsail_class_f64 (double a, uint32_t flags)
441 {
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);
452 }
453 
454 
455 /* 'class' for a f32-converted f16 which should otherwise be treated like f32
456  except for its limits.  */
457 
458 uint32_t
__hsail_class_f32_f16(float a,uint32_t flags)459 __hsail_class_f32_f16 (float a, uint32_t flags)
460 {
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);
475 }
476