1 //===-- runtime/numeric.cpp -----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Runtime/numeric.h"
10 #include "terminator.h"
11 #include "flang/Runtime/float128.h"
12 #include <cfloat>
13 #include <climits>
14 #include <cmath>
15 #include <limits>
16 
17 namespace Fortran::runtime {
18 
19 template <typename RES>
20 inline RES getIntArgValue(const char *source, int line, void *arg, int kind,
21     std::int64_t defaultValue, int resKind) {
22   RES res;
23   if (!arg) {
24     res = static_cast<RES>(defaultValue);
25   } else if (kind == 1) {
26     res = static_cast<RES>(
27         *static_cast<CppTypeFor<TypeCategory::Integer, 1> *>(arg));
28   } else if (kind == 2) {
29     res = static_cast<RES>(
30         *static_cast<CppTypeFor<TypeCategory::Integer, 2> *>(arg));
31   } else if (kind == 4) {
32     res = static_cast<RES>(
33         *static_cast<CppTypeFor<TypeCategory::Integer, 4> *>(arg));
34   } else if (kind == 8) {
35     res = static_cast<RES>(
36         *static_cast<CppTypeFor<TypeCategory::Integer, 8> *>(arg));
37 #ifdef __SIZEOF_INT128__
38   } else if (kind == 16) {
39     if (resKind != 16) {
40       Terminator{source, line}.Crash("Unexpected integer kind in runtime");
41     }
42     res = static_cast<RES>(
43         *static_cast<CppTypeFor<TypeCategory::Integer, 16> *>(arg));
44 #endif
45   } else {
46     Terminator{source, line}.Crash("Unexpected integer kind in runtime");
47   }
48   return res;
49 }
50 
51 // NINT (16.9.141)
52 template <typename RESULT, typename ARG> inline RESULT Nint(ARG x) {
53   if (x >= 0) {
54     return std::trunc(x + ARG{0.5});
55   } else {
56     return std::trunc(x - ARG{0.5});
57   }
58 }
59 
60 // CEILING & FLOOR (16.9.43, .79)
61 template <typename RESULT, typename ARG> inline RESULT Ceiling(ARG x) {
62   return std::ceil(x);
63 }
64 template <typename RESULT, typename ARG> inline RESULT Floor(ARG x) {
65   return std::floor(x);
66 }
67 
68 // EXPONENT (16.9.75)
69 template <typename RESULT, typename ARG> inline RESULT Exponent(ARG x) {
70   if (std::isinf(x) || std::isnan(x)) {
71     return std::numeric_limits<RESULT>::max(); // +/-Inf, NaN -> HUGE(0)
72   } else if (x == 0) {
73     return 0; // 0 -> 0
74   } else {
75     return std::ilogb(x) + 1;
76   }
77 }
78 
79 // FRACTION (16.9.80)
80 template <typename T> inline T Fraction(T x) {
81   if (std::isnan(x)) {
82     return x; // NaN -> same NaN
83   } else if (std::isinf(x)) {
84     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
85   } else if (x == 0) {
86     return 0; // 0 -> 0
87   } else {
88     int ignoredExp;
89     return std::frexp(x, &ignoredExp);
90   }
91 }
92 
93 // MOD & MODULO (16.9.135, .136)
94 template <bool IS_MODULO, typename T>
95 inline T IntMod(T x, T p, const char *sourceFile, int sourceLine) {
96   if (p == 0) {
97     Terminator{sourceFile, sourceLine}.Crash(
98         IS_MODULO ? "MODULO with P==0" : "MOD with P==0");
99   }
100   auto mod{x - (x / p) * p};
101   if (IS_MODULO && (x > 0) != (p > 0)) {
102     mod += p;
103   }
104   return mod;
105 }
106 template <bool IS_MODULO, typename T>
107 inline T RealMod(T a, T p, const char *sourceFile, int sourceLine) {
108   if (p == 0) {
109     Terminator{sourceFile, sourceLine}.Crash(
110         IS_MODULO ? "MODULO with P==0" : "MOD with P==0");
111   }
112   T quotient{a / p};
113   if (std::isinf(quotient) && std::isfinite(a) && std::isfinite(p)) {
114     // a/p overflowed -- so it must be an integer, and the result
115     // must be a zero of the same sign as one of the operands.
116     return std::copysign(T{}, IS_MODULO ? p : a);
117   }
118   T toInt{IS_MODULO ? std::floor(quotient) : std::trunc(quotient)};
119   return a - toInt * p;
120 }
121 
122 // RRSPACING (16.9.164)
123 template <int PREC, typename T> inline T RRSpacing(T x) {
124   if (std::isnan(x)) {
125     return x; // NaN -> same NaN
126   } else if (std::isinf(x)) {
127     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
128   } else if (x == 0) {
129     return 0; // 0 -> 0
130   } else {
131     return std::ldexp(std::abs(x), PREC - (std::ilogb(x) + 1));
132   }
133 }
134 
135 // SCALE (16.9.166)
136 template <typename T> inline T Scale(T x, std::int64_t p) {
137   auto ip{static_cast<int>(p)};
138   if (ip != p) {
139     ip = p < 0 ? std::numeric_limits<int>::min()
140                : std::numeric_limits<int>::max();
141   }
142   return std::ldexp(x, p); // x*2**p
143 }
144 
145 // SELECTED_REAL_KIND (16.9.170)
146 template <typename P, typename R, typename D>
147 inline CppTypeFor<TypeCategory::Integer, 4> SelectedRealKind(P p, R r, D d) {
148   if (d != 2) {
149     return -5;
150   }
151 
152   int error{0};
153   int kind{0};
154   if (p <= 3) {
155     kind = 2;
156   } else if (p <= 6) {
157     kind = 4;
158   } else if (p <= 15) {
159     kind = 8;
160 #if LDBL_MANT_DIG == 64
161   } else if (p <= 18) {
162     kind = 10;
163   } else if (p <= 33) {
164     kind = 16;
165 #elif LDBL_MANT_DIG == 113
166   } else if (p <= 33) {
167     kind = 16;
168 #endif
169   } else {
170     error -= 1;
171   }
172 
173   if (r <= 4) {
174     kind = kind < 2 ? 2 : kind;
175   } else if (r <= 37) {
176     kind = kind < 3 ? (p == 3 ? 4 : 3) : kind;
177   } else if (r <= 307) {
178     kind = kind < 8 ? 8 : kind;
179 #if LDBL_MANT_DIG == 64
180   } else if (r <= 4931) {
181     kind = kind < 10 ? 10 : kind;
182 #elif LDBL_MANT_DIG == 113
183   } else if (r <= 4931) {
184     kind = kind < 16 ? 16 : kind;
185 #endif
186   } else {
187     error -= 2;
188   }
189 
190   return error ? error : kind;
191 }
192 
193 // SET_EXPONENT (16.9.171)
194 template <typename T> inline T SetExponent(T x, std::int64_t p) {
195   if (std::isnan(x)) {
196     return x; // NaN -> same NaN
197   } else if (std::isinf(x)) {
198     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
199   } else if (x == 0) {
200     return x; // return negative zero if x is negative zero
201   } else {
202     int expo{std::ilogb(x) + 1};
203     auto ip{static_cast<int>(p - expo)};
204     if (ip != p - expo) {
205       ip = p < 0 ? std::numeric_limits<int>::min()
206                  : std::numeric_limits<int>::max();
207     }
208     return std::ldexp(x, ip); // x*2**(p-e)
209   }
210 }
211 
212 // SPACING (16.9.180)
213 template <int PREC, typename T> inline T Spacing(T x) {
214   if (std::isnan(x)) {
215     return x; // NaN -> same NaN
216   } else if (std::isinf(x)) {
217     return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN
218   } else if (x == 0) {
219     // The standard-mandated behavior seems broken, since TINY() can't be
220     // subnormal.
221     return std::numeric_limits<T>::min(); // 0 -> TINY(x)
222   } else {
223     return std::ldexp(
224         static_cast<T>(1.0), std::ilogb(x) + 1 - PREC); // 2**(e-p)
225   }
226 }
227 
228 // NEAREST (16.9.139)
229 template <int PREC, typename T> inline T Nearest(T x, bool positive) {
230   auto spacing{Spacing<PREC>(x)};
231   if (x == 0) {
232     auto least{std::numeric_limits<T>::denorm_min()};
233     return positive ? least : -least;
234   } else {
235     return positive ? x + spacing : x - spacing;
236   }
237 }
238 
239 extern "C" {
240 
241 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling4_1)(
242     CppTypeFor<TypeCategory::Real, 4> x) {
243   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
244 }
245 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling4_2)(
246     CppTypeFor<TypeCategory::Real, 4> x) {
247   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
248 }
249 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling4_4)(
250     CppTypeFor<TypeCategory::Real, 4> x) {
251   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
252 }
253 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling4_8)(
254     CppTypeFor<TypeCategory::Real, 4> x) {
255   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
256 }
257 #ifdef __SIZEOF_INT128__
258 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling4_16)(
259     CppTypeFor<TypeCategory::Real, 4> x) {
260   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
261 }
262 #endif
263 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling8_1)(
264     CppTypeFor<TypeCategory::Real, 8> x) {
265   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
266 }
267 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling8_2)(
268     CppTypeFor<TypeCategory::Real, 8> x) {
269   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
270 }
271 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling8_4)(
272     CppTypeFor<TypeCategory::Real, 8> x) {
273   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
274 }
275 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling8_8)(
276     CppTypeFor<TypeCategory::Real, 8> x) {
277   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
278 }
279 #ifdef __SIZEOF_INT128__
280 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling8_16)(
281     CppTypeFor<TypeCategory::Real, 8> x) {
282   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
283 }
284 #endif
285 #if LDBL_MANT_DIG == 64
286 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling10_1)(
287     CppTypeFor<TypeCategory::Real, 10> x) {
288   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
289 }
290 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling10_2)(
291     CppTypeFor<TypeCategory::Real, 10> x) {
292   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
293 }
294 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling10_4)(
295     CppTypeFor<TypeCategory::Real, 10> x) {
296   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
297 }
298 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling10_8)(
299     CppTypeFor<TypeCategory::Real, 10> x) {
300   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
301 }
302 #ifdef __SIZEOF_INT128__
303 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling10_16)(
304     CppTypeFor<TypeCategory::Real, 10> x) {
305   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
306 }
307 #endif
308 #elif LDBL_MANT_DIG == 113
309 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling16_1)(
310     CppTypeFor<TypeCategory::Real, 16> x) {
311   return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x);
312 }
313 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling16_2)(
314     CppTypeFor<TypeCategory::Real, 16> x) {
315   return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x);
316 }
317 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling16_4)(
318     CppTypeFor<TypeCategory::Real, 16> x) {
319   return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x);
320 }
321 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling16_8)(
322     CppTypeFor<TypeCategory::Real, 16> x) {
323   return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x);
324 }
325 #ifdef __SIZEOF_INT128__
326 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling16_16)(
327     CppTypeFor<TypeCategory::Real, 16> x) {
328   return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x);
329 }
330 #endif
331 #endif
332 
333 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent4_4)(
334     CppTypeFor<TypeCategory::Real, 4> x) {
335   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
336 }
337 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent4_8)(
338     CppTypeFor<TypeCategory::Real, 4> x) {
339   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
340 }
341 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent8_4)(
342     CppTypeFor<TypeCategory::Real, 8> x) {
343   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
344 }
345 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent8_8)(
346     CppTypeFor<TypeCategory::Real, 8> x) {
347   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
348 }
349 #if LDBL_MANT_DIG == 64
350 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent10_4)(
351     CppTypeFor<TypeCategory::Real, 10> x) {
352   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
353 }
354 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent10_8)(
355     CppTypeFor<TypeCategory::Real, 10> x) {
356   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
357 }
358 #elif LDBL_MANT_DIG == 113
359 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent16_4)(
360     CppTypeFor<TypeCategory::Real, 16> x) {
361   return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x);
362 }
363 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent16_8)(
364     CppTypeFor<TypeCategory::Real, 16> x) {
365   return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x);
366 }
367 #endif
368 
369 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor4_1)(
370     CppTypeFor<TypeCategory::Real, 4> x) {
371   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
372 }
373 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor4_2)(
374     CppTypeFor<TypeCategory::Real, 4> x) {
375   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
376 }
377 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor4_4)(
378     CppTypeFor<TypeCategory::Real, 4> x) {
379   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
380 }
381 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor4_8)(
382     CppTypeFor<TypeCategory::Real, 4> x) {
383   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
384 }
385 #ifdef __SIZEOF_INT128__
386 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor4_16)(
387     CppTypeFor<TypeCategory::Real, 4> x) {
388   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
389 }
390 #endif
391 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor8_1)(
392     CppTypeFor<TypeCategory::Real, 8> x) {
393   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
394 }
395 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor8_2)(
396     CppTypeFor<TypeCategory::Real, 8> x) {
397   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
398 }
399 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor8_4)(
400     CppTypeFor<TypeCategory::Real, 8> x) {
401   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
402 }
403 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor8_8)(
404     CppTypeFor<TypeCategory::Real, 8> x) {
405   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
406 }
407 #ifdef __SIZEOF_INT128__
408 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor8_16)(
409     CppTypeFor<TypeCategory::Real, 8> x) {
410   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
411 }
412 #endif
413 #if LDBL_MANT_DIG == 64
414 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor10_1)(
415     CppTypeFor<TypeCategory::Real, 10> x) {
416   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
417 }
418 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor10_2)(
419     CppTypeFor<TypeCategory::Real, 10> x) {
420   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
421 }
422 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor10_4)(
423     CppTypeFor<TypeCategory::Real, 10> x) {
424   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
425 }
426 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor10_8)(
427     CppTypeFor<TypeCategory::Real, 10> x) {
428   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
429 }
430 #ifdef __SIZEOF_INT128__
431 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor10_16)(
432     CppTypeFor<TypeCategory::Real, 10> x) {
433   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
434 }
435 #endif
436 #elif LDBL_MANT_DIG == 113
437 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor16_1)(
438     CppTypeFor<TypeCategory::Real, 16> x) {
439   return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x);
440 }
441 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor16_2)(
442     CppTypeFor<TypeCategory::Real, 16> x) {
443   return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x);
444 }
445 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor16_4)(
446     CppTypeFor<TypeCategory::Real, 16> x) {
447   return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x);
448 }
449 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor16_8)(
450     CppTypeFor<TypeCategory::Real, 16> x) {
451   return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x);
452 }
453 #ifdef __SIZEOF_INT128__
454 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor16_16)(
455     CppTypeFor<TypeCategory::Real, 16> x) {
456   return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x);
457 }
458 #endif
459 #endif
460 
461 CppTypeFor<TypeCategory::Real, 4> RTNAME(Fraction4)(
462     CppTypeFor<TypeCategory::Real, 4> x) {
463   return Fraction(x);
464 }
465 CppTypeFor<TypeCategory::Real, 8> RTNAME(Fraction8)(
466     CppTypeFor<TypeCategory::Real, 8> x) {
467   return Fraction(x);
468 }
469 #if LDBL_MANT_DIG == 64
470 CppTypeFor<TypeCategory::Real, 10> RTNAME(Fraction10)(
471     CppTypeFor<TypeCategory::Real, 10> x) {
472   return Fraction(x);
473 }
474 #elif LDBL_MANT_DIG == 113
475 CppTypeFor<TypeCategory::Real, 16> RTNAME(Fraction16)(
476     CppTypeFor<TypeCategory::Real, 16> x) {
477   return Fraction(x);
478 }
479 #endif
480 
481 bool RTNAME(IsFinite4)(CppTypeFor<TypeCategory::Real, 4> x) {
482   return std::isfinite(x);
483 }
484 bool RTNAME(IsFinite8)(CppTypeFor<TypeCategory::Real, 8> x) {
485   return std::isfinite(x);
486 }
487 #if LDBL_MANT_DIG == 64
488 bool RTNAME(IsFinite10)(CppTypeFor<TypeCategory::Real, 10> x) {
489   return std::isfinite(x);
490 }
491 #elif LDBL_MANT_DIG == 113
492 bool RTNAME(IsFinite16)(CppTypeFor<TypeCategory::Real, 16> x) {
493   return std::isfinite(x);
494 }
495 #endif
496 
497 bool RTNAME(IsNaN4)(CppTypeFor<TypeCategory::Real, 4> x) {
498   return std::isnan(x);
499 }
500 bool RTNAME(IsNaN8)(CppTypeFor<TypeCategory::Real, 8> x) {
501   return std::isnan(x);
502 }
503 #if LDBL_MANT_DIG == 64
504 bool RTNAME(IsNaN10)(CppTypeFor<TypeCategory::Real, 10> x) {
505   return std::isnan(x);
506 }
507 #elif LDBL_MANT_DIG == 113
508 bool RTNAME(IsNaN16)(CppTypeFor<TypeCategory::Real, 16> x) {
509   return std::isnan(x);
510 }
511 #endif
512 
513 CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModInteger1)(
514     CppTypeFor<TypeCategory::Integer, 1> x,
515     CppTypeFor<TypeCategory::Integer, 1> p, const char *sourceFile,
516     int sourceLine) {
517   return IntMod<false>(x, p, sourceFile, sourceLine);
518 }
519 CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModInteger2)(
520     CppTypeFor<TypeCategory::Integer, 2> x,
521     CppTypeFor<TypeCategory::Integer, 2> p, const char *sourceFile,
522     int sourceLine) {
523   return IntMod<false>(x, p, sourceFile, sourceLine);
524 }
525 CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModInteger4)(
526     CppTypeFor<TypeCategory::Integer, 4> x,
527     CppTypeFor<TypeCategory::Integer, 4> p, const char *sourceFile,
528     int sourceLine) {
529   return IntMod<false>(x, p, sourceFile, sourceLine);
530 }
531 CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModInteger8)(
532     CppTypeFor<TypeCategory::Integer, 8> x,
533     CppTypeFor<TypeCategory::Integer, 8> p, const char *sourceFile,
534     int sourceLine) {
535   return IntMod<false>(x, p, sourceFile, sourceLine);
536 }
537 #ifdef __SIZEOF_INT128__
538 CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModInteger16)(
539     CppTypeFor<TypeCategory::Integer, 16> x,
540     CppTypeFor<TypeCategory::Integer, 16> p, const char *sourceFile,
541     int sourceLine) {
542   return IntMod<false>(x, p, sourceFile, sourceLine);
543 }
544 #endif
545 CppTypeFor<TypeCategory::Real, 4> RTNAME(ModReal4)(
546     CppTypeFor<TypeCategory::Real, 4> x, CppTypeFor<TypeCategory::Real, 4> p,
547     const char *sourceFile, int sourceLine) {
548   return RealMod<false>(x, p, sourceFile, sourceLine);
549 }
550 CppTypeFor<TypeCategory::Real, 8> RTNAME(ModReal8)(
551     CppTypeFor<TypeCategory::Real, 8> x, CppTypeFor<TypeCategory::Real, 8> p,
552     const char *sourceFile, int sourceLine) {
553   return RealMod<false>(x, p, sourceFile, sourceLine);
554 }
555 #if LDBL_MANT_DIG == 64
556 CppTypeFor<TypeCategory::Real, 10> RTNAME(ModReal10)(
557     CppTypeFor<TypeCategory::Real, 10> x, CppTypeFor<TypeCategory::Real, 10> p,
558     const char *sourceFile, int sourceLine) {
559   return RealMod<false>(x, p, sourceFile, sourceLine);
560 }
561 #elif LDBL_MANT_DIG == 113
562 CppTypeFor<TypeCategory::Real, 16> RTNAME(ModReal16)(
563     CppTypeFor<TypeCategory::Real, 16> x, CppTypeFor<TypeCategory::Real, 16> p,
564     const char *sourceFile, int sourceLine) {
565   return RealMod<false>(x, p, sourceFile, sourceLine);
566 }
567 #endif
568 
569 CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModuloInteger1)(
570     CppTypeFor<TypeCategory::Integer, 1> x,
571     CppTypeFor<TypeCategory::Integer, 1> p, const char *sourceFile,
572     int sourceLine) {
573   return IntMod<true>(x, p, sourceFile, sourceLine);
574 }
575 CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModuloInteger2)(
576     CppTypeFor<TypeCategory::Integer, 2> x,
577     CppTypeFor<TypeCategory::Integer, 2> p, const char *sourceFile,
578     int sourceLine) {
579   return IntMod<true>(x, p, sourceFile, sourceLine);
580 }
581 CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModuloInteger4)(
582     CppTypeFor<TypeCategory::Integer, 4> x,
583     CppTypeFor<TypeCategory::Integer, 4> p, const char *sourceFile,
584     int sourceLine) {
585   return IntMod<true>(x, p, sourceFile, sourceLine);
586 }
587 CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModuloInteger8)(
588     CppTypeFor<TypeCategory::Integer, 8> x,
589     CppTypeFor<TypeCategory::Integer, 8> p, const char *sourceFile,
590     int sourceLine) {
591   return IntMod<true>(x, p, sourceFile, sourceLine);
592 }
593 #ifdef __SIZEOF_INT128__
594 CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModuloInteger16)(
595     CppTypeFor<TypeCategory::Integer, 16> x,
596     CppTypeFor<TypeCategory::Integer, 16> p, const char *sourceFile,
597     int sourceLine) {
598   return IntMod<true>(x, p, sourceFile, sourceLine);
599 }
600 #endif
601 CppTypeFor<TypeCategory::Real, 4> RTNAME(ModuloReal4)(
602     CppTypeFor<TypeCategory::Real, 4> x, CppTypeFor<TypeCategory::Real, 4> p,
603     const char *sourceFile, int sourceLine) {
604   return RealMod<true>(x, p, sourceFile, sourceLine);
605 }
606 CppTypeFor<TypeCategory::Real, 8> RTNAME(ModuloReal8)(
607     CppTypeFor<TypeCategory::Real, 8> x, CppTypeFor<TypeCategory::Real, 8> p,
608     const char *sourceFile, int sourceLine) {
609   return RealMod<true>(x, p, sourceFile, sourceLine);
610 }
611 #if LDBL_MANT_DIG == 64
612 CppTypeFor<TypeCategory::Real, 10> RTNAME(ModuloReal10)(
613     CppTypeFor<TypeCategory::Real, 10> x, CppTypeFor<TypeCategory::Real, 10> p,
614     const char *sourceFile, int sourceLine) {
615   return RealMod<true>(x, p, sourceFile, sourceLine);
616 }
617 #elif LDBL_MANT_DIG == 113
618 CppTypeFor<TypeCategory::Real, 16> RTNAME(ModuloReal16)(
619     CppTypeFor<TypeCategory::Real, 16> x, CppTypeFor<TypeCategory::Real, 16> p,
620     const char *sourceFile, int sourceLine) {
621   return RealMod<true>(x, p, sourceFile, sourceLine);
622 }
623 #endif
624 
625 CppTypeFor<TypeCategory::Real, 4> RTNAME(Nearest4)(
626     CppTypeFor<TypeCategory::Real, 4> x, bool positive) {
627   return Nearest<24>(x, positive);
628 }
629 CppTypeFor<TypeCategory::Real, 8> RTNAME(Nearest8)(
630     CppTypeFor<TypeCategory::Real, 8> x, bool positive) {
631   return Nearest<53>(x, positive);
632 }
633 #if LDBL_MANT_DIG == 64
634 CppTypeFor<TypeCategory::Real, 10> RTNAME(Nearest10)(
635     CppTypeFor<TypeCategory::Real, 10> x, bool positive) {
636   return Nearest<64>(x, positive);
637 }
638 #elif LDBL_MANT_DIG == 113
639 CppTypeFor<TypeCategory::Real, 16> RTNAME(Nearest16)(
640     CppTypeFor<TypeCategory::Real, 16> x, bool positive) {
641   return Nearest<113>(x, positive);
642 }
643 #endif
644 
645 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint4_1)(
646     CppTypeFor<TypeCategory::Real, 4> x) {
647   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
648 }
649 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint4_2)(
650     CppTypeFor<TypeCategory::Real, 4> x) {
651   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
652 }
653 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint4_4)(
654     CppTypeFor<TypeCategory::Real, 4> x) {
655   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
656 }
657 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint4_8)(
658     CppTypeFor<TypeCategory::Real, 4> x) {
659   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
660 }
661 #ifdef __SIZEOF_INT128__
662 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint4_16)(
663     CppTypeFor<TypeCategory::Real, 4> x) {
664   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
665 }
666 #endif
667 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint8_1)(
668     CppTypeFor<TypeCategory::Real, 8> x) {
669   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
670 }
671 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint8_2)(
672     CppTypeFor<TypeCategory::Real, 8> x) {
673   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
674 }
675 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint8_4)(
676     CppTypeFor<TypeCategory::Real, 8> x) {
677   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
678 }
679 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint8_8)(
680     CppTypeFor<TypeCategory::Real, 8> x) {
681   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
682 }
683 #ifdef __SIZEOF_INT128__
684 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint8_16)(
685     CppTypeFor<TypeCategory::Real, 8> x) {
686   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
687 }
688 #endif
689 #if LDBL_MANT_DIG == 64
690 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint10_1)(
691     CppTypeFor<TypeCategory::Real, 10> x) {
692   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
693 }
694 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint10_2)(
695     CppTypeFor<TypeCategory::Real, 10> x) {
696   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
697 }
698 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint10_4)(
699     CppTypeFor<TypeCategory::Real, 10> x) {
700   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
701 }
702 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint10_8)(
703     CppTypeFor<TypeCategory::Real, 10> x) {
704   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
705 }
706 #ifdef __SIZEOF_INT128__
707 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint10_16)(
708     CppTypeFor<TypeCategory::Real, 10> x) {
709   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
710 }
711 #endif
712 #elif LDBL_MANT_DIG == 113
713 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint16_1)(
714     CppTypeFor<TypeCategory::Real, 16> x) {
715   return Nint<CppTypeFor<TypeCategory::Integer, 1>>(x);
716 }
717 CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint16_2)(
718     CppTypeFor<TypeCategory::Real, 16> x) {
719   return Nint<CppTypeFor<TypeCategory::Integer, 2>>(x);
720 }
721 CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint16_4)(
722     CppTypeFor<TypeCategory::Real, 16> x) {
723   return Nint<CppTypeFor<TypeCategory::Integer, 4>>(x);
724 }
725 CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint16_8)(
726     CppTypeFor<TypeCategory::Real, 16> x) {
727   return Nint<CppTypeFor<TypeCategory::Integer, 8>>(x);
728 }
729 #ifdef __SIZEOF_INT128__
730 CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint16_16)(
731     CppTypeFor<TypeCategory::Real, 16> x) {
732   return Nint<CppTypeFor<TypeCategory::Integer, 16>>(x);
733 }
734 #endif
735 #endif
736 
737 CppTypeFor<TypeCategory::Real, 4> RTNAME(RRSpacing4)(
738     CppTypeFor<TypeCategory::Real, 4> x) {
739   return RRSpacing<24>(x);
740 }
741 CppTypeFor<TypeCategory::Real, 8> RTNAME(RRSpacing8)(
742     CppTypeFor<TypeCategory::Real, 8> x) {
743   return RRSpacing<53>(x);
744 }
745 #if LDBL_MANT_DIG == 64
746 CppTypeFor<TypeCategory::Real, 10> RTNAME(RRSpacing10)(
747     CppTypeFor<TypeCategory::Real, 10> x) {
748   return RRSpacing<64>(x);
749 }
750 #elif LDBL_MANT_DIG == 113
751 CppTypeFor<TypeCategory::Real, 16> RTNAME(RRSpacing16)(
752     CppTypeFor<TypeCategory::Real, 16> x) {
753   return RRSpacing<113>(x);
754 }
755 #endif
756 
757 CppTypeFor<TypeCategory::Real, 4> RTNAME(SetExponent4)(
758     CppTypeFor<TypeCategory::Real, 4> x, std::int64_t p) {
759   return SetExponent(x, p);
760 }
761 CppTypeFor<TypeCategory::Real, 8> RTNAME(SetExponent8)(
762     CppTypeFor<TypeCategory::Real, 8> x, std::int64_t p) {
763   return SetExponent(x, p);
764 }
765 #if LDBL_MANT_DIG == 64
766 CppTypeFor<TypeCategory::Real, 10> RTNAME(SetExponent10)(
767     CppTypeFor<TypeCategory::Real, 10> x, std::int64_t p) {
768   return SetExponent(x, p);
769 }
770 #elif LDBL_MANT_DIG == 113
771 CppTypeFor<TypeCategory::Real, 16> RTNAME(SetExponent16)(
772     CppTypeFor<TypeCategory::Real, 16> x, std::int64_t p) {
773   return SetExponent(x, p);
774 }
775 #endif
776 
777 CppTypeFor<TypeCategory::Real, 4> RTNAME(Scale4)(
778     CppTypeFor<TypeCategory::Real, 4> x, std::int64_t p) {
779   return Scale(x, p);
780 }
781 CppTypeFor<TypeCategory::Real, 8> RTNAME(Scale8)(
782     CppTypeFor<TypeCategory::Real, 8> x, std::int64_t p) {
783   return Scale(x, p);
784 }
785 #if LDBL_MANT_DIG == 64
786 CppTypeFor<TypeCategory::Real, 10> RTNAME(Scale10)(
787     CppTypeFor<TypeCategory::Real, 10> x, std::int64_t p) {
788   return Scale(x, p);
789 }
790 #elif LDBL_MANT_DIG == 113
791 CppTypeFor<TypeCategory::Real, 16> RTNAME(Scale16)(
792     CppTypeFor<TypeCategory::Real, 16> x, std::int64_t p) {
793   return Scale(x, p);
794 }
795 #endif
796 
797 // SELECTED_REAL_KIND
798 CppTypeFor<TypeCategory::Integer, 4> RTNAME(SelectedRealKind)(
799     const char *source, int line, void *precision, int pKind, void *range,
800     int rKind, void *radix, int dKind) {
801 #ifdef __SIZEOF_INT128__
802   CppTypeFor<TypeCategory::Integer, 16> p =
803       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
804           source, line, precision, pKind, /*defaultValue*/ 0, /*resKind*/ 16);
805   CppTypeFor<TypeCategory::Integer, 16> r =
806       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
807           source, line, range, rKind, /*defaultValue*/ 0, /*resKind*/ 16);
808   CppTypeFor<TypeCategory::Integer, 16> d =
809       getIntArgValue<CppTypeFor<TypeCategory::Integer, 16>>(
810           source, line, radix, dKind, /*defaultValue*/ 2, /*resKind*/ 16);
811 #else
812   std::int64_t p = getIntArgValue<std::int64_t>(
813       source, line, precision, pKind, /*defaultValue*/ 0, /*resKind*/ 8);
814   std::int64_t r = getIntArgValue<std::int64_t>(
815       source, line, range, rKind, /*defaultValue*/ 0, /*resKind*/ 8);
816   std::int64_t d = getIntArgValue<std::int64_t>(
817       source, line, radix, dKind, /*defaultValue*/ 2, /*resKind*/ 8);
818 #endif
819   return SelectedRealKind(p, r, d);
820 }
821 
822 CppTypeFor<TypeCategory::Real, 4> RTNAME(Spacing4)(
823     CppTypeFor<TypeCategory::Real, 4> x) {
824   return Spacing<24>(x);
825 }
826 CppTypeFor<TypeCategory::Real, 8> RTNAME(Spacing8)(
827     CppTypeFor<TypeCategory::Real, 8> x) {
828   return Spacing<53>(x);
829 }
830 #if LDBL_MANT_DIG == 64
831 CppTypeFor<TypeCategory::Real, 10> RTNAME(Spacing10)(
832     CppTypeFor<TypeCategory::Real, 10> x) {
833   return Spacing<64>(x);
834 }
835 #elif LDBL_MANT_DIG == 113
836 CppTypeFor<TypeCategory::Real, 16> RTNAME(Spacing16)(
837     CppTypeFor<TypeCategory::Real, 16> x) {
838   return Spacing<113>(x);
839 }
840 #endif
841 } // extern "C"
842 } // namespace Fortran::runtime
843