forked from OSchip/llvm-project
[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:
parent
2348d593ae
commit
dc4fac5634
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue