1 /*
2  * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 /** \file
18  * \brief Implement floating-point folding with host arithmetic
19  *
20  *  Implements the compile-time evaluation interfaces of "fp-folding.h"
21  *  using the native host floating-point arithmetic operations and
22  *  math library.
23  */
24 
25 #include "fp-folding.h"
26 #include <assert.h>
27 #include <complex.h>
28 #include <errno.h>
29 #include <fenv.h>
30 #include <float.h>
31 #include <math.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 /*
39  *  Build-time sanity checks
40  */
41 #if __STDC_VERSION__+0 < 199901
42 # warning C99 compiler required but __STDC_VERSION__ is less than 199901
43 #endif
44 #if FLT_RADIX+0 != 2
45 # error FLT_RADIX != 2
46 #endif
47 #if FLT_MANT_DIG+0 != 24
48 # error FLT_MANT_DIG != 24
49 #endif
50 #if DBL_MANT_DIG+0 != 53
51 # error DBL_MANT_DIG != 53
52 #endif
53 #if DECIMAL_DIG < 17
54 # error DECIMAL_DIG < 17
55 #endif
56 
57 void
fold_sanity_check(void)58 fold_sanity_check(void)
59 {
60   assert(sizeof(float32_t) == 4);
61   assert(sizeof(float64_t) == 8);
62   assert(sizeof(float128_t) == 16);
63 }
64 
65 /*
66  *  C99 feature: alert the compiler that the following code cares about
67  *  the dynamic floating-point environment.
68  */
69 #pragma STDC FENV_ACCESS ON
70 
71 /*
72  *  Configure "denormal inputs are zero" and "flush denormal results to zero"
73  *  modes.
74  *
75  *  TODO: Find a more portable way to configure these settings.
76  */
77 
78 static void
configure_denormals(bool denorms_are_zeros,bool flush_to_zero)79 configure_denormals(bool denorms_are_zeros, bool flush_to_zero)
80 {
81   fenv_t fenv;
82   if (fegetenv(&fenv) != 0)
83     fprintf(stderr, "fegetenv() failed: %s\n", strerror(errno));
84 #ifdef __x86_64__
85   fenv.__mxcsr &= ~0x0040;
86   if (denorms_are_zeros)
87     fenv.__mxcsr |= 0x0040;
88   fenv.__mxcsr &= ~0x8000;
89   if (flush_to_zero)
90     fenv.__mxcsr |= 0x8000;
91 #endif
92   if (fesetenv(&fenv) != 0)
93     fprintf(stderr, "fesetenv() failed: %s\n", strerror(errno));
94 }
95 
96 /*
97  *  Comparisons.  These can't trap.
98  */
99 
100 #define COMPARE_BODY { \
101   enum fold_relation rel = FOLD_UN; \
102   fenv_t fenv; \
103   if (feholdexcept(&fenv) != 0) \
104     fprintf(stderr, "feholdexcept() failed: %s\n", strerror(errno)); \
105   configure_denormals(false, false); \
106   if (*x < *y) \
107     rel = FOLD_LT; \
108   else if (*x == *y) \
109     rel = FOLD_EQ; \
110   else if (*x > *y) \
111     rel = FOLD_GT; \
112   if (fesetenv(&fenv) != 0) \
113     fprintf(stderr, "fesetenv() failed: %s\n", strerror(errno)); \
114   return rel; \
115 }
116 
117 enum fold_relation
fold_real32_compare(const float32_t * x,const float32_t * y)118 fold_real32_compare(const float32_t *x, const float32_t *y)
119 {
120   COMPARE_BODY
121 }
122 
123 enum fold_relation
fold_real64_compare(const float64_t * x,const float64_t * y)124 fold_real64_compare(const float64_t *x, const float64_t *y)
125 {
126   COMPARE_BODY
127 }
128 
129 enum fold_relation
fold_real128_compare(const float128_t * x,const float128_t * y)130 fold_real128_compare(const float128_t *x, const float128_t *y)
131 {
132   COMPARE_BODY
133 }
134 
135 /*
136  *  Set up the floating-point environment so that exceptional conditions
137  *  are recorded but don't raise traps.
138  *
139  *  TODO: Consider setting the daz and flushz modes by the compiler to
140  *  match the expected run-time environment (-Mdaz, -Mflushz).  Those
141  *  compiler options are documented as "link-time" but maybe it would
142  *  be a good idea to respect them while folding.
143  */
144 static void
set_up_floating_point_environment(fenv_t * fenv)145 set_up_floating_point_environment(fenv_t *fenv)
146 {
147   if (feholdexcept(fenv) != 0)
148     fprintf(stderr, "feholdexcept() failed: %s\n", strerror(errno));
149   configure_denormals(false, false);
150   errno = 0;
151 }
152 
153 /*
154  *  Map floating-point exceptional conditions to a folding status code.
155  */
156 
157 static enum fold_status
interpret_exceptions(int exceptions,int errno_capture)158 interpret_exceptions(int exceptions, int errno_capture)
159 {
160   if (exceptions & FE_INVALID)
161     return FOLD_INVALID;
162   if (exceptions & (FE_DIVBYZERO | FE_OVERFLOW))
163     return FOLD_OVERFLOW;
164   if (exceptions & FE_UNDERFLOW)
165     return FOLD_UNDERFLOW;
166   if (exceptions & FE_INEXACT)
167     return FOLD_INEXACT;
168   /* ignore any non-standard extended flags */
169   if (errno_capture == EDOM)
170     return FOLD_INVALID;
171   if (errno_capture == ERANGE)
172     return FOLD_OVERFLOW; /* can't distinguish over/underflow from errno */
173   return FOLD_OK;
174 }
175 
176 /*
177  *  Common exit processing: restore the processor's floating-point
178  *  environment and translate any exceptions that may have arisen.
179  */
180 
181 static enum fold_status
check_and_restore_floating_point_environment(const fenv_t * saved_fenv)182 check_and_restore_floating_point_environment(const fenv_t *saved_fenv)
183 {
184   int errno_capture = errno;
185   int exceptions = fetestexcept(FE_ALL_EXCEPT);
186   if (fesetenv(saved_fenv) != 0)
187     fprintf(stderr, "fesetenv() failed: %s\n", strerror(errno));
188   return interpret_exceptions(exceptions, errno_capture);
189 }
190 
191 /*
192  *  Compile-time evaluation routines for a large set of operations
193  *  on all of the available host floating-point types.
194  */
195 
196 /* 32-bit */
197 
198 enum fold_status
fold_int32_from_real32(int32_t * res,const float32_t * arg)199 fold_int32_from_real32(int32_t *res, const float32_t *arg)
200 {
201   fenv_t saved_fenv;
202   set_up_floating_point_environment(&saved_fenv);
203   *res = *arg;
204   return check_and_restore_floating_point_environment(&saved_fenv);
205 }
206 
207 enum fold_status
fold_int64_from_real32(int64_t * res,const float32_t * arg)208 fold_int64_from_real32(int64_t *res, const float32_t *arg)
209 {
210   fenv_t saved_fenv;
211   set_up_floating_point_environment(&saved_fenv);
212   *res = *arg;
213   return check_and_restore_floating_point_environment(&saved_fenv);
214 }
215 
216 enum fold_status
fold_uint64_from_real32(uint64_t * res,const float32_t * arg)217 fold_uint64_from_real32(uint64_t *res, const float32_t *arg)
218 {
219   fenv_t saved_fenv;
220   set_up_floating_point_environment(&saved_fenv);
221   *res = *arg;
222   return check_and_restore_floating_point_environment(&saved_fenv);
223 }
224 
225 enum fold_status
fold_uint32_from_real32(uint32_t * res,const float32_t * arg)226 fold_uint32_from_real32(uint32_t *res, const float32_t *arg)
227 {
228   fenv_t saved_fenv;
229   set_up_floating_point_environment(&saved_fenv);
230   *res = *arg;
231   return check_and_restore_floating_point_environment(&saved_fenv);
232 }
233 
234 enum fold_status
fold_real32_from_int64(float32_t * res,const int64_t * arg)235 fold_real32_from_int64(float32_t *res, const int64_t *arg)
236 {
237   fenv_t saved_fenv;
238   set_up_floating_point_environment(&saved_fenv);
239   *res = *arg;
240   return check_and_restore_floating_point_environment(&saved_fenv);
241 }
242 
243 enum fold_status
fold_real32_from_uint64(float32_t * res,const uint64_t * arg)244 fold_real32_from_uint64(float32_t *res, const uint64_t *arg)
245 {
246   fenv_t saved_fenv;
247   set_up_floating_point_environment(&saved_fenv);
248   *res = *arg;
249   return check_and_restore_floating_point_environment(&saved_fenv);
250 }
251 
252 enum fold_status
fold_real32_from_real64(float32_t * res,const float64_t * arg)253 fold_real32_from_real64(float32_t *res, const float64_t *arg)
254 {
255   fenv_t saved_fenv;
256   set_up_floating_point_environment(&saved_fenv);
257   *res = *arg;
258   return check_and_restore_floating_point_environment(&saved_fenv);
259 }
260 
261 enum fold_status
fold_real32_from_real128(float32_t * res,const float128_t * arg)262 fold_real32_from_real128(float32_t *res, const float128_t *arg)
263 {
264   fenv_t saved_fenv;
265   set_up_floating_point_environment(&saved_fenv);
266   *res = *arg;
267   return check_and_restore_floating_point_environment(&saved_fenv);
268 }
269 
270 enum fold_status
fold_real32_negate(float32_t * res,const float32_t * arg)271 fold_real32_negate(float32_t *res, const float32_t *arg)
272 {
273   fenv_t saved_fenv;
274   set_up_floating_point_environment(&saved_fenv);
275   *res = -*arg;
276   return check_and_restore_floating_point_environment(&saved_fenv);
277 }
278 
279 enum fold_status
fold_real32_abs(float32_t * res,const float32_t * arg)280 fold_real32_abs(float32_t *res, const float32_t *arg)
281 {
282   fenv_t saved_fenv;
283   set_up_floating_point_environment(&saved_fenv);
284   *res = fabsf(*arg);
285   return check_and_restore_floating_point_environment(&saved_fenv);
286 }
287 
288 enum fold_status
fold_real32_sqrt(float32_t * res,const float32_t * arg)289 fold_real32_sqrt(float32_t *res, const float32_t *arg)
290 {
291   fenv_t saved_fenv;
292   set_up_floating_point_environment(&saved_fenv);
293   *res = sqrtf(*arg);
294   return check_and_restore_floating_point_environment(&saved_fenv);
295 }
296 
297 enum fold_status
fold_real32_add(float32_t * res,const float32_t * x,const float32_t * y)298 fold_real32_add(float32_t *res, const float32_t *x, const float32_t *y)
299 {
300   fenv_t saved_fenv;
301   set_up_floating_point_environment(&saved_fenv);
302   *res = *x+*y;
303   return check_and_restore_floating_point_environment(&saved_fenv);
304 }
305 
306 enum fold_status
fold_real32_subtract(float32_t * res,const float32_t * x,const float32_t * y)307 fold_real32_subtract(float32_t *res, const float32_t *x, const float32_t *y)
308 {
309   fenv_t saved_fenv;
310   set_up_floating_point_environment(&saved_fenv);
311   *res = *x - *y;
312   return check_and_restore_floating_point_environment(&saved_fenv);
313 }
314 
315 enum fold_status
fold_real32_multiply(float32_t * res,const float32_t * x,const float32_t * y)316 fold_real32_multiply(float32_t *res, const float32_t *x, const float32_t *y)
317 {
318   fenv_t saved_fenv;
319   set_up_floating_point_environment(&saved_fenv);
320   *res = *x * *y;
321   return check_and_restore_floating_point_environment(&saved_fenv);
322 }
323 
324 enum fold_status
fold_real32_divide(float32_t * res,const float32_t * x,const float32_t * y)325 fold_real32_divide(float32_t *res, const float32_t *x, const float32_t *y)
326 {
327   fenv_t saved_fenv;
328   set_up_floating_point_environment(&saved_fenv);
329   *res = *x / *y;
330   return check_and_restore_floating_point_environment(&saved_fenv);
331 }
332 
333 enum fold_status
fold_real32_pow(float32_t * res,const float32_t * x,const float32_t * y)334 fold_real32_pow(float32_t *res, const float32_t *x, const float32_t *y)
335 {
336   fenv_t saved_fenv;
337   set_up_floating_point_environment(&saved_fenv);
338   *res = powf(*x, *y);
339   return check_and_restore_floating_point_environment(&saved_fenv);
340 }
341 
342 enum fold_status
fold_real32_sin(float32_t * res,const float32_t * arg)343 fold_real32_sin(float32_t *res, const float32_t *arg)
344 {
345   fenv_t saved_fenv;
346   set_up_floating_point_environment(&saved_fenv);
347   *res = sinf(*arg);
348   return check_and_restore_floating_point_environment(&saved_fenv);
349 }
350 
351 enum fold_status
fold_real32_cos(float32_t * res,const float32_t * arg)352 fold_real32_cos(float32_t *res, const float32_t *arg)
353 {
354   fenv_t saved_fenv;
355   set_up_floating_point_environment(&saved_fenv);
356   *res = cosf(*arg);
357   return check_and_restore_floating_point_environment(&saved_fenv);
358 }
359 
360 enum fold_status
fold_real32_tan(float32_t * res,const float32_t * arg)361 fold_real32_tan(float32_t *res, const float32_t *arg)
362 {
363   fenv_t saved_fenv;
364   set_up_floating_point_environment(&saved_fenv);
365   *res = tanf(*arg);
366   return check_and_restore_floating_point_environment(&saved_fenv);
367 }
368 
369 enum fold_status
fold_real32_asin(float32_t * res,const float32_t * arg)370 fold_real32_asin(float32_t *res, const float32_t *arg)
371 {
372   fenv_t saved_fenv;
373   set_up_floating_point_environment(&saved_fenv);
374   *res = asinf(*arg);
375   return check_and_restore_floating_point_environment(&saved_fenv);
376 }
377 
378 enum fold_status
fold_real32_acos(float32_t * res,const float32_t * arg)379 fold_real32_acos(float32_t *res, const float32_t *arg)
380 {
381   fenv_t saved_fenv;
382   set_up_floating_point_environment(&saved_fenv);
383   *res = acosf(*arg);
384   return check_and_restore_floating_point_environment(&saved_fenv);
385 }
386 
387 enum fold_status
fold_real32_atan(float32_t * res,const float32_t * arg)388 fold_real32_atan(float32_t *res, const float32_t *arg)
389 {
390   fenv_t saved_fenv;
391   set_up_floating_point_environment(&saved_fenv);
392   *res = atanf(*arg);
393   return check_and_restore_floating_point_environment(&saved_fenv);
394 }
395 
396 enum fold_status
fold_real32_atan2(float32_t * res,const float32_t * x,const float32_t * y)397 fold_real32_atan2(float32_t *res, const float32_t *x, const float32_t *y)
398 {
399   fenv_t saved_fenv;
400   set_up_floating_point_environment(&saved_fenv);
401   *res = atan2f(*x, *y);
402   return check_and_restore_floating_point_environment(&saved_fenv);
403 }
404 
405 enum fold_status
fold_real32_exp(float32_t * res,const float32_t * arg)406 fold_real32_exp(float32_t *res, const float32_t *arg)
407 {
408   fenv_t saved_fenv;
409   set_up_floating_point_environment(&saved_fenv);
410   *res = expf(*arg);
411   return check_and_restore_floating_point_environment(&saved_fenv);
412 }
413 
414 enum fold_status
fold_real32_log(float32_t * res,const float32_t * arg)415 fold_real32_log(float32_t *res, const float32_t *arg)
416 {
417   fenv_t saved_fenv;
418   set_up_floating_point_environment(&saved_fenv);
419   *res = logf(*arg);
420   return check_and_restore_floating_point_environment(&saved_fenv);
421 }
422 
423 enum fold_status
fold_real32_log10(float32_t * res,const float32_t * arg)424 fold_real32_log10(float32_t *res, const float32_t *arg)
425 {
426   fenv_t saved_fenv;
427   set_up_floating_point_environment(&saved_fenv);
428   *res = log10f(*arg);
429   return check_and_restore_floating_point_environment(&saved_fenv);
430 }
431 
432 /* 64-bit */
433 
434 enum fold_status
fold_int32_from_real64(int32_t * res,const float64_t * arg)435 fold_int32_from_real64(int32_t *res, const float64_t *arg)
436 {
437   fenv_t saved_fenv;
438   set_up_floating_point_environment(&saved_fenv);
439   *res = *arg;
440   return check_and_restore_floating_point_environment(&saved_fenv);
441 }
442 
443 enum fold_status
fold_int64_from_real64(int64_t * res,const float64_t * arg)444 fold_int64_from_real64(int64_t *res, const float64_t *arg)
445 {
446   fenv_t saved_fenv;
447   set_up_floating_point_environment(&saved_fenv);
448   *res = *arg;
449   return check_and_restore_floating_point_environment(&saved_fenv);
450 }
451 
452 enum fold_status
fold_uint32_from_real64(uint32_t * res,const float64_t * arg)453 fold_uint32_from_real64(uint32_t *res, const float64_t *arg)
454 {
455   fenv_t saved_fenv;
456   set_up_floating_point_environment(&saved_fenv);
457   *res = *arg;
458   return check_and_restore_floating_point_environment(&saved_fenv);
459 }
460 
461 enum fold_status
fold_uint64_from_real64(uint64_t * res,const float64_t * arg)462 fold_uint64_from_real64(uint64_t *res, const float64_t *arg)
463 {
464   fenv_t saved_fenv;
465   set_up_floating_point_environment(&saved_fenv);
466   *res = *arg;
467   return check_and_restore_floating_point_environment(&saved_fenv);
468 }
469 
470 enum fold_status
fold_real64_from_int64(float64_t * res,const int64_t * arg)471 fold_real64_from_int64(float64_t *res, const int64_t *arg)
472 {
473   fenv_t saved_fenv;
474   set_up_floating_point_environment(&saved_fenv);
475   *res = *arg;
476   return check_and_restore_floating_point_environment(&saved_fenv);
477 }
478 
479 enum fold_status
fold_real64_from_uint64(float64_t * res,const uint64_t * arg)480 fold_real64_from_uint64(float64_t *res, const uint64_t *arg)
481 {
482   fenv_t saved_fenv;
483   set_up_floating_point_environment(&saved_fenv);
484   *res = *arg;
485   return check_and_restore_floating_point_environment(&saved_fenv);
486 }
487 
488 enum fold_status
fold_real64_from_real32(float64_t * res,const float32_t * arg)489 fold_real64_from_real32(float64_t *res, const float32_t *arg)
490 {
491   fenv_t saved_fenv;
492   set_up_floating_point_environment(&saved_fenv);
493   *res = *arg;
494   return check_and_restore_floating_point_environment(&saved_fenv);
495 }
496 
497 enum fold_status
fold_real64_from_real128(float64_t * res,const float128_t * arg)498 fold_real64_from_real128(float64_t *res, const float128_t *arg)
499 {
500   fenv_t saved_fenv;
501   set_up_floating_point_environment(&saved_fenv);
502   *res = *arg;
503   return check_and_restore_floating_point_environment(&saved_fenv);
504 }
505 
506 enum fold_status
fold_real64_negate(float64_t * res,const float64_t * arg)507 fold_real64_negate(float64_t *res, const float64_t *arg)
508 {
509   fenv_t saved_fenv;
510   set_up_floating_point_environment(&saved_fenv);
511   *res = -*arg;
512   return check_and_restore_floating_point_environment(&saved_fenv);
513 }
514 
515 enum fold_status
fold_real64_abs(float64_t * res,const float64_t * arg)516 fold_real64_abs(float64_t *res, const float64_t *arg)
517 {
518   fenv_t saved_fenv;
519   set_up_floating_point_environment(&saved_fenv);
520   *res = fabs(*arg);
521   return check_and_restore_floating_point_environment(&saved_fenv);
522 }
523 
524 enum fold_status
fold_real64_sqrt(float64_t * res,const float64_t * arg)525 fold_real64_sqrt(float64_t *res, const float64_t *arg)
526 {
527   fenv_t saved_fenv;
528   set_up_floating_point_environment(&saved_fenv);
529   *res = sqrt(*arg);
530   return check_and_restore_floating_point_environment(&saved_fenv);
531 }
532 
533 enum fold_status
fold_real64_add(float64_t * res,const float64_t * x,const float64_t * y)534 fold_real64_add(float64_t *res, const float64_t *x, const float64_t *y)
535 {
536   fenv_t saved_fenv;
537   set_up_floating_point_environment(&saved_fenv);
538   *res = *x + *y;
539   return check_and_restore_floating_point_environment(&saved_fenv);
540 }
541 
542 enum fold_status
fold_real64_subtract(float64_t * res,const float64_t * x,const float64_t * y)543 fold_real64_subtract(float64_t *res, const float64_t *x, const float64_t *y)
544 {
545   fenv_t saved_fenv;
546   set_up_floating_point_environment(&saved_fenv);
547   *res = *x - *y;
548   return check_and_restore_floating_point_environment(&saved_fenv);
549 }
550 
551 enum fold_status
fold_real64_multiply(float64_t * res,const float64_t * x,const float64_t * y)552 fold_real64_multiply(float64_t *res, const float64_t *x, const float64_t *y)
553 {
554   fenv_t saved_fenv;
555   set_up_floating_point_environment(&saved_fenv);
556   *res = *x * *y;
557   return check_and_restore_floating_point_environment(&saved_fenv);
558 }
559 
560 enum fold_status
fold_real64_divide(float64_t * res,const float64_t * x,const float64_t * y)561 fold_real64_divide(float64_t *res, const float64_t *x, const float64_t *y)
562 {
563   fenv_t saved_fenv;
564   set_up_floating_point_environment(&saved_fenv);
565   *res = *x / *y;
566   return check_and_restore_floating_point_environment(&saved_fenv);
567 }
568 
569 enum fold_status
fold_real64_pow(float64_t * res,const float64_t * x,const float64_t * y)570 fold_real64_pow(float64_t *res, const float64_t *x, const float64_t *y)
571 {
572   fenv_t saved_fenv;
573   set_up_floating_point_environment(&saved_fenv);
574   *res = pow(*x, *y);
575   return check_and_restore_floating_point_environment(&saved_fenv);
576 }
577 
578 enum fold_status
fold_real64_sin(float64_t * res,const float64_t * arg)579 fold_real64_sin(float64_t *res, const float64_t *arg)
580 {
581   fenv_t saved_fenv;
582   set_up_floating_point_environment(&saved_fenv);
583   *res = sin(*arg);
584   return check_and_restore_floating_point_environment(&saved_fenv);
585 }
586 
587 enum fold_status
fold_real64_cos(float64_t * res,const float64_t * arg)588 fold_real64_cos(float64_t *res, const float64_t *arg)
589 {
590   fenv_t saved_fenv;
591   set_up_floating_point_environment(&saved_fenv);
592   *res = cos(*arg);
593   return check_and_restore_floating_point_environment(&saved_fenv);
594 }
595 
596 enum fold_status
fold_real64_tan(float64_t * res,const float64_t * arg)597 fold_real64_tan(float64_t *res, const float64_t *arg)
598 {
599   fenv_t saved_fenv;
600   set_up_floating_point_environment(&saved_fenv);
601   *res = tan(*arg);
602   return check_and_restore_floating_point_environment(&saved_fenv);
603 }
604 
605 enum fold_status
fold_real64_asin(float64_t * res,const float64_t * arg)606 fold_real64_asin(float64_t *res, const float64_t *arg)
607 {
608   fenv_t saved_fenv;
609   set_up_floating_point_environment(&saved_fenv);
610   *res = asin(*arg);
611   return check_and_restore_floating_point_environment(&saved_fenv);
612 }
613 
614 enum fold_status
fold_real64_acos(float64_t * res,const float64_t * arg)615 fold_real64_acos(float64_t *res, const float64_t *arg)
616 {
617   fenv_t saved_fenv;
618   set_up_floating_point_environment(&saved_fenv);
619   *res = acos(*arg);
620   return check_and_restore_floating_point_environment(&saved_fenv);
621 }
622 
623 enum fold_status
fold_real64_atan(float64_t * res,const float64_t * arg)624 fold_real64_atan(float64_t *res, const float64_t *arg)
625 {
626   fenv_t saved_fenv;
627   set_up_floating_point_environment(&saved_fenv);
628   *res = atan(*arg);
629   return check_and_restore_floating_point_environment(&saved_fenv);
630 }
631 
632 enum fold_status
fold_real64_atan2(float64_t * res,const float64_t * x,const float64_t * y)633 fold_real64_atan2(float64_t *res, const float64_t *x, const float64_t *y)
634 {
635   fenv_t saved_fenv;
636   set_up_floating_point_environment(&saved_fenv);
637   *res = atan2(*x, *y);
638   return check_and_restore_floating_point_environment(&saved_fenv);
639 }
640 
641 enum fold_status
fold_real64_exp(float64_t * res,const float64_t * arg)642 fold_real64_exp(float64_t *res, const float64_t *arg)
643 {
644   fenv_t saved_fenv;
645   set_up_floating_point_environment(&saved_fenv);
646   *res = exp(*arg);
647   return check_and_restore_floating_point_environment(&saved_fenv);
648 }
649 
650 enum fold_status
fold_real64_log(float64_t * res,const float64_t * arg)651 fold_real64_log(float64_t *res, const float64_t *arg)
652 {
653   fenv_t saved_fenv;
654   set_up_floating_point_environment(&saved_fenv);
655   *res = log(*arg);
656   return check_and_restore_floating_point_environment(&saved_fenv);
657 }
658 
659 enum fold_status
fold_real64_log10(float64_t * res,const float64_t * arg)660 fold_real64_log10(float64_t *res, const float64_t *arg)
661 {
662   fenv_t saved_fenv;
663   set_up_floating_point_environment(&saved_fenv);
664   *res = log10(*arg);
665   return check_and_restore_floating_point_environment(&saved_fenv);
666 }
667 
668 /* 80, 64+64, or 128-bit */
669 
670 enum fold_status
fold_int32_from_real128(int32_t * res,const float128_t * arg)671 fold_int32_from_real128(int32_t *res, const float128_t *arg)
672 {
673   fenv_t saved_fenv;
674   set_up_floating_point_environment(&saved_fenv);
675   *res = *arg;
676   return check_and_restore_floating_point_environment(&saved_fenv);
677 }
678 
679 enum fold_status
fold_int64_from_real128(int64_t * res,const float128_t * arg)680 fold_int64_from_real128(int64_t *res, const float128_t *arg)
681 {
682   fenv_t saved_fenv;
683   set_up_floating_point_environment(&saved_fenv);
684   *res = *arg;
685   return check_and_restore_floating_point_environment(&saved_fenv);
686 }
687 
688 enum fold_status
fold_uint32_from_real128(uint32_t * res,const float128_t * arg)689 fold_uint32_from_real128(uint32_t *res, const float128_t *arg)
690 {
691   fenv_t saved_fenv;
692   set_up_floating_point_environment(&saved_fenv);
693   *res = *arg;
694   return check_and_restore_floating_point_environment(&saved_fenv);
695 }
696 
697 enum fold_status
fold_uint64_from_real128(uint64_t * res,const float128_t * arg)698 fold_uint64_from_real128(uint64_t *res, const float128_t *arg)
699 {
700   fenv_t saved_fenv;
701   set_up_floating_point_environment(&saved_fenv);
702   *res = *arg;
703   return check_and_restore_floating_point_environment(&saved_fenv);
704 }
705 
706 enum fold_status
fold_real128_from_int64(float128_t * res,const int64_t * arg)707 fold_real128_from_int64(float128_t *res, const int64_t *arg)
708 {
709   fenv_t saved_fenv;
710   set_up_floating_point_environment(&saved_fenv);
711   *res = *arg;
712   return check_and_restore_floating_point_environment(&saved_fenv);
713 }
714 
715 enum fold_status
fold_real128_from_uint64(float128_t * res,const uint64_t * arg)716 fold_real128_from_uint64(float128_t *res, const uint64_t *arg)
717 {
718   fenv_t saved_fenv;
719   set_up_floating_point_environment(&saved_fenv);
720   *res = *arg;
721   return check_and_restore_floating_point_environment(&saved_fenv);
722 }
723 
724 enum fold_status
fold_real128_from_real32(float128_t * res,const float32_t * arg)725 fold_real128_from_real32(float128_t *res, const float32_t *arg)
726 {
727   fenv_t saved_fenv;
728   set_up_floating_point_environment(&saved_fenv);
729   *res = *arg;
730   return check_and_restore_floating_point_environment(&saved_fenv);
731 }
732 
733 enum fold_status
fold_real128_from_real64(float128_t * res,const float64_t * arg)734 fold_real128_from_real64(float128_t *res, const float64_t *arg)
735 {
736   fenv_t saved_fenv;
737   set_up_floating_point_environment(&saved_fenv);
738   *res = *arg;
739   return check_and_restore_floating_point_environment(&saved_fenv);
740 }
741 
742 enum fold_status
fold_real128_negate(float128_t * res,const float128_t * arg)743 fold_real128_negate(float128_t *res, const float128_t *arg)
744 {
745   fenv_t saved_fenv;
746   set_up_floating_point_environment(&saved_fenv);
747   *res = -*arg;
748   return check_and_restore_floating_point_environment(&saved_fenv);
749 }
750 
751 enum fold_status
fold_real128_abs(float128_t * res,const float128_t * arg)752 fold_real128_abs(float128_t *res, const float128_t *arg)
753 {
754   fenv_t saved_fenv;
755   set_up_floating_point_environment(&saved_fenv);
756   *res = fabsl(*arg);
757   return check_and_restore_floating_point_environment(&saved_fenv);
758 }
759 
760 enum fold_status
fold_real128_sqrt(float128_t * res,const float128_t * arg)761 fold_real128_sqrt(float128_t *res, const float128_t *arg)
762 {
763   fenv_t saved_fenv;
764   set_up_floating_point_environment(&saved_fenv);
765   *res = sqrtl(*arg);
766   return check_and_restore_floating_point_environment(&saved_fenv);
767 }
768 
769 enum fold_status
fold_real128_add(float128_t * res,const float128_t * x,const float128_t * y)770 fold_real128_add(float128_t *res, const float128_t *x, const float128_t *y)
771 {
772   fenv_t saved_fenv;
773   set_up_floating_point_environment(&saved_fenv);
774   *res = *x + *y;
775   return check_and_restore_floating_point_environment(&saved_fenv);
776 }
777 
778 enum fold_status
fold_real128_subtract(float128_t * res,const float128_t * x,const float128_t * y)779 fold_real128_subtract(float128_t *res, const float128_t *x, const float128_t *y)
780 {
781   fenv_t saved_fenv;
782   set_up_floating_point_environment(&saved_fenv);
783   *res = *x - *y;
784   return check_and_restore_floating_point_environment(&saved_fenv);
785 }
786 
787 enum fold_status
fold_real128_multiply(float128_t * res,const float128_t * x,const float128_t * y)788 fold_real128_multiply(float128_t *res, const float128_t *x, const float128_t *y)
789 {
790   fenv_t saved_fenv;
791   set_up_floating_point_environment(&saved_fenv);
792   *res = *x * *y;
793   return check_and_restore_floating_point_environment(&saved_fenv);
794 }
795 
796 enum fold_status
fold_real128_divide(float128_t * res,const float128_t * x,const float128_t * y)797 fold_real128_divide(float128_t *res, const float128_t *x, const float128_t *y)
798 {
799   fenv_t saved_fenv;
800   set_up_floating_point_environment(&saved_fenv);
801   *res = *x / *y;
802   return check_and_restore_floating_point_environment(&saved_fenv);
803 }
804 
805 enum fold_status
fold_real128_pow(float128_t * res,const float128_t * x,const float128_t * y)806 fold_real128_pow(float128_t *res, const float128_t *x, const float128_t *y)
807 {
808   fenv_t saved_fenv;
809   set_up_floating_point_environment(&saved_fenv);
810   *res = powl(*x, *y);
811   return check_and_restore_floating_point_environment(&saved_fenv);
812 }
813 
814 enum fold_status
fold_real128_sin(float128_t * res,const float128_t * arg)815 fold_real128_sin(float128_t *res, const float128_t *arg)
816 {
817   fenv_t saved_fenv;
818   set_up_floating_point_environment(&saved_fenv);
819   *res = sinl(*arg);
820   return check_and_restore_floating_point_environment(&saved_fenv);
821 }
822 
823 enum fold_status
fold_real128_cos(float128_t * res,const float128_t * arg)824 fold_real128_cos(float128_t *res, const float128_t *arg)
825 {
826   fenv_t saved_fenv;
827   set_up_floating_point_environment(&saved_fenv);
828   *res = cosl(*arg);
829   return check_and_restore_floating_point_environment(&saved_fenv);
830 }
831 
832 enum fold_status
fold_real128_tan(float128_t * res,const float128_t * arg)833 fold_real128_tan(float128_t *res, const float128_t *arg)
834 {
835   fenv_t saved_fenv;
836   set_up_floating_point_environment(&saved_fenv);
837   *res = tanl(*arg);
838   return check_and_restore_floating_point_environment(&saved_fenv);
839 }
840 
841 enum fold_status
fold_real128_asin(float128_t * res,const float128_t * arg)842 fold_real128_asin(float128_t *res, const float128_t *arg)
843 {
844   fenv_t saved_fenv;
845   set_up_floating_point_environment(&saved_fenv);
846   *res = asinl(*arg);
847   return check_and_restore_floating_point_environment(&saved_fenv);
848 }
849 
850 enum fold_status
fold_real128_acos(float128_t * res,const float128_t * arg)851 fold_real128_acos(float128_t *res, const float128_t *arg)
852 {
853   fenv_t saved_fenv;
854   set_up_floating_point_environment(&saved_fenv);
855   *res = acosl(*arg);
856   return check_and_restore_floating_point_environment(&saved_fenv);
857 }
858 
859 enum fold_status
fold_real128_atan(float128_t * res,const float128_t * arg)860 fold_real128_atan(float128_t *res, const float128_t *arg)
861 {
862   fenv_t saved_fenv;
863   set_up_floating_point_environment(&saved_fenv);
864   *res = atanl(*arg);
865   return check_and_restore_floating_point_environment(&saved_fenv);
866 }
867 
868 enum fold_status
fold_real128_atan2(float128_t * res,const float128_t * x,const float128_t * y)869 fold_real128_atan2(float128_t *res, const float128_t *x, const float128_t *y)
870 {
871   fenv_t saved_fenv;
872   set_up_floating_point_environment(&saved_fenv);
873   *res = atan2l(*x, *y);
874   return check_and_restore_floating_point_environment(&saved_fenv);
875 }
876 
877 enum fold_status
fold_real128_exp(float128_t * res,const float128_t * arg)878 fold_real128_exp(float128_t *res, const float128_t *arg)
879 {
880   fenv_t saved_fenv;
881   set_up_floating_point_environment(&saved_fenv);
882   *res = expl(*arg);
883   return check_and_restore_floating_point_environment(&saved_fenv);
884 }
885 
886 enum fold_status
fold_real128_log(float128_t * res,const float128_t * arg)887 fold_real128_log(float128_t *res, const float128_t *arg)
888 {
889   fenv_t saved_fenv;
890   set_up_floating_point_environment(&saved_fenv);
891   *res = logl(*arg);
892   return check_and_restore_floating_point_environment(&saved_fenv);
893 }
894 
895 enum fold_status
fold_real128_log10(float128_t * res,const float128_t * arg)896 fold_real128_log10(float128_t *res, const float128_t *arg)
897 {
898   fenv_t saved_fenv;
899   set_up_floating_point_environment(&saved_fenv);
900   *res = log10l(*arg);
901   return check_and_restore_floating_point_environment(&saved_fenv);
902 }
903