xref: /llvm-project/flang/unittests/Decimal/thorough-test.cpp (revision ecd691750648b72b9e0ce6879fcfa60396693a77)
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 
failed(float x)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 
testReadback(float x,int flags)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::snprintf(q + result.length,
55           buffer + sizeof buffer - (q + result.length), "e%d", expo);
56     }
57     const char *p{q};
58     auto rflags{ConvertDecimalToFloat(&p, &y, RoundNearest)};
59     if (!(x == x)) {
60       if (y == y || *p != '\0' || (rflags & Invalid)) {
61         u.x = y;
62         failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x";
63         failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n';
64       }
65     } else if (x != y || *p != '\0' || (rflags & Invalid)) {
66       u.x = y;
67       failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x";
68       failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n';
69     }
70   }
71 }
72 
main()73 int main() {
74   union u u;
75   for (u.u = 0; u.u < 0x7f800010; u.u += incr) {
76     testReadback(u.x, 0);
77     if constexpr (doNegative) {
78       testReadback(-u.x, 0);
79     }
80     if constexpr (doMinimize) {
81       testReadback(u.x, Minimize);
82       if constexpr (doNegative) {
83         testReadback(-u.x, Minimize);
84       }
85     }
86   }
87   llvm::outs() << '\n' << tests << " tests run, " << fails << " tests failed\n";
88   return fails > 0;
89 }
90