[flang] Numeric constant formatting and tests.

Original-commit: flang-compiler/f18@ade6442020
Reviewed-on: https://github.com/flang-compiler/f18/pull/111
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-06-20 15:10:34 -07:00
parent 3d867f3202
commit 9e1ba097f5
5 changed files with 137 additions and 1 deletions

View File

@ -29,6 +29,7 @@
#include <cinttypes>
#include <climits>
#include <cstddef>
#include <string>
#include <type_traits>
namespace Fortran::evaluate::value {
@ -236,7 +237,48 @@ public:
return result;
}
// TODO formatting
std::string UnsignedDecimal() const {
if constexpr (bits < 4) {
char digit = '0' + ToUInt64();
return {digit};
} else if (IsZero()) {
return {'0'};
} else {
QuotientWithRemainder qr{DivideUnsigned(10)};
char digit = '0' + qr.remainder.ToUInt64();
if (qr.quotient.IsZero()) {
return {digit};
} else {
return qr.quotient.UnsignedDecimal() + digit;
}
}
}
std::string SignedDecimal() const {
if (IsNegative()) {
return std::string{'-'} + Negate().value.UnsignedDecimal();
} else {
return UnsignedDecimal();
}
}
// Omits a leading "0x".
std::string Hexadecimal() const {
std::string result;
int digits{(bits + 3) >> 2};
for (int j{0}; j < digits; ++j) {
int pos{(digits - 1 - j) * 4};
char nybble = IBITS(pos, 4).ToUInt64();
if (nybble != 0 || !result.empty() || j + 1 == digits) {
char digit = '0' + nybble;
if (digit > '9') {
digit += 'a' - ('9' + 1);
}
result += digit;
}
}
return result;
}
static constexpr Integer BIT_SIZE() { return {std::uint64_t{bits}}; }
static constexpr Integer HUGE() { return MASKR(bits - 1); }

View File

@ -13,6 +13,7 @@
// limitations under the License.
#include "real.h"
#include "../common/idioms.h"
namespace Fortran::evaluate::value {
@ -375,6 +376,53 @@ void Real<W, P, IM>::NormalizeAndRound(ValueWithRealFlags<Real> &result,
result.flags |= result.value.Round(rounding, roundingBits, multiply);
}
template<typename W, int P, bool IM>
std::string Real<W, P, IM>::DumpHexadecimal() const {
if (IsNotANumber()) {
return "NaN 0x"s + word_.Hexadecimal();
} else if (IsNegative()) {
return "-"s + Negate().DumpHexadecimal();
} else if (IsInfinite()) {
return "Inf"s;
} else if (IsZero()) {
return "0.0"s;
} else {
Fraction frac{GetFraction()};
std::string result{"0x"};
char intPart = '0' + frac.BTEST(frac.bits - 1);
result += intPart;
result += '.';
int trailz{frac.TRAILZ()};
if (trailz >= frac.bits - 1) {
result += '0';
} else {
int remainingBits{frac.bits - 1 - trailz};
int wholeNybbles{remainingBits / 4};
int lostBits{remainingBits - 4 * wholeNybbles};
if (wholeNybbles > 0) {
std::string fracHex{frac.SHIFTR(trailz + lostBits)
.IAND(frac.MASKR(4 * wholeNybbles))
.Hexadecimal()};
std::size_t field = wholeNybbles;
if (fracHex.size() < field) {
result += std::string(field - fracHex.size(), '0');
}
result += fracHex;
}
if (lostBits > 0) {
result += frac.SHIFTR(trailz)
.IAND(frac.MASKR(lostBits))
.SHIFTL(4 - lostBits)
.Hexadecimal();
}
}
result += 'p';
int exponent = Exponent() - exponentBias;
result += Integer<32>{exponent}.SignedDecimal();
return result;
}
}
template class Real<Integer<16>, 11>;
template class Real<Integer<32>, 24>;
template class Real<Integer<64>, 53>;

View File

@ -20,6 +20,7 @@
#include "rounding-bits.h"
#include <cinttypes>
#include <limits>
#include <string>
namespace Fortran::evaluate::value {
@ -208,6 +209,8 @@ public:
return word_.IBITS(significandBits, exponentBits).ToUInt64();
}
std::string DumpHexadecimal() const;
private:
using Fraction = Integer<precision>; // all bits made explicit
using Significand = Integer<significandBits>; // no implicit bit

View File

@ -15,6 +15,7 @@
#include "../../lib/evaluate/integer.h"
#include "testing.h"
#include <cstdio>
#include <string>
using Fortran::evaluate::Ordering;
using Fortran::evaluate::value::Integer;
@ -57,6 +58,18 @@ template<int BITS, typename INT = Integer<BITS>> void exhaustiveTesting() {
TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
TEST(!*p)("%s, x=0x%llx", desc, x);
std::string udec{a.UnsignedDecimal()};
p = udec.data();
readcheck = INT::ReadUnsigned(p);
TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
TEST(!*p)("%s, x=0x%llx", desc, x);
std::string hex{a.Hexadecimal()};
p = hex.data();
readcheck = INT::ReadUnsigned(p, 16);
TEST(!readcheck.overflow)("%s, x=0x%llx", desc, x);
MATCH(x, readcheck.value.ToUInt64())("%s, x=0x%llx", desc, x);
TEST(!*p)("%s, x=0x%llx", desc, x);
INT t{a.NOT()};
MATCH(x ^ maxUnsignedValue, t.ToUInt64())("%s, x=0x%llx", desc, x);
auto negated{a.Negate()};
@ -246,6 +259,10 @@ int main() {
TEST(Reverse(Ordering::Less) == Ordering::Greater);
TEST(Reverse(Ordering::Greater) == Ordering::Less);
TEST(Reverse(Ordering::Equal) == Ordering::Equal);
TEST(Integer<128>{123456789}.UnsignedDecimal() == "123456789");
TEST(Integer<128>{123456789}.SignedDecimal() == "123456789");
TEST(Integer<128>{-123456789}.SignedDecimal() == "-123456789");
TEST(Integer<128>{0x123456789abcdef}.Hexadecimal() == "123456789abcdef");
exhaustiveTesting<1>();
exhaustiveTesting<2>();
exhaustiveTesting<7>();

View File

@ -28,6 +28,31 @@ using Real16 = typename Type<Category::Real, 16>::Value;
using Integer4 = typename Type<Category::Integer, 4>::Value;
using Integer8 = typename Type<Category::Integer, 8>::Value;
void dumpTest() {
struct {
std::uint64_t raw;
const char *expected;
} table[] = {
{ 0x7f876543, "NaN 0x7f876543" },
{ 0x7f800000, "Inf" },
{ 0xff800000, "-Inf" },
{ 0x00000000, "0.0" },
{ 0x80000000, "-0.0" },
{ 0x3f800000, "0x1.0p0" },
{ 0xbf800000, "-0x1.0p0" },
{ 0x40000000, "0x1.0p1" },
{ 0x3f000000, "0x1.0p-1" },
{ 0x7f7fffff, "0x1.fffffep127" },
{ 0x00800000, "0x1.0p-126" },
{ 0x00400000, "0x0.8p-127" },
{ 0x00000001, "0x0.000002p-127" },
{ 0, nullptr }
};
for (int j{0}; table[j].expected != nullptr; ++j) {
TEST(Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected)("%d", j);
}
}
template<typename R> void basicTests(int rm, Rounding rounding) {
char desc[64];
using Word = typename R::Word;
@ -354,6 +379,7 @@ void roundTest(int rm, Rounding rounding, std::uint32_t opds) {
}
int main() {
dumpTest();
std::uint32_t opds{512}; // for quick testing by default
if (const char *p{std::getenv("REAL_TEST_OPERANDS")}) {
// Use 8192 or 16384 for more exhaustive testing.