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