[flang] Begin adding tests

Original-commit: flang-compiler/f18@8776d8b663
Reviewed-on: https://github.com/flang-compiler/f18/pull/671
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-08-14 15:25:16 -07:00
parent 9cdb101a4d
commit afda616c31
7 changed files with 192 additions and 22 deletions

View File

@ -43,10 +43,11 @@ static constexpr std::uint64_t TenToThe(int power) {
// even, so that pairs of decimal digits do not straddle Digits.
// So LOG10RADIX must be 16 or 6.
template<int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
private:
public:
using Real = BinaryFloatingPointNumber<PREC>;
static constexpr int log10Radix{LOG10RADIX};
private:
static constexpr std::uint64_t uint64Radix{TenToThe(log10Radix)};
static constexpr int minDigitBits{
64 - common::LeadingZeroBitCount(uint64Radix)};
@ -103,8 +104,8 @@ public:
private:
BigRadixFloatingPointNumber(const BigRadixFloatingPointNumber &that)
: digits_{that.digits_}, exponent_{that.exponent_}, isNegative_{
that.isNegative_} {
: digits_{that.digits_}, exponent_{that.exponent_},
isNegative_{that.isNegative_}, rounding_{that.rounding_} {
for (int j{0}; j < digits_; ++j) {
digit_[j] = that.digit_[j];
}

View File

@ -21,13 +21,14 @@ template<int PREC, int LOG10RADIX>
BigRadixFloatingPointNumber<PREC, LOG10RADIX>::BigRadixFloatingPointNumber(
BinaryFloatingPointNumber<PREC> x, enum FortranRounding rounding)
: rounding_{rounding} {
if (x.IsNegative() < 0) {
isNegative_ = true;
x.Negate();
}
bool negative{x.IsNegative()};
if (x.IsZero()) {
isNegative_ = negative;
return;
}
if (negative) {
x.Negate();
}
int twoPow{x.UnbiasedExponent()};
twoPow -= x.bits - 1;
if (!x.implicitMSB) {
@ -44,6 +45,7 @@ BigRadixFloatingPointNumber<PREC, LOG10RADIX>::BigRadixFloatingPointNumber(
auto word{x.Fraction()};
word <<= lshift;
SetTo(word);
isNegative_ = negative;
// The significand is now encoded in *this as an integer (D) and
// decimal exponent (E): x = D * 10.**E * 2.**twoPow
@ -297,9 +299,9 @@ ConversionToDecimalResult ConvertToDecimal(char *buffer, size_t size, int flags,
if (x.IsNaN()) {
return {"NaN", 3, 0, Invalid};
} else if (x.IsInfinite()) {
return {x.IsNegative() ? "-Inf" : "+Inf", 4, 0, Exact};
return {x.IsNegative() ? "-Inf" : (flags & AlwaysSign) ? "+Inf" : "Inf", 4,
0, Exact};
} else {
using Binary = BinaryFloatingPointNumber<PREC>;
using Big = BigRadixFloatingPointNumber<PREC>;
Big number{x, rounding};
if ((flags & Minimize) && !x.IsZero()) {
@ -311,6 +313,7 @@ ConversionToDecimalResult ConvertToDecimal(char *buffer, size_t size, int flags,
// the bounds of the range of decimal values that will map back to the
// original binary value, and find a (not necessary unique) shortest
// decimal sequence in that range.
using Binary = typename Big::Real;
Binary less{x};
--less.raw;
Binary more{x};

View File

@ -409,3 +409,26 @@ template ConversionToBinaryResult<112> ConvertToBinary<112>(
const char *&, enum FortranRounding);
}
extern "C" {
ConversionResultFlags ConvertDecimalToFloat(
const char **p, float *f, enum FortranRounding rounding) {
auto result{Fortran::decimal::ConvertToBinary<24>(*p, rounding)};
*f = *reinterpret_cast<const float *>(&result.binary);
return result.flags;
}
ConversionResultFlags ConvertDecimalToDouble(
const char **p, double *d, enum FortranRounding rounding) {
auto result{Fortran::decimal::ConvertToBinary<53>(*p, rounding)};
*d = *reinterpret_cast<const double *>(&result.binary);
return result.flags;
}
#if __x86_64__
ConversionResultFlags ConvertDecimalToLongDouble(
const char **p, long double *ld, enum FortranRounding rounding) {
auto result{Fortran::decimal::ConvertToBinary<64>(*p, rounding)};
*ld = *reinterpret_cast<const long double *>(&result.binary);
return result.flags;
}
#endif
}

View File

@ -67,22 +67,28 @@ enum DecimalConversionFlags {
namespace Fortran::decimal {
template<int PREC>
ConversionToDecimalResult ConvertToDecimal(char *, size_t, int flags,
int digits, enum FortranRounding rounding,
BinaryFloatingPointNumber<PREC> x);
ConversionToDecimalResult ConvertToDecimal(char *, size_t,
enum DecimalConversionFlags flags, int digits,
enum FortranRounding rounding, BinaryFloatingPointNumber<PREC> x);
extern template ConversionToDecimalResult ConvertToDecimal<8>(char *, size_t,
int, int, enum FortranRounding, BinaryFloatingPointNumber<8>);
enum DecimalConversionFlags, int, enum FortranRounding,
BinaryFloatingPointNumber<8>);
extern template ConversionToDecimalResult ConvertToDecimal<11>(char *, size_t,
int, int, enum FortranRounding, BinaryFloatingPointNumber<11>);
enum DecimalConversionFlags, int, enum FortranRounding,
BinaryFloatingPointNumber<11>);
extern template ConversionToDecimalResult ConvertToDecimal<24>(char *, size_t,
int, int, enum FortranRounding, BinaryFloatingPointNumber<24>);
enum DecimalConversionFlags, int, enum FortranRounding,
BinaryFloatingPointNumber<24>);
extern template ConversionToDecimalResult ConvertToDecimal<53>(char *, size_t,
int, int, enum FortranRounding, BinaryFloatingPointNumber<53>);
enum DecimalConversionFlags, int, enum FortranRounding,
BinaryFloatingPointNumber<53>);
extern template ConversionToDecimalResult ConvertToDecimal<64>(char *, size_t,
int, int, enum FortranRounding, BinaryFloatingPointNumber<64>);
enum DecimalConversionFlags, int, enum FortranRounding,
BinaryFloatingPointNumber<64>);
extern template ConversionToDecimalResult ConvertToDecimal<112>(char *, size_t,
int, int, enum FortranRounding, BinaryFloatingPointNumber<112>);
enum DecimalConversionFlags, int, enum FortranRounding,
BinaryFloatingPointNumber<112>);
template<int PREC> struct ConversionToBinaryResult {
BinaryFloatingPointNumber<PREC> binary;
@ -105,7 +111,7 @@ extern template ConversionToBinaryResult<64> ConvertToBinary<64>(
const char *&, enum FortranRounding = RoundNearest);
extern template ConversionToBinaryResult<112> ConvertToBinary<112>(
const char *&, enum FortranRounding = RoundNearest);
} // namespace
}
extern "C" {
#endif /* C++ */
@ -118,7 +124,16 @@ ConversionToDecimalResult ConvertLongDoubleToDecimal(
char *, size_t, int flags, int digits, enum FortranRounding, long double);
#endif
ConversionResultFlags ConvertDecimalToFloat(
const char **, float *, enum FortranRounding);
ConversionResultFlags ConvertDecimalToDouble(
const char **, double *, enum FortranRounding);
#if __x86_64__
ConversionResultFlags ConvertDecimalToLongDouble(
const char **, long double *, enum FortranRounding);
#endif
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* DECIMAL_H_ */
#endif

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -12,5 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
add_subdirectory(decimal)
add_subdirectory(evaluate)
add_subdirectory(semantics)

View File

@ -0,0 +1,39 @@
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
add_executable(quick-sanity-test
quick-sanity-test.cc
)
target_link_libraries(quick-sanity-test
FortranDecimal
)
# add_executable(thorough-test
# thorough-test.cc
# )
# target_link_libraries(thorough-test
# FortranDecimal
# )
# add_executable(benchmark01
# benchmark01.cc
# )
# target_link_libraries(benchmark01
# FortranDecimal
# )
add_test(Sanity quick-sanity-test)

View File

@ -0,0 +1,88 @@
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "../../lib/decimal/decimal.h"
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <iostream>
static int tests{0};
static int fails{0};
std::ostream &failed(float x) {
++fails;
return std::cout << "FAIL: 0x" << std::hex
<< *reinterpret_cast<std::uint32_t *>(&x) << std::dec;
}
void testDirect(float x, const char *expect, int expectExpo) {
char buffer[1024];
++tests;
auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
static_cast<enum DecimalConversionFlags>(0), 1024,
RoundNearest, x)};
if (result.str == nullptr) {
failed(x) << ": no result str\n";
} else if (std::strcmp(result.str, expect) != 0) {
failed(x) << ": expect '" << expect << "', got '" << result.str << "'\n";
} else if (result.decimalExponent != expectExpo) {
failed(x) << ": expect exponent " << expectExpo << ", got "
<< result.decimalExponent << '\n';
}
}
void testReadback(float x) {
char buffer[1024];
++tests;
auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
static_cast<enum DecimalConversionFlags>(0), 1024,
RoundNearest, x)};
if (result.str == nullptr) {
failed(x) << ": no result str\n";
} else {
float y{0};
char *q{const_cast<char *>(result.str)};
std::sprintf(q + result.length, "e%d", static_cast<int>(result.decimalExponent - result.length));
const char *p{q};
auto flags{ConvertDecimalToFloat(&p, &y, RoundNearest)};
if (x != y || *p != '\0' || (flags & Invalid)) {
failed(x) << ": -> '" << buffer << "' -> 0x"
<< std::hex << *reinterpret_cast<std::uint32_t *>(&y)
<< std::dec << " '" << p << "'\n";
}
}
}
int main() {
testDirect(-1.0, "-1", 1);
testDirect(0.0, "0", 0);
testDirect(1.0, "1", 1);
testDirect(2.0, "2", 1);
testDirect(-1.0, "-1", 1);
testDirect(314159, "314159", 6);
testDirect(0.0625, "625", -1);
float x;
std::uint32_t *ix{reinterpret_cast<std::uint32_t *>(&x)};
*ix = 0x80000000;
testDirect(x, "-0", 0);
*ix = 0x7f800000;
testDirect(x, "Inf", 0);
*ix = 0xff800000;
testDirect(x, "-Inf", 0);
*ix = 0xffffffff;
testDirect(x, "NaN", 0);
std::cout << tests << " tests run, " << fails << " tests failed\n";
return fails > 0;
}