| #include "flang/Decimal/decimal.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cinttypes> |
| #include <cstdio> |
| #include <cstring> |
| |
| static constexpr int incr{1}; // steps through all values |
| static constexpr bool doNegative{true}; |
| static constexpr bool doMinimize{true}; |
| |
| using namespace Fortran::decimal; |
| |
| static std::uint64_t tests{0}; |
| static std::uint64_t fails{0}; |
| |
| union u { |
| float x; |
| std::uint32_t u; |
| }; |
| |
| llvm::raw_ostream &failed(float x) { |
| ++fails; |
| union u u; |
| u.x = x; |
| llvm::outs() << "FAIL: 0x"; |
| return llvm::outs().write_hex(u.u); |
| } |
| |
| void testReadback(float x, int flags) { |
| char buffer[1024]; |
| union u u; |
| u.x = x; |
| if (!(tests & 0x3fffff)) { |
| llvm::errs() << "\n0x"; |
| llvm::errs().write_hex(u.u) << ' '; |
| } else if (!(tests & 0xffff)) { |
| llvm::errs() << '.'; |
| } |
| ++tests; |
| auto result{ConvertFloatToDecimal(buffer, sizeof buffer, |
| static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)}; |
| if (result.str == nullptr) { |
| failed(x) << ' ' << flags << ": no result str\n"; |
| } else { |
| float y{0}; |
| char *q{const_cast<char *>(result.str)}; |
| if ((*q >= '0' && *q <= '9') || |
| ((*q == '-' || *q == '+') && q[1] >= '0' && q[1] <= '9')) { |
| int expo{result.decimalExponent}; |
| expo -= result.length; |
| if (*q == '-' || *q == '+') { |
| ++expo; |
| } |
| std::sprintf(q + result.length, "e%d", expo); |
| } |
| const char *p{q}; |
| auto rflags{ConvertDecimalToFloat(&p, &y, RoundNearest)}; |
| if (!(x == x)) { |
| if (y == y || *p != '\0' || (rflags & Invalid)) { |
| u.x = y; |
| failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x"; |
| failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n'; |
| } |
| } else if (x != y || *p != '\0' || (rflags & Invalid)) { |
| u.x = y; |
| failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x"; |
| failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n'; |
| } |
| } |
| } |
| |
| int main() { |
| union u u; |
| for (u.u = 0; u.u < 0x7f800010; u.u += incr) { |
| testReadback(u.x, 0); |
| if constexpr (doNegative) { |
| testReadback(-u.x, 0); |
| } |
| if constexpr (doMinimize) { |
| testReadback(u.x, Minimize); |
| if constexpr (doNegative) { |
| testReadback(-u.x, Minimize); |
| } |
| } |
| } |
| llvm::outs() << '\n' << tests << " tests run, " << fails << " tests failed\n"; |
| return fails > 0; |
| } |