2018-05-31 01:08:42 +02:00
|
|
|
// Copyright (c) 2018, 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 "testing.h"
|
2018-05-31 01:09:52 +02:00
|
|
|
#include "../../lib/evaluate/fixed-point.h"
|
2018-05-31 01:08:42 +02:00
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
using Fortran::evaluate::FixedPoint;
|
2018-05-31 01:09:52 +02:00
|
|
|
using Fortran::evaluate::Ordering;
|
2018-05-31 01:08:42 +02:00
|
|
|
|
2018-05-31 01:09:52 +02:00
|
|
|
template<int BITS, typename FP = FixedPoint<BITS>> void exhaustiveTesting() {
|
2018-05-31 01:08:42 +02:00
|
|
|
COMPARE(BITS, ==, FP::bits);
|
|
|
|
std::uint64_t maxUnsignedValue{(std::uint64_t{1} << BITS) - 1};
|
|
|
|
std::int64_t maxPositiveSignedValue{(std::int64_t{1} << (BITS - 1)) - 1};
|
2018-05-31 01:09:52 +02:00
|
|
|
std::int64_t mostNegativeSignedValue{-(std::int64_t{1} << (BITS - 1))};
|
2018-05-31 01:08:42 +02:00
|
|
|
char desc[64];
|
2018-05-31 18:44:27 +02:00
|
|
|
std::snprintf(desc, sizeof desc, "BITS=%d, PARTBITS=%d, sizeof(Part)=%d, LE=%d",
|
|
|
|
BITS, FP::partBits, static_cast<int>(sizeof(typename FP::Part)),
|
|
|
|
FP::littleEndian);
|
2018-05-31 01:08:42 +02:00
|
|
|
FP zero;
|
|
|
|
TEST(zero.IsZero())(desc);
|
|
|
|
for (std::uint64_t x{0}; x <= maxUnsignedValue; ++x) {
|
|
|
|
FP a{x};
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(x, a.ToUInt64())(desc);
|
2018-05-31 01:08:42 +02:00
|
|
|
FP copy{a};
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(x, copy.ToUInt64())(desc);
|
2018-05-31 01:08:42 +02:00
|
|
|
copy = a;
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(x, copy.ToUInt64())(desc);
|
|
|
|
MATCH(x == 0, a.IsZero())("%s, x=0x%llx", desc, x);
|
|
|
|
FP t{a.NOT()};
|
|
|
|
MATCH(x ^ maxUnsignedValue, t.ToUInt64())("%s, x=0x%llx", desc, x);
|
|
|
|
auto negated{a.Negate()};
|
|
|
|
MATCH(x == std::uint64_t{1} << (BITS - 1), negated.overflow)
|
|
|
|
("%s, x=0x%llx", desc, x);
|
|
|
|
MATCH(negated.value.ToUInt64(), -x & maxUnsignedValue)
|
|
|
|
("%s, x=0x%llx", desc, x);
|
2018-05-31 20:18:14 +02:00
|
|
|
int lzbc{a.LEADZ()};
|
2018-05-31 01:08:42 +02:00
|
|
|
COMPARE(lzbc, >=, 0)("%s, x=0x%llx", desc, x);
|
|
|
|
COMPARE(lzbc, <=, BITS)("%s, x=0x%llx", desc, x);
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(x == 0, lzbc == BITS)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
|
2018-05-31 01:08:42 +02:00
|
|
|
std::uint64_t lzcheck{std::uint64_t{1} << (BITS - lzbc)};
|
|
|
|
COMPARE(x, <, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
|
|
|
|
COMPARE(x + x + !x, >=, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
|
|
|
|
Ordering ord{Ordering::Equal};
|
|
|
|
std::int64_t sx = x;
|
|
|
|
if (x + x > maxUnsignedValue) {
|
|
|
|
TEST(a.IsNegative())("%s, x=0x%llx", desc, x);
|
|
|
|
sx = x | (~std::uint64_t{0} << BITS);
|
|
|
|
TEST(sx < 0)("%s, x=0x%llx %lld", desc, x, sx);
|
|
|
|
ord = Ordering::Less;
|
|
|
|
} else {
|
|
|
|
TEST(!a.IsNegative())("%s, x=0x%llx", desc, x);
|
|
|
|
TEST(sx >= 0)("%s, x=0x%llx %lld", desc, x, sx);
|
|
|
|
if (sx > 0) {
|
|
|
|
ord = Ordering::Greater;
|
|
|
|
} else {
|
|
|
|
ord = Ordering::Equal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TEST(sx == a.ToInt64())("%s, x=0x%llx %lld", desc, x, sx);
|
|
|
|
TEST(a.CompareToZeroSigned() == ord)("%s, x=0x%llx %lld", desc, x, sx);
|
|
|
|
for (int count{0}; count <= BITS + 1; ++count) {
|
2018-05-31 20:18:14 +02:00
|
|
|
t = a.SHIFTL(count);
|
|
|
|
MATCH((x << count) & maxUnsignedValue, t.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, count=%d", desc, x, count);
|
2018-05-31 20:18:14 +02:00
|
|
|
t = a.ISHFT(count);
|
|
|
|
MATCH((x << count) & maxUnsignedValue, t.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, count=%d", desc, x, count);
|
2018-05-31 20:18:14 +02:00
|
|
|
t = a.SHIFTR(count);
|
|
|
|
MATCH(x >> count, t.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, count=%d", desc, x, count);
|
2018-05-31 20:18:14 +02:00
|
|
|
t = a.ISHFT(-count);
|
|
|
|
MATCH(x >> count, t.ToUInt64())("%s, x=0x%llx, count=%d", desc, x, count);
|
|
|
|
t = a.SHIFTA(count);
|
2018-05-31 18:44:27 +02:00
|
|
|
std::uint64_t fill{-(x >> (BITS-1))};
|
|
|
|
std::uint64_t sra{count >= BITS ? fill : (x >> count) | (fill << (BITS-count))};
|
2018-05-31 20:18:14 +02:00
|
|
|
MATCH(sra, t.ToInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, count=%d", desc, x, count);
|
2018-05-31 01:08:42 +02:00
|
|
|
}
|
|
|
|
for (std::uint64_t y{0}; y <= maxUnsignedValue; ++y) {
|
|
|
|
std::int64_t sy = y;
|
|
|
|
if (y + y > maxUnsignedValue) {
|
|
|
|
sy = y | (~std::uint64_t{0} << BITS);
|
|
|
|
}
|
|
|
|
FP b{y};
|
|
|
|
if (x < y) {
|
|
|
|
ord = Ordering::Less;
|
|
|
|
} else if (x > y) {
|
|
|
|
ord = Ordering::Greater;
|
|
|
|
} else {
|
|
|
|
ord = Ordering::Equal;
|
|
|
|
}
|
|
|
|
TEST(a.CompareUnsigned(b) == ord)("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
if (sx < sy) {
|
|
|
|
ord = Ordering::Less;
|
|
|
|
} else if (sx > sy) {
|
|
|
|
ord = Ordering::Greater;
|
|
|
|
} else {
|
|
|
|
ord = Ordering::Equal;
|
|
|
|
}
|
2018-05-31 01:09:52 +02:00
|
|
|
TEST(a.CompareSigned(b) == ord)
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx %lld %d, y=0x%llx %lld %d", desc, x, sx,
|
|
|
|
a.IsNegative(), y, sy, b.IsNegative());
|
2018-05-31 20:58:50 +02:00
|
|
|
t = a.IAND(b);
|
|
|
|
MATCH(x & y, t.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
t = a.IOR(b);
|
|
|
|
MATCH(x | y, t.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
t = a.IEOR(b);
|
|
|
|
MATCH(x ^ y, t.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
auto sum{a.AddUnsigned(b)};
|
|
|
|
COMPARE(x + y, ==, sum.value.ToUInt64() + (std::uint64_t{sum.carry} << BITS))
|
|
|
|
("%s, x=0x%llx, y=0x%llx, carry=%d", desc, x, y, sum.carry);
|
|
|
|
auto ssum{a.AddSigned(b)};
|
|
|
|
MATCH((sx + sy) & maxUnsignedValue, ssum.value.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 20:58:50 +02:00
|
|
|
MATCH(sx + sy < mostNegativeSignedValue ||
|
|
|
|
sx + sy > maxPositiveSignedValue, ssum.overflow)
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 20:58:50 +02:00
|
|
|
auto diff{a.SubtractSigned(b)};
|
|
|
|
MATCH((sx - sy) & maxUnsignedValue, diff.value.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 20:58:50 +02:00
|
|
|
MATCH(sx - sy < mostNegativeSignedValue ||
|
|
|
|
sx - sy > maxPositiveSignedValue, diff.overflow)
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 20:58:50 +02:00
|
|
|
auto product{a.MultiplyUnsigned(b)};
|
|
|
|
MATCH(x * y, (product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx, lower=0x%llx, upper=0x%llx", desc, x, y,
|
2018-05-31 20:58:50 +02:00
|
|
|
product.lower.ToUInt64(), product.upper.ToUInt64());
|
|
|
|
product = a.MultiplySigned(b);
|
|
|
|
MATCH((sx * sy) & maxUnsignedValue, product.lower.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 20:58:50 +02:00
|
|
|
MATCH(((sx * sy) >> BITS) & maxUnsignedValue, product.upper.ToUInt64())
|
2018-05-31 19:45:41 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
copy = a;
|
|
|
|
FP rem;
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(y == 0, copy.DivideUnsigned(b, rem))
|
2018-05-31 01:09:52 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 19:45:41 +02:00
|
|
|
if (y == 0) {
|
|
|
|
MATCH(maxUnsignedValue, copy.ToUInt64())
|
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
MATCH(0, rem.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
} else {
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(x / y, copy.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
MATCH(x % y, rem.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
}
|
|
|
|
copy = a;
|
|
|
|
bool badCase{sx == mostNegativeSignedValue &&
|
2018-05-31 01:09:52 +02:00
|
|
|
((sy == -1 && sx != sy) || (BITS == 1 && sx == sy))};
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(y == 0 || badCase, copy.DivideSigned(b, rem))
|
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
if (y == 0) {
|
|
|
|
if (sx >= 0) {
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(maxPositiveSignedValue, copy.ToInt64())
|
2018-05-31 01:09:52 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
} else {
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(mostNegativeSignedValue, copy.ToInt64())
|
2018-05-31 01:09:52 +02:00
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
}
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(0, rem.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
} else if (badCase) {
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(x, copy.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
|
|
|
MATCH(0, rem.ToUInt64())("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
} else {
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(sx / sy, copy.ToInt64())
|
|
|
|
("%s, x=0x%llx %lld, y=0x%llx %lld; unsigned 0x%llx", desc, x, sx, y,
|
2018-05-31 01:09:52 +02:00
|
|
|
sy, copy.ToUInt64());
|
2018-05-31 19:45:41 +02:00
|
|
|
MATCH(sx - sy * (sx / sy), rem.ToInt64())
|
|
|
|
("%s, x=0x%llx, y=0x%llx", desc, x, y);
|
2018-05-31 01:08:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
TEST(Reverse(Ordering::Less) == Ordering::Greater);
|
|
|
|
TEST(Reverse(Ordering::Greater) == Ordering::Less);
|
|
|
|
TEST(Reverse(Ordering::Equal) == Ordering::Equal);
|
|
|
|
exhaustiveTesting<1>();
|
|
|
|
exhaustiveTesting<2>();
|
|
|
|
exhaustiveTesting<7>();
|
|
|
|
exhaustiveTesting<8>();
|
|
|
|
exhaustiveTesting<9>();
|
|
|
|
exhaustiveTesting<9, FixedPoint<9, 1>>();
|
|
|
|
exhaustiveTesting<9, FixedPoint<9, 1, std::uint8_t, std::uint16_t>>();
|
|
|
|
exhaustiveTesting<9, FixedPoint<9, 2>>();
|
|
|
|
exhaustiveTesting<9, FixedPoint<9, 2, std::uint8_t, std::uint16_t>>();
|
|
|
|
exhaustiveTesting<9, FixedPoint<9, 8, std::uint8_t, std::uint16_t>>();
|
2018-05-31 18:44:27 +02:00
|
|
|
exhaustiveTesting<9, FixedPoint<9, 8, std::uint8_t, std::uint16_t, false>>();
|
2018-05-31 01:08:42 +02:00
|
|
|
return testing::Complete();
|
|
|
|
}
|