1#include "fp-testing.h"
2#include "testing.h"
3#include "flang/Evaluate/type.h"
4#include "llvm/Support/raw_ostream.h"
5#include <cmath>
6#include <cstdio>
7#include <cstdlib>
8#include <type_traits>
9
10using namespace Fortran::evaluate;
11using namespace Fortran::common;
12
13using Real2 = Scalar<Type<TypeCategory::Real, 2>>;
14using Real3 = Scalar<Type<TypeCategory::Real, 3>>;
15using Real4 = Scalar<Type<TypeCategory::Real, 4>>;
16using Real8 = Scalar<Type<TypeCategory::Real, 8>>;
17#ifdef __x86_64__
18using Real10 = Scalar<Type<TypeCategory::Real, 10>>;
19#endif
20using Real16 = Scalar<Type<TypeCategory::Real, 16>>;
21using Integer4 = Scalar<Type<TypeCategory::Integer, 4>>;
22using Integer8 = Scalar<Type<TypeCategory::Integer, 8>>;
23
24void dumpTest() {
25 struct {
26 std::uint64_t raw;
27 const char *expected;
28 } table[] = {
29 {.raw: 0x7f876543, .expected: "NaN0x7f876543"},
30 {.raw: 0x7f800000, .expected: "Inf"},
31 {.raw: 0xff800000, .expected: "-Inf"},
32 {.raw: 0x00000000, .expected: "0.0"},
33 {.raw: 0x80000000, .expected: "-0.0"},
34 {.raw: 0x3f800000, .expected: "0x1.0p0"},
35 {.raw: 0xbf800000, .expected: "-0x1.0p0"},
36 {.raw: 0x40000000, .expected: "0x1.0p1"},
37 {.raw: 0x3f000000, .expected: "0x1.0p-1"},
38 {.raw: 0x7f7fffff, .expected: "0x1.fffffep127"},
39 {.raw: 0x00800000, .expected: "0x1.0p-126"},
40 {.raw: 0x00400000, .expected: "0x0.8p-126"},
41 {.raw: 0x00000001, .expected: "0x0.000002p-126"},
42 {.raw: 0, .expected: nullptr},
43 };
44 for (int j{0}; table[j].expected != nullptr; ++j) {
45 TEST(Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected)
46 ("%d", j);
47 }
48}
49
50template <typename R> void basicTests(int rm, Rounding rounding) {
51 static constexpr int kind{R::bits / 8};
52 char desc[64];
53 using Word = typename R::Word;
54 std::snprintf(s: desc, maxlen: sizeof desc, format: "bits=%d, le=%d, kind=%d", R::bits,
55 Word::littleEndian, kind);
56 R zero;
57 TEST(!zero.IsNegative())(desc);
58 TEST(!zero.IsNotANumber())(desc);
59 TEST(!zero.IsInfinite())(desc);
60 TEST(zero.IsZero())(desc);
61 MATCH(0, zero.Exponent())(desc);
62 TEST(zero.RawBits().IsZero())(desc);
63 MATCH(0, zero.RawBits().ToUInt64())(desc);
64 TEST(zero.ABS().RawBits().IsZero())(desc);
65 TEST(zero.Negate().RawBits().IEOR(Word::MASKL(1)).IsZero())(desc);
66 TEST(zero.Compare(zero) == Relation::Equal)(desc);
67 R minusZero{Word{std::uint64_t{1}}.SHIFTL(R::bits - 1)};
68 TEST(minusZero.IsNegative())(desc);
69 TEST(!minusZero.IsNotANumber())(desc);
70 TEST(!minusZero.IsInfinite())(desc);
71 TEST(minusZero.IsZero())(desc);
72 TEST(minusZero.ABS().RawBits().IsZero())(desc);
73 TEST(minusZero.Negate().RawBits().IsZero())(desc);
74 MATCH(0, minusZero.Exponent())(desc);
75 MATCH(0, minusZero.RawBits().LEADZ())(desc);
76 MATCH(1, minusZero.RawBits().POPCNT())(desc);
77 TEST(minusZero.Compare(minusZero) == Relation::Equal)(desc);
78 TEST(zero.Compare(minusZero) == Relation::Equal)(desc);
79 ValueWithRealFlags<R> vr;
80 MATCH(0, vr.value.RawBits().ToUInt64())(desc);
81 TEST(vr.flags.empty())(desc);
82 R nan{Word{std::uint64_t{1}}
83 .SHIFTL(R::bits)
84 .SubtractSigned(Word{std::uint64_t{1}})
85 .value};
86 MATCH(R::bits, nan.RawBits().POPCNT())(desc);
87 TEST(!nan.IsNegative())(desc);
88 TEST(nan.IsNotANumber())(desc);
89 TEST(!nan.IsInfinite())(desc);
90 TEST(!nan.IsZero())(desc);
91 TEST(zero.Compare(nan) == Relation::Unordered)(desc);
92 TEST(minusZero.Compare(nan) == Relation::Unordered)(desc);
93 TEST(nan.Compare(zero) == Relation::Unordered)(desc);
94 TEST(nan.Compare(minusZero) == Relation::Unordered)(desc);
95 TEST(nan.Compare(nan) == Relation::Unordered)(desc);
96 int significandBits{R::binaryPrecision - R::isImplicitMSB};
97 int exponentBits{R::bits - significandBits - 1};
98 std::uint64_t maxExponent{(std::uint64_t{1} << exponentBits) - 1};
99 MATCH(nan.Exponent(), maxExponent)(desc);
100 Word infWord{Word{maxExponent}.SHIFTL(significandBits)};
101 Word negInfWord{
102 Word{maxExponent}.SHIFTL(significandBits).IOR(Word::MASKL(1))};
103 if constexpr (kind == 10) { // x87
104 infWord = infWord.IBSET(63);
105 negInfWord = negInfWord.IBSET(63);
106 }
107 R inf{infWord};
108 R negInf{negInfWord};
109 TEST(!inf.IsNegative())(desc);
110 TEST(!inf.IsNotANumber())(desc);
111 TEST(inf.IsInfinite())(desc);
112 TEST(!inf.IsZero())(desc);
113 TEST(inf.RawBits().CompareUnsigned(inf.ABS().RawBits()) == Ordering::Equal)
114 (desc);
115 TEST(zero.Compare(inf) == Relation::Less)(desc);
116 TEST(minusZero.Compare(inf) == Relation::Less)(desc);
117 TEST(nan.Compare(inf) == Relation::Unordered)(desc);
118 TEST(inf.Compare(inf) == Relation::Equal)(desc);
119 TEST(negInf.IsNegative())(desc);
120 TEST(!negInf.IsNotANumber())(desc);
121 TEST(negInf.IsInfinite())(desc);
122 TEST(!negInf.IsZero())(desc);
123 TEST(inf.RawBits().CompareUnsigned(negInf.ABS().RawBits()) == Ordering::Equal)
124 (desc);
125 TEST(inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) ==
126 Ordering::Equal)
127 (desc);
128 TEST(inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) ==
129 Ordering::Equal)
130 (desc);
131 TEST(zero.Compare(negInf) == Relation::Greater)(desc);
132 TEST(minusZero.Compare(negInf) == Relation::Greater)(desc);
133 TEST(nan.Compare(negInf) == Relation::Unordered)(desc);
134 TEST(inf.Compare(negInf) == Relation::Greater)(desc);
135 TEST(negInf.Compare(negInf) == Relation::Equal)(desc);
136 for (std::uint64_t j{0}; j < 63; ++j) {
137 char ldesc[128];
138 std::uint64_t x{1};
139 x <<= j;
140 std::snprintf(s: ldesc, maxlen: sizeof ldesc, format: "%s j=%d x=0x%jx rm=%d", desc,
141 static_cast<int>(j), static_cast<std::intmax_t>(x), rm);
142 Integer8 ix{x};
143 TEST(!ix.IsNegative())(ldesc);
144 MATCH(x, ix.ToUInt64())(ldesc);
145 vr = R::FromInteger(ix, rounding);
146 TEST(!vr.value.IsNegative())(ldesc);
147 TEST(!vr.value.IsNotANumber())(ldesc);
148 TEST(!vr.value.IsZero())(ldesc);
149 auto ivf = vr.value.template ToInteger<Integer8>();
150 if (j > (maxExponent / 2)) {
151 TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
152 TEST(vr.value.IsInfinite())(ldesc);
153 TEST(ivf.flags.test(RealFlag::Overflow))(ldesc);
154 MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())(ldesc);
155 } else {
156 TEST(vr.flags.empty())(ldesc);
157 TEST(!vr.value.IsInfinite())(ldesc);
158 TEST(ivf.flags.empty())(ldesc);
159 MATCH(x, ivf.value.ToUInt64())(ldesc);
160 if (rounding.mode == RoundingMode::TiesToEven) { // to match stold()
161 std::string buf;
162 llvm::raw_string_ostream ss{buf};
163 vr.value.AsFortran(ss, kind, false /*exact*/);
164 std::string decimal{ss.str()};
165 const char *p{decimal.data()};
166 MATCH(x, static_cast<std::uint64_t>(std::stold(decimal)))
167 ("%s %s", ldesc, p);
168 auto check{R::Read(p, rounding)};
169 auto icheck{check.value.template ToInteger<Integer8>()};
170 MATCH(x, icheck.value.ToUInt64())(ldesc);
171 TEST(vr.value.Compare(check.value) == Relation::Equal)(ldesc);
172 }
173 }
174 TEST(vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal)
175 (ldesc);
176 ix = ix.Negate().value;
177 TEST(ix.IsNegative())(ldesc);
178 x = -x;
179 std::int64_t nx = x;
180 MATCH(x, ix.ToUInt64())(ldesc);
181 MATCH(nx, ix.ToInt64())(ldesc);
182 vr = R::FromInteger(ix);
183 TEST(vr.value.IsNegative())(ldesc);
184 TEST(!vr.value.IsNotANumber())(ldesc);
185 TEST(!vr.value.IsZero())(ldesc);
186 ivf = vr.value.template ToInteger<Integer8>();
187 if (j > (maxExponent / 2)) {
188 TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
189 TEST(vr.value.IsInfinite())(ldesc);
190 TEST(ivf.flags.test(RealFlag::Overflow))(ldesc);
191 MATCH(0x8000000000000000, ivf.value.ToUInt64())(ldesc);
192 } else {
193 TEST(vr.flags.empty())(ldesc);
194 TEST(!vr.value.IsInfinite())(ldesc);
195 TEST(ivf.flags.empty())(ldesc);
196 MATCH(x, ivf.value.ToUInt64())(ldesc);
197 MATCH(nx, ivf.value.ToInt64())(ldesc);
198 }
199 TEST(vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal)
200 (ldesc);
201 }
202}
203
204// Takes an integer and distributes its bits across a floating
205// point value. The LSB is used to complement the result.
206std::uint32_t MakeReal(std::uint32_t n) {
207 int shifts[] = {-1, 31, 23, 30, 22, 0, 24, 29, 25, 28, 26, 1, 16, 21, 2, -1};
208 std::uint32_t x{0};
209 for (int j{1}; shifts[j] >= 0; ++j) {
210 x |= ((n >> j) & 1) << shifts[j];
211 }
212 x ^= -(n & 1);
213 return x;
214}
215
216std::uint64_t MakeReal(std::uint64_t n) {
217 int shifts[] = {
218 -1, 63, 52, 62, 51, 0, 53, 61, 54, 60, 55, 59, 1, 16, 50, 2, -1};
219 std::uint64_t x{0};
220 for (int j{1}; shifts[j] >= 0; ++j) {
221 x |= ((n >> j) & 1) << shifts[j];
222 }
223 x ^= -(n & 1);
224 return x;
225}
226
227inline bool IsNaN(std::uint32_t x) {
228 return (x & 0x7f800000) == 0x7f800000 && (x & 0x007fffff) != 0;
229}
230
231inline bool IsNaN(std::uint64_t x) {
232 return (x & 0x7ff0000000000000) == 0x7ff0000000000000 &&
233 (x & 0x000fffffffffffff) != 0;
234}
235
236inline bool IsInfinite(std::uint32_t x) {
237 return (x & 0x7fffffff) == 0x7f800000;
238}
239
240inline bool IsInfinite(std::uint64_t x) {
241 return (x & 0x7fffffffffffffff) == 0x7ff0000000000000;
242}
243
244inline bool IsNegative(std::uint32_t x) { return (x & 0x80000000) != 0; }
245
246inline bool IsNegative(std::uint64_t x) {
247 return (x & 0x8000000000000000) != 0;
248}
249
250inline std::uint32_t NormalizeNaN(std::uint32_t x) {
251 if (IsNaN(x)) {
252 x = 0x7fe00000;
253 }
254 return x;
255}
256
257inline std::uint64_t NormalizeNaN(std::uint64_t x) {
258 if (IsNaN(x)) {
259 x = 0x7ffc000000000000;
260 }
261 return x;
262}
263
264enum FlagBits {
265 Overflow = 1,
266 DivideByZero = 2,
267 InvalidArgument = 4,
268 Underflow = 8,
269 Inexact = 16,
270};
271
272#ifdef __clang__
273// clang support for fenv.h is broken, so tests of flag settings
274// are disabled.
275inline std::uint32_t FlagsToBits(const RealFlags &) { return 0; }
276#else
277inline std::uint32_t FlagsToBits(const RealFlags &flags) {
278 std::uint32_t bits{0};
279 if (flags.test(RealFlag::Overflow)) {
280 bits |= Overflow;
281 }
282 if (flags.test(RealFlag::DivideByZero)) {
283 bits |= DivideByZero;
284 }
285 if (flags.test(RealFlag::InvalidArgument)) {
286 bits |= InvalidArgument;
287 }
288 if (flags.test(RealFlag::Underflow)) {
289 bits |= Underflow;
290 }
291 if (flags.test(RealFlag::Inexact)) {
292 bits |= Inexact;
293 }
294 return bits;
295}
296#endif // __clang__
297
298template <typename UINT = std::uint32_t, typename FLT = float, typename REAL>
299void inttest(std::int64_t x, int pass, Rounding rounding) {
300 union {
301 UINT ui;
302 FLT f;
303 } u;
304 ScopedHostFloatingPointEnvironment fpenv;
305 Integer8 ix{x};
306 ValueWithRealFlags<REAL> real;
307 real = real.value.FromInteger(ix, rounding);
308#ifndef __clang__ // broken and also slow
309 fpenv.ClearFlags();
310#endif
311 FLT fcheck = x; // TODO unsigned too
312 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
313 u.f = fcheck;
314 UINT rcheck{NormalizeNaN(u.ui)};
315 UINT check = real.value.RawBits().ToUInt64();
316 MATCH(rcheck, check)("%d 0x%llx", pass, x);
317 MATCH(actualFlags, FlagsToBits(real.flags))("%d 0x%llx", pass, x);
318}
319
320template <typename FLT = float> FLT ToIntPower(FLT x, int power) {
321 if (power == 0) {
322 return x / x;
323 }
324 bool negative{power < 0};
325 if (negative) {
326 power = -power;
327 }
328 FLT result{1};
329 while (power > 0) {
330 if (power & 1) {
331 result *= x;
332 }
333 x *= x;
334 power >>= 1;
335 }
336 if (negative) {
337 result = 1.0 / result;
338 }
339 return result;
340}
341
342template <typename FLT, int decimalDigits>
343FLT TimesIntPowerOfTen(FLT x, int power) {
344 if (power > decimalDigits || power < -decimalDigits) {
345 auto maxExactPowerOfTen{
346 TimesIntPowerOfTen<FLT, decimalDigits>(1, decimalDigits)};
347 auto big{ToIntPower<FLT>(maxExactPowerOfTen, power / decimalDigits)};
348 auto small{
349 TimesIntPowerOfTen<FLT, decimalDigits>(1, power % decimalDigits)};
350 return (x * big) * small;
351 }
352 return x * ToIntPower<FLT>(10.0, power);
353}
354
355template <typename UINT = std::uint32_t, typename FLT = float,
356 typename REAL = Real4>
357void subsetTests(int pass, Rounding rounding, std::uint32_t opds) {
358 for (int j{0}; j < 63; ++j) {
359 std::int64_t x{1};
360 x <<= j;
361 inttest<UINT, FLT, REAL>(x, pass, rounding);
362 inttest<UINT, FLT, REAL>(-x, pass, rounding);
363 }
364 inttest<UINT, FLT, REAL>(0, pass, rounding);
365 inttest<UINT, FLT, REAL>(
366 static_cast<std::int64_t>(0x8000000000000000), pass, rounding);
367
368 union {
369 UINT ui;
370 FLT f;
371 } u;
372 ScopedHostFloatingPointEnvironment fpenv;
373
374 for (UINT j{0}; j < opds; ++j) {
375
376 UINT rj{MakeReal(j)};
377 u.ui = rj;
378 FLT fj{u.f};
379 REAL x{typename REAL::Word{std::uint64_t{rj}}};
380
381 // unary operations
382 {
383 ValueWithRealFlags<REAL> aint{x.ToWholeNumber()};
384#ifndef __clang__ // broken and also slow
385 fpenv.ClearFlags();
386#endif
387 FLT fcheck{std::trunc(fj)};
388 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
389 actualFlags &= ~Inexact; // x86 std::trunc can set Inexact; AINT ain't
390 u.f = fcheck;
391#ifndef __clang__
392 if (IsNaN(u.ui)) {
393 actualFlags |= InvalidArgument; // x86 std::trunc(NaN) workaround
394 }
395#endif
396 UINT rcheck{NormalizeNaN(u.ui)};
397 UINT check = aint.value.RawBits().ToUInt64();
398 MATCH(rcheck, check)
399 ("%d AINT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
400 MATCH(actualFlags, FlagsToBits(aint.flags))
401 ("%d AINT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
402 }
403
404 {
405 ValueWithRealFlags<REAL> root{x.SQRT(rounding)};
406#ifndef __clang__ // broken and also slow
407 fpenv.ClearFlags();
408#endif
409 FLT fcheck{std::sqrt(fj)};
410 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
411 u.f = fcheck;
412 UINT rcheck{NormalizeNaN(u.ui)};
413 UINT check = root.value.RawBits().ToUInt64();
414 MATCH(rcheck, check)
415 ("%d SQRT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
416 MATCH(actualFlags, FlagsToBits(root.flags))
417 ("%d SQRT(0x%jx)", pass, static_cast<std::intmax_t>(rj));
418 }
419
420 {
421 MATCH(IsNaN(rj), x.IsNotANumber())
422 ("%d IsNaN(0x%jx)", pass, static_cast<std::intmax_t>(rj));
423 MATCH(IsInfinite(rj), x.IsInfinite())
424 ("%d IsInfinite(0x%jx)", pass, static_cast<std::intmax_t>(rj));
425
426 static constexpr int kind{REAL::bits / 8};
427 std::string ssBuf, cssBuf;
428 llvm::raw_string_ostream ss{ssBuf};
429 llvm::raw_string_ostream css{cssBuf};
430 x.AsFortran(ss, kind, false /*exact*/);
431 std::string s{ss.str()};
432 if (IsNaN(rj)) {
433 css << "(0._" << kind << "/0.)";
434 MATCH(css.str(), s)
435 ("%d invalid(0x%jx)", pass, static_cast<std::intmax_t>(rj));
436 } else if (IsInfinite(rj)) {
437 css << '(';
438 if (IsNegative(rj)) {
439 css << '-';
440 }
441 css << "1._" << kind << "/0.)";
442 MATCH(css.str(), s)
443 ("%d overflow(0x%jx)", pass, static_cast<std::intmax_t>(rj));
444 } else {
445 const char *p = s.data();
446 if (*p == '(') {
447 ++p;
448 }
449 auto readBack{REAL::Read(p, rounding)};
450 MATCH(rj, readBack.value.RawBits().ToUInt64())
451 ("%d Read(AsFortran()) 0x%jx %s %g", pass,
452 static_cast<std::intmax_t>(rj), s.data(), static_cast<double>(fj));
453 MATCH('_', *p)
454 ("%d Read(AsFortran()) 0x%jx %s %d", pass,
455 static_cast<std::intmax_t>(rj), s.data(),
456 static_cast<int>(p - s.data()));
457 }
458 }
459
460 // dyadic operations
461 for (UINT k{0}; k < opds; ++k) {
462 UINT rk{MakeReal(k)};
463 u.ui = rk;
464 FLT fk{u.f};
465 REAL y{typename REAL::Word{std::uint64_t{rk}}};
466 {
467 ValueWithRealFlags<REAL> sum{x.Add(y, rounding)};
468#ifndef __clang__ // broken and also slow
469 fpenv.ClearFlags();
470#endif
471 FLT fcheck{fj + fk};
472 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
473 u.f = fcheck;
474 UINT rcheck{NormalizeNaN(u.ui)};
475 UINT check = sum.value.RawBits().ToUInt64();
476 MATCH(rcheck, check)
477 ("%d 0x%jx + 0x%jx", pass, static_cast<std::intmax_t>(rj),
478 static_cast<std::intmax_t>(rk));
479 MATCH(actualFlags, FlagsToBits(sum.flags))
480 ("%d 0x%jx + 0x%jx", pass, static_cast<std::intmax_t>(rj),
481 static_cast<std::intmax_t>(rk));
482 }
483 {
484 ValueWithRealFlags<REAL> diff{x.Subtract(y, rounding)};
485#ifndef __clang__ // broken and also slow
486 fpenv.ClearFlags();
487#endif
488 FLT fcheck{fj - fk};
489 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
490 u.f = fcheck;
491 UINT rcheck{NormalizeNaN(u.ui)};
492 UINT check = diff.value.RawBits().ToUInt64();
493 MATCH(rcheck, check)
494 ("%d 0x%jx - 0x%jx", pass, static_cast<std::intmax_t>(rj),
495 static_cast<std::intmax_t>(rk));
496 MATCH(actualFlags, FlagsToBits(diff.flags))
497 ("%d 0x%jx - 0x%jx", pass, static_cast<std::intmax_t>(rj),
498 static_cast<std::intmax_t>(rk));
499 }
500 {
501 ValueWithRealFlags<REAL> prod{x.Multiply(y, rounding)};
502#ifndef __clang__ // broken and also slow
503 fpenv.ClearFlags();
504#endif
505 FLT fcheck{fj * fk};
506 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
507 u.f = fcheck;
508 UINT rcheck{NormalizeNaN(u.ui)};
509 UINT check = prod.value.RawBits().ToUInt64();
510 MATCH(rcheck, check)
511 ("%d 0x%jx * 0x%jx", pass, static_cast<std::intmax_t>(rj),
512 static_cast<std::intmax_t>(rk));
513 MATCH(actualFlags, FlagsToBits(prod.flags))
514 ("%d 0x%jx * 0x%jx", pass, static_cast<std::intmax_t>(rj),
515 static_cast<std::intmax_t>(rk));
516 }
517 {
518 ValueWithRealFlags<REAL> quot{x.Divide(y, rounding)};
519#ifndef __clang__ // broken and also slow
520 fpenv.ClearFlags();
521#endif
522 FLT fcheck{fj / fk};
523 auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
524 u.f = fcheck;
525 UINT rcheck{NormalizeNaN(u.ui)};
526 UINT check = quot.value.RawBits().ToUInt64();
527 MATCH(rcheck, check)
528 ("%d 0x%jx / 0x%jx", pass, static_cast<std::intmax_t>(rj),
529 static_cast<std::intmax_t>(rk));
530 MATCH(actualFlags, FlagsToBits(quot.flags))
531 ("%d 0x%jx / 0x%jx", pass, static_cast<std::intmax_t>(rj),
532 static_cast<std::intmax_t>(rk));
533 }
534 }
535 }
536}
537
538void roundTest(int rm, Rounding rounding, std::uint32_t opds) {
539 basicTests<Real2>(rm, rounding);
540 basicTests<Real3>(rm, rounding);
541 basicTests<Real4>(rm, rounding);
542 basicTests<Real8>(rm, rounding);
543#ifdef __x86_64__
544 basicTests<Real10>(rm, rounding);
545#endif
546 basicTests<Real16>(rm, rounding);
547 ScopedHostFloatingPointEnvironment::SetRounding(rounding);
548 subsetTests<std::uint32_t, float, Real4>(rm, rounding, opds);
549 subsetTests<std::uint64_t, double, Real8>(rm, rounding, opds);
550}
551
552int main() {
553 dumpTest();
554 std::uint32_t opds{512}; // for quick testing by default
555 if (const char *p{std::getenv(name: "REAL_TEST_OPERANDS")}) {
556 // Use 8192 or 16384 for more exhaustive testing.
557 opds = std::atol(nptr: p);
558 }
559 roundTest(0, Rounding{RoundingMode::TiesToEven}, opds);
560 roundTest(1, Rounding{RoundingMode::ToZero}, opds);
561 roundTest(2, Rounding{RoundingMode::Up}, opds);
562 roundTest(3, Rounding{RoundingMode::Down}, opds);
563 // TODO: how to test Rounding::TiesAwayFromZero on x86?
564 return testing::Complete();
565}
566

source code of flang/unittests/Evaluate/real.cpp