// 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 "../../lib/evaluate/integer.h" #include "testing.h" #include #include using Fortran::evaluate::Ordering; using Fortran::evaluate::value::Integer; template> void exhaustiveTesting() { std::uint64_t maxUnsignedValue{(std::uint64_t{1} << BITS) - 1}; std::int64_t maxPositiveSignedValue{(std::int64_t{1} << (BITS - 1)) - 1}; std::int64_t mostNegativeSignedValue{-(std::int64_t{1} << (BITS - 1))}; char desc[64]; std::snprintf(desc, sizeof desc, "BITS=%d, PARTBITS=%d, sizeof(Part)=%d, LE=%d", BITS, INT::partBits, static_cast(sizeof(typename INT::Part)), INT::littleEndian); MATCH(BITS, INT::bits)(desc); MATCH(maxPositiveSignedValue, INT::HUGE().ToUInt64())(desc); INT zero; TEST(zero.IsZero())(desc); MATCH(0, zero.ToUInt64())(desc); MATCH(0, zero.ToInt64())(desc); for (std::uint64_t x{0}; x <= maxUnsignedValue; ++x) { unsigned long long ullx = x; INT a{x}; MATCH(x, a.ToUInt64())(desc); INT copy{a}; MATCH(x, copy.ToUInt64())(desc); copy = a; MATCH(x, copy.ToUInt64())(desc); MATCH(x == 0, a.IsZero())("%s, x=0x%llx", desc, x); char buffer[64]; std::snprintf(buffer, sizeof buffer, " %llu", ullx); const char *p{buffer}; auto 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::snprintf(buffer, sizeof buffer, "%llx", ullx); p = buffer; 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); 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()}; MATCH(x == std::uint64_t{1} << (BITS - 1), negated.overflow) ("%s, x=0x%llx", desc, x); MATCH(-x & maxUnsignedValue, negated.value.ToUInt64()) ("%s, x=0x%llx", desc, x); auto abs{a.ABS()}; MATCH(x == std::uint64_t{1} << (BITS - 1), abs.overflow) ("%s, x=0x%llx", desc, x); MATCH(x >> (BITS - 1) ? -x & maxUnsignedValue : x, abs.value.ToUInt64()) ("%s, x=0x%llx", desc, x); int lzbc{a.LEADZ()}; COMPARE(lzbc, >=, 0)("%s, x=0x%llx", desc, x); COMPARE(lzbc, <=, BITS)("%s, x=0x%llx", desc, x); MATCH(x == 0, lzbc == BITS)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc); 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); int popcheck{0}; for (int j{0}; j < BITS; ++j) { popcheck += (x >> j) & 1; } MATCH(popcheck, a.POPCNT())("%s, x=0x%llx", desc, x); MATCH(popcheck & 1, a.POPPAR())("%s, x=0x%llx", desc, x); int trailcheck{0}; for (; trailcheck < BITS; ++trailcheck) { if ((x >> trailcheck) & 1) { break; } } MATCH(trailcheck, a.TRAILZ())("%s, x=0x%llx", desc, x); for (int j{0}; j < BITS; ++j) { MATCH((x >> j) & 1, a.BTEST(j)) ("%s, x=0x%llx, bit %d", desc, x, j); } // TODO test DIM, MODULO, ISHFTC, DSHIFTL/R // TODO test IBCLR, IBSET, IBITS, MAX, MIN, MERGE_BITS, RANGE, SIGN 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) { t = a.SHIFTL(count); MATCH((x << count) & maxUnsignedValue, t.ToUInt64()) ("%s, x=0x%llx, count=%d", desc, x, count); t = a.ISHFT(count); MATCH((x << count) & maxUnsignedValue, t.ToUInt64()) ("%s, x=0x%llx, count=%d", desc, x, count); t = a.SHIFTR(count); MATCH(x >> count, t.ToUInt64()) ("%s, x=0x%llx, count=%d", desc, x, count); t = a.ISHFT(-count); MATCH(x >> count, t.ToUInt64())("%s, x=0x%llx, count=%d", desc, x, count); t = a.SHIFTA(count); std::uint64_t fill{-(x >> (BITS - 1))}; std::uint64_t sra{ count >= BITS ? fill : (x >> count) | (fill << (BITS - count))}; MATCH(sra, t.ToInt64()) ("%s, x=0x%llx, count=%d", desc, x, count); } 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); } INT 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); MATCH(x >= y, a.BGE(b))("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(x > y, a.BGT(b))("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(x <= y, a.BLE(b))("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(x < y, a.BLT(b))("%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; } TEST(a.CompareSigned(b) == ord) ("%s, x=0x%llx %lld %d, y=0x%llx %lld %d", desc, x, sx, a.IsNegative(), y, sy, b.IsNegative()); 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()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH( sx + sy < mostNegativeSignedValue || sx + sy > maxPositiveSignedValue, ssum.overflow) ("%s, x=0x%llx, y=0x%llx", desc, x, y); auto diff{a.SubtractSigned(b)}; MATCH((sx - sy) & maxUnsignedValue, diff.value.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH( sx - sy < mostNegativeSignedValue || sx - sy > maxPositiveSignedValue, diff.overflow) ("%s, x=0x%llx, y=0x%llx", desc, x, y); auto product{a.MultiplyUnsigned(b)}; MATCH( x * y, (product.upper.ToUInt64() << BITS) ^ product.lower.ToUInt64()) ("%s, x=0x%llx, y=0x%llx, lower=0x%llx, upper=0x%llx", desc, x, y, product.lower.ToUInt64(), product.upper.ToUInt64()); product = a.MultiplySigned(b); MATCH((sx * sy) & maxUnsignedValue, product.lower.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(((sx * sy) >> BITS) & maxUnsignedValue, product.upper.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); auto quot{a.DivideUnsigned(b)}; MATCH(y == 0, quot.divisionByZero)("%s, x=0x%llx, y=0x%llx", desc, x, y); if (y == 0) { MATCH(maxUnsignedValue, quot.quotient.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(0, quot.remainder.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } else { MATCH(x / y, quot.quotient.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(x % y, quot.remainder.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } quot = a.DivideSigned(b); bool badCase{sx == mostNegativeSignedValue && ((sy == -1 && sx != sy) || (BITS == 1 && sx == sy))}; MATCH(y == 0, quot.divisionByZero)("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(badCase, quot.overflow)("%s, x=0x%llx, y=0x%llx", desc, x, y); if (y == 0) { if (sx >= 0) { MATCH(maxPositiveSignedValue, quot.quotient.ToInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } else { MATCH(mostNegativeSignedValue, quot.quotient.ToInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } MATCH(0, quot.remainder.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } else if (badCase) { MATCH(x, quot.quotient.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); MATCH(0, quot.remainder.ToUInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } else { MATCH(sx / sy, quot.quotient.ToInt64()) ("%s, x=0x%llx %lld, y=0x%llx %lld; unsigned 0x%llx", desc, x, sx, y, sy, quot.quotient.ToUInt64()); MATCH(sx - sy * (sx / sy), quot.remainder.ToInt64()) ("%s, x=0x%llx, y=0x%llx", desc, x, y); } } } } 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"); std::uint64_t big{0x123456789abcdef}; TEST(Integer<128>{big}.Hexadecimal() == "123456789abcdef"); exhaustiveTesting<1>(); exhaustiveTesting<2>(); exhaustiveTesting<7>(); exhaustiveTesting<8>(); exhaustiveTesting<9>(); exhaustiveTesting<9, Integer<9, true, 1>>(); exhaustiveTesting<9, Integer<9, true, 1, std::uint8_t, std::uint16_t>>(); exhaustiveTesting<9, Integer<9, true, 2>>(); exhaustiveTesting<9, Integer<9, true, 2, std::uint8_t, std::uint16_t>>(); exhaustiveTesting<9, Integer<9, true, 8, std::uint8_t, std::uint16_t>>(); exhaustiveTesting<9, Integer<9, false, 8, std::uint8_t, std::uint16_t>>(); return testing::Complete(); }