[flang] Testing and debugging

Original-commit: flang-compiler/f18@3fa2e55bef
Reviewed-on: https://github.com/flang-compiler/f18/pull/785
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-10-21 14:14:38 -07:00
parent 2348d593ae
commit dc4fac5634
7 changed files with 207 additions and 37 deletions

View File

@ -14,7 +14,7 @@
add_subdirectory(burnside)
add_subdirectory(common)
add_subdirectory(decimal)
add_subdirectory(evaluate)
add_subdirectory(decimal)
add_subdirectory(parser)
add_subdirectory(semantics)

View File

@ -12,12 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Portable 128-bit unsigned integer arithmetic
// Portable 128-bit unsigned integer arithmetic for use in impoverished
// C++ implementations lacking __uint128_t.
#ifndef FORTRAN_COMMON_UINT128_H_
#define FORTRAN_COMMON_UINT128_H_
#define AVOID_NATIVE_UINT128 1 // for testing purposes
#ifndef AVOID_NATIVE_UINT128_T
#define AVOID_NATIVE_UINT128_T 1 // for testing purposes (pmk!)
#endif
#include "leading-zero-bit-count.h"
#include <cstdint>
@ -29,8 +32,12 @@ class UnsignedInt128 {
public:
constexpr UnsignedInt128() {}
constexpr UnsignedInt128(std::uint64_t n) : low_{n} {}
constexpr UnsignedInt128(std::int64_t n) : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(n<0)} {}
constexpr UnsignedInt128(int n) : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(n<0)} {}
constexpr UnsignedInt128(std::int64_t n)
: low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
n < 0)} {}
constexpr UnsignedInt128(int n)
: low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
n < 0)} {}
constexpr UnsignedInt128(const UnsignedInt128 &) = default;
constexpr UnsignedInt128(UnsignedInt128 &&) = default;
constexpr UnsignedInt128 &operator=(const UnsignedInt128 &) = default;
@ -79,6 +86,8 @@ public:
constexpr UnsignedInt128 operator<<(UnsignedInt128 that) const {
if (that >= 128) {
return {};
} else if (that == 0) {
return *this;
} else {
std::uint64_t n{that.low_};
if (n >= 64) {
@ -91,6 +100,8 @@ public:
constexpr UnsignedInt128 operator>>(UnsignedInt128 that) const {
if (that >= 128) {
return {};
} else if (that == 0) {
return *this;
} else {
std::uint64_t n{that.low_};
if (n >= 64) {
@ -119,18 +130,21 @@ public:
UnsignedInt128 x1y0{x1 * y0}, x1y1{x1 * y1};
return x0y0 + ((x0y1 + x1y0) << 32) + (x1y1 << 64);
} else {
std::uint64_t x0{low_ & mask32}, x1{low_ >> 32}, x2{high_ & mask32}, x3{high_ >> 32};
std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32}, y2{that.high_ & mask32}, y3{that.high_ >> 32};
std::uint64_t x0{low_ & mask32}, x1{low_ >> 32}, x2{high_ & mask32},
x3{high_ >> 32};
std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32},
y2{that.high_ & mask32}, y3{that.high_ >> 32};
UnsignedInt128 x0y0{x0 * y0}, x0y1{x0 * y1}, x0y2{x0 * y2}, x0y3{x0 * y3};
UnsignedInt128 x1y0{x1 * y0}, x1y1{x1 * y1}, x1y2{x1 * y2};
UnsignedInt128 x2y0{x2 * y0}, x2y1{x2 * y1};
UnsignedInt128 x3y0{x3 * y0};
return x0y0 + ((x0y1 + x1y0) << 32) + ((x0y2 + x1y1 + x2y0) << 64) + ((x0y3 + x1y2 + x2y1 + x3y0) << 96);
return x0y0 + ((x0y1 + x1y0) << 32) + ((x0y2 + x1y1 + x2y0) << 64) +
((x0y3 + x1y2 + x2y1 + x3y0) << 96);
}
}
constexpr UnsignedInt128 operator/(UnsignedInt128 that) const {
int j{high_ == 0 ? 64 + LeadingZeroBitCount(low_) : LeadingZeroBitCount(high_)};
int j{LeadingZeroes()};
UnsignedInt128 bits{*this};
bits <<= j;
UnsignedInt128 numerator{};
@ -151,7 +165,7 @@ public:
}
constexpr UnsignedInt128 operator%(UnsignedInt128 that) const {
int j{high_ == 0 ? 64 + LeadingZeroBitCount(low_) : LeadingZeroBitCount(high_)};
int j{LeadingZeroes()};
UnsignedInt128 bits{*this};
bits <<= j;
UnsignedInt128 remainder{};
@ -180,12 +194,8 @@ public:
constexpr bool operator!=(UnsignedInt128 that) const {
return !(*this == that);
}
constexpr bool operator>=(UnsignedInt128 that) const {
return that <= *this;
}
constexpr bool operator>(UnsignedInt128 that) const {
return that < *this;
}
constexpr bool operator>=(UnsignedInt128 that) const { return that <= *this; }
constexpr bool operator>(UnsignedInt128 that) const { return that < *this; }
constexpr UnsignedInt128 &operator&=(const UnsignedInt128 &that) {
*this = *this & that;
@ -229,12 +239,22 @@ public:
}
private:
constexpr UnsignedInt128(std::uint64_t hi, std::uint64_t lo) : low_{lo}, high_{hi} {}
constexpr UnsignedInt128(std::uint64_t hi, std::uint64_t lo)
: low_{lo}, high_{hi} {}
constexpr int LeadingZeroes() const {
if (high_ == 0) {
return 64 + LeadingZeroBitCount(low_);
} else {
return LeadingZeroBitCount(high_);
}
}
static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
std::uint64_t low_{0}, high_{0};
};
#if (defined __GNUC__ || defined __clang__) && defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128
#if AVOID_NATIVE_UINT128_T
using uint128_t = UnsignedInt128;
#elif (defined __GNUC__ || defined __clang__) && defined __SIZEOF_INT128__
using uint128_t = __uint128_t;
#else
using uint128_t = UnsignedInt128;

View File

@ -68,10 +68,10 @@ static_assert(FixedPointReciprocal<std::uint64_t>::For(10).Divide(
template<typename UINT, std::uint64_t DENOM>
inline constexpr UINT DivideUnsignedBy(UINT n) {
if constexpr (!std::is_same_v<UINT, uint128_t>) {
return FixedPointReciprocal<UINT>::For(DENOM).Divide(n);
} else {
if constexpr (std::is_same_v<UINT, uint128_t>) {
return n / static_cast<UINT>(DENOM);
} else {
return FixedPointReciprocal<UINT>::For(DENOM).Divide(n);
}
}
}

View File

@ -143,7 +143,7 @@ private:
return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10;
}
// Set to an unsigned integer value.
// Sets *this to an unsigned integer value.
// Returns any remainder.
template<typename UINT> UINT SetTo(UINT n) {
static_assert(

View File

@ -55,12 +55,14 @@ template<int PRECISION> struct BinaryFloatingPointNumber {
static constexpr int RANGE{static_cast<int>(
(exponentBias - 1) * ScaledLogBaseTenOfTwo / 1000000000000)};
BinaryFloatingPointNumber() {} // zero
BinaryFloatingPointNumber(const BinaryFloatingPointNumber &that) = default;
BinaryFloatingPointNumber(BinaryFloatingPointNumber &&that) = default;
BinaryFloatingPointNumber &operator=(
constexpr BinaryFloatingPointNumber() {} // zero
constexpr BinaryFloatingPointNumber(
const BinaryFloatingPointNumber &that) = default;
BinaryFloatingPointNumber &operator=(
constexpr BinaryFloatingPointNumber(
BinaryFloatingPointNumber &&that) = default;
constexpr BinaryFloatingPointNumber &operator=(
const BinaryFloatingPointNumber &that) = default;
constexpr BinaryFloatingPointNumber &operator=(
BinaryFloatingPointNumber &&that) = default;
template<typename A> explicit constexpr BinaryFloatingPointNumber(A x) {

View File

@ -23,8 +23,6 @@ add_executable(leading-zero-bit-count-test
target_link_libraries(leading-zero-bit-count-test
FortranEvaluateTesting
FortranEvaluate
FortranSemantics
)
add_executable(bit-population-count-test
@ -33,10 +31,21 @@ add_executable(bit-population-count-test
target_link_libraries(bit-population-count-test
FortranEvaluateTesting
FortranEvaluate
FortranSemantics
)
add_executable(uint128-test
uint128.cc
)
target_link_libraries(uint128-test
FortranEvaluateTesting
)
# These routines live in lib/common but we test them here.
add_test(UINT128 uint128-test)
add_test(Leadz leading-zero-bit-count-test)
add_test(PopPar bit-population-count-test)
add_executable(expression-test
expression.cc
)
@ -55,7 +64,6 @@ add_executable(integer-test
target_link_libraries(integer-test
FortranEvaluateTesting
FortranEvaluate
FortranSemantics
)
add_executable(intrinsics-test
@ -77,8 +85,6 @@ add_executable(logical-test
target_link_libraries(logical-test
FortranEvaluateTesting
FortranEvaluate
FortranSemantics
)
# GCC -fno-exceptions breaks the fenv.h interfaces needed to capture
@ -141,10 +147,7 @@ set(FOLDING_TESTS
folding08.f90
)
add_test(Expression expression-test)
add_test(Leadz leading-zero-bit-count-test)
add_test(PopPar bit-population-count-test)
add_test(Integer integer-test)
add_test(Intrinsics intrinsics-test)
add_test(Logical logical-test)

View File

@ -0,0 +1,145 @@
// 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.
#define AVOID_NATIVE_UINT128_T 1
#include "../../lib/common/uint128.h"
#include "testing.h"
#include <cinttypes>
#include <iostream>
#if (defined __GNUC__ || defined __clang__) && defined __SIZEOF_INT128__
# define HAS_NATIVE_UINT128_T 1
#else
# undef HAS_NATIVE_UINT128_T
#endif
using U128 = Fortran::common::UnsignedInt128;
static void Test(std::uint64_t x) {
U128 n{x};
MATCH(x, static_cast<std::uint64_t>(n));
MATCH(~x, static_cast<std::uint64_t>(~n));
MATCH(-x, static_cast<std::uint64_t>(-n));
MATCH(!x, static_cast<std::uint64_t>(!n));
TEST(n == n);
TEST(n + n == n * static_cast<U128>(2));
TEST(n - n == static_cast<U128>(0));
TEST(n + n == n << static_cast<U128>(1));
TEST(n + n == n << static_cast<U128>(1));
TEST((n + n) - n == n);
TEST(((n + n) >> static_cast<U128>(1)) == n);
if (x != 0) {
TEST(static_cast<U128>(0) / n == static_cast<U128>(0));
TEST(static_cast<U128>(n - 1) / n == static_cast<U128>(0));
TEST(static_cast<U128>(n) / n == static_cast<U128>(1));
TEST(static_cast<U128>(n + n - 1) / n == static_cast<U128>(1));
TEST(static_cast<U128>(n + n) / n == static_cast<U128>(2));
}
}
static void Test(std::uint64_t x, std::uint64_t y) {
U128 m{x}, n{y};
MATCH(x, static_cast<std::uint64_t>(m));
MATCH(y, static_cast<std::uint64_t>(n));
MATCH(x & y, static_cast<std::uint64_t>(m & n));
MATCH(x | y, static_cast<std::uint64_t>(m | n));
MATCH(x ^ y, static_cast<std::uint64_t>(m ^ n));
MATCH(x + y, static_cast<std::uint64_t>(m + n));
MATCH(x - y, static_cast<std::uint64_t>(m - n));
MATCH(x * y, static_cast<std::uint64_t>(m * n));
if (n != 0) {
MATCH(x / y, static_cast<std::uint64_t>(m / n));
}
}
#if HAS_NATIVE_UINT128_T
static __uint128_t ToNative(U128 n) {
return static_cast<__uint128_t>(static_cast<std::uint64_t>(n >> 64)) << 64 | static_cast<std::uint64_t>(n);
}
static U128 FromNative(__uint128_t n) {
return U128{static_cast<std::uint64_t>(n >> 64)} << 64 | U128{static_cast<std::uint64_t>(n)};
}
static void TestVsNative(__uint128_t x, __uint128_t y) {
U128 m{FromNative(x)}, n{FromNative(y)};
TEST(ToNative(m) == x);
TEST(ToNative(n) == y);
TEST(ToNative(~m) == ~x);
TEST(ToNative(-m) == -x);
TEST(ToNative(!m) == !x);
TEST(ToNative(m < n) == (x < y));
TEST(ToNative(m <= n) == (x <= y));
TEST(ToNative(m == n) == (x == y));
TEST(ToNative(m != n) == (x != y));
TEST(ToNative(m >= n) == (x >= y));
TEST(ToNative(m > n) == (x > y));
TEST(ToNative(m & n) == (x & y));
TEST(ToNative(m | n) == (x | y));
TEST(ToNative(m ^ n) == (x ^ y));
if (y < 128) {
TEST(ToNative(m << n) == (x << y));
TEST(ToNative(m >> n) == (x >> y));
}
TEST(ToNative(m + n) == (x + y));
TEST(ToNative(m - n) == (x - y));
TEST(ToNative(m * n) == (x * y));
if (y > 0) {
TEST(ToNative(m / n) == (x / y));
TEST(ToNative(m % n) == (x % y));
TEST(ToNative(m - n * (m / n)) == (x / y));
}
}
static void TestVsNative() {
for (int j{0}; j < 128; ++j) {
for (int k{0}; k < 128; ++k) {
__uint128_t m{1}, n{1};
m <<= j, n <<= k;
TestVsNative(m, n);
TestVsNative(~m, n);
TestVsNative(m, ~n);
TestVsNative(~m, ~n);
TestVsNative(m ^ n, n);
TestVsNative(m, m ^ n);
TestVsNative(m ^ ~n, n);
TestVsNative(m, ~m ^ n);
TestVsNative(m ^ ~n, m ^ n);
TestVsNative(m ^ n, ~m ^ n);
TestVsNative(m ^ ~n, ~m ^ n);
Test(m, 10000000000000000); // important case for decimal conversion
Test(~m, 10000000000000000);
}
}
}
#endif
int main() {
for (std::uint64_t j{0}; j < 64; ++j) {
Test(j);
Test(~j);
Test(std::uint64_t(1) << j);
for (std::uint64_t k{0}; k < 64; ++k) {
Test(j, k);
}
}
#if HAS_NATIVE_UINT128_T
std::cout << "Environment has native __uint128_t\n";
TestVsNative();
#else
std::cout << "Environment lacks native __uint128_t\n";
#endif
testing::Complete();
}