forked from OSchip/llvm-project
[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:
parent
3d867f3202
commit
9e1ba097f5
|
@ -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); }
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue