xref: /llvm-project/flang/unittests/Decimal/thorough-test.cpp (revision 1f8790050b0e99e7b46cc69518aa84f46f50738e)
1 #include "flang/Decimal/decimal.h"
2 #include "llvm/Support/raw_ostream.h"
3 #include <cinttypes>
4 #include <cstdio>
5 #include <cstring>
6 
7 static constexpr int incr{1}; // steps through all values
8 static constexpr bool doNegative{true};
9 static constexpr bool doMinimize{true};
10 
11 using namespace Fortran::decimal;
12 
13 static std::uint64_t tests{0};
14 static std::uint64_t fails{0};
15 
16 union u {
17   float x;
18   std::uint32_t u;
19 };
20 
21 llvm::raw_ostream &failed(float x) {
22   ++fails;
23   union u u;
24   u.x = x;
25   llvm::outs() << "FAIL: 0x";
26   return llvm::outs().write_hex(u.u);
27 }
28 
29 void testReadback(float x, int flags) {
30   char buffer[1024];
31   union u u;
32   u.x = x;
33   if (!(tests & 0x3fffff)) {
34     llvm::errs() << "\n0x";
35     llvm::errs().write_hex(u.u) << ' ';
36   } else if (!(tests & 0xffff)) {
37     llvm::errs() << '.';
38   }
39   ++tests;
40   auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
41       static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)};
42   if (result.str == nullptr) {
43     failed(x) << ' ' << flags << ": no result str\n";
44   } else {
45     float y{0};
46     char *q{const_cast<char *>(result.str)};
47     if ((*q >= '0' && *q <= '9') ||
48         ((*q == '-' || *q == '+') && q[1] >= '0' && q[1] <= '9')) {
49       int expo{result.decimalExponent};
50       expo -= result.length;
51       if (*q == '-' || *q == '+') {
52         ++expo;
53       }
54       std::sprintf(q + result.length, "e%d", expo);
55     }
56     const char *p{q};
57     auto rflags{ConvertDecimalToFloat(&p, &y, RoundNearest)};
58     if (!(x == x)) {
59       if (y == y || *p != '\0' || (rflags & Invalid)) {
60         u.x = y;
61         failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x";
62         failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n';
63       }
64     } else if (x != y || *p != '\0' || (rflags & Invalid)) {
65       u.x = y;
66       failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x";
67       failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n';
68     }
69   }
70 }
71 
72 int main() {
73   union u u;
74   for (u.u = 0; u.u < 0x7f800010; u.u += incr) {
75     testReadback(u.x, 0);
76     if constexpr (doNegative) {
77       testReadback(-u.x, 0);
78     }
79     if constexpr (doMinimize) {
80       testReadback(u.x, Minimize);
81       if constexpr (doNegative) {
82         testReadback(-u.x, Minimize);
83       }
84     }
85   }
86   llvm::outs() << '\n' << tests << " tests run, " << fails << " tests failed\n";
87   return fails > 0;
88 }
89