1 #include "flang/Decimal/decimal.h"
2 #include "llvm/Support/raw_ostream.h"
3 #include <cinttypes>
4 #include <cstdio>
5 #include <cstring>
6 
7 using namespace Fortran::decimal;
8 
9 static int tests{0};
10 static int fails{0};
11 
12 union u {
13   float x;
14   std::uint32_t u;
15 };
16 
failed(float x)17 llvm::raw_ostream &failed(float x) {
18   ++fails;
19   union u u;
20   u.x = x;
21   llvm::outs() << "FAIL: 0x";
22   return llvm::outs().write_hex(u.u);
23 }
24 
testDirect(float x,const char * expect,int expectExpo,int flags=0)25 void testDirect(float x, const char *expect, int expectExpo, int flags = 0) {
26   char buffer[1024];
27   ++tests;
28   auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
29       static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)};
30   if (result.str == nullptr) {
31     failed(x) << ' ' << flags << ": no result str\n";
32   } else if (std::strcmp(result.str, expect) != 0 ||
33       result.decimalExponent != expectExpo) {
34     failed(x) << ' ' << flags << ": expect '." << expect << 'e' << expectExpo
35               << "', got '." << result.str << 'e' << result.decimalExponent
36               << "'\n";
37   }
38 }
39 
testReadback(float x,int flags)40 void testReadback(float x, int flags) {
41   char buffer[1024];
42   ++tests;
43   auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
44       static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)};
45   if (result.str == nullptr) {
46     failed(x) << ' ' << flags << ": no result str\n";
47   } else {
48     float y{0};
49     char *q{const_cast<char *>(result.str)};
50     int expo{result.decimalExponent};
51     expo -= result.length;
52     if (*q == '-' || *q == '+') {
53       ++expo;
54     }
55     if (q >= buffer && q < buffer + sizeof buffer) {
56       std::sprintf(q + result.length, "e%d", expo);
57     }
58     const char *p{q};
59     auto rflags{ConvertDecimalToFloat(&p, &y, RoundNearest)};
60     union u u;
61     if (!(x == x)) {
62       if (y == y || *p != '\0' || (rflags & Invalid)) {
63         u.x = y;
64         (failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x")
65                 .write_hex(u.u)
66             << " '" << p << "' " << rflags << '\n';
67       }
68     } else if (x != y || *p != '\0' || (rflags & Invalid)) {
69       u.x = x;
70       (failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x")
71               .write_hex(u.u)
72           << " '" << p << "' " << rflags << '\n';
73     }
74   }
75 }
76 
main()77 int main() {
78   union u u;
79   testDirect(-1.0, "-1", 1);
80   testDirect(0.0, "0", 0);
81   testDirect(0.0, "+0", 0, AlwaysSign);
82   testDirect(1.0, "1", 1);
83   testDirect(2.0, "2", 1);
84   testDirect(-1.0, "-1", 1);
85   testDirect(314159, "314159", 6);
86   testDirect(0.0625, "625", -1);
87   u.u = 0x80000000;
88   testDirect(u.x, "-0", 0);
89   u.u = 0x7f800000;
90   testDirect(u.x, "Inf", 0);
91   testDirect(u.x, "+Inf", 0, AlwaysSign);
92   u.u = 0xff800000;
93   testDirect(u.x, "-Inf", 0);
94   u.u = 0xffffffff;
95   testDirect(u.x, "NaN", 0);
96   testDirect(u.x, "NaN", 0, AlwaysSign);
97   u.u = 1;
98   testDirect(u.x,
99       "140129846432481707092372958328991613128026194187651577175706828388979108"
100       "268586060148663818836212158203125",
101       -44, 0);
102   testDirect(u.x, "1", -44, Minimize);
103   u.u = 0x7f777777;
104   testDirect(u.x, "3289396118917826996438159226753253376", 39, 0);
105   testDirect(u.x, "32893961", 39, Minimize);
106   for (u.u = 0; u.u < 16; ++u.u) {
107     testReadback(u.x, 0);
108     testReadback(-u.x, 0);
109     testReadback(u.x, Minimize);
110     testReadback(-u.x, Minimize);
111   }
112   for (u.u = 1; u.u < 0x7f800000; u.u *= 2) {
113     testReadback(u.x, 0);
114     testReadback(-u.x, 0);
115     testReadback(u.x, Minimize);
116     testReadback(-u.x, Minimize);
117   }
118   for (u.u = 0x7f7ffff0; u.u < 0x7f800010; ++u.u) {
119     testReadback(u.x, 0);
120     testReadback(-u.x, 0);
121     testReadback(u.x, Minimize);
122     testReadback(-u.x, Minimize);
123   }
124   for (u.u = 0; u.u < 0x7f800000; u.u += 65536) {
125     testReadback(u.x, 0);
126     testReadback(-u.x, 0);
127     testReadback(u.x, Minimize);
128     testReadback(-u.x, Minimize);
129   }
130   for (u.u = 0; u.u < 0x7f800000; u.u += 99999) {
131     testReadback(u.x, 0);
132     testReadback(-u.x, 0);
133     testReadback(u.x, Minimize);
134     testReadback(-u.x, Minimize);
135   }
136   for (u.u = 0; u.u < 0x7f800000; u.u += 32767) {
137     testReadback(u.x, 0);
138     testReadback(-u.x, 0);
139     testReadback(u.x, Minimize);
140     testReadback(-u.x, Minimize);
141   }
142   llvm::outs() << tests << " tests run, " << fails << " tests failed\n";
143   return fails > 0;
144 }
145