static constexpr Part topPartMask{static_cast<Part>(~0) >> extraTopPartBits};
public:
+ struct ValueWithOverflow {
+ Integer value;
+ bool overflow;
+ };
+
+ struct ValueWithCarry {
+ Integer value;
+ bool carry;
+ };
+
+ struct Product {
+ Integer upper, lower;
+ };
+
+ struct QuotientWithRemainder {
+ Integer quotient, remainder;
+ bool divisionByZero, overflow;
+ };
+
// Constructors and value-generating static functions
constexpr Integer() { Clear(); } // default constructor: zero
constexpr Integer(const Integer &) = default;
}
}
+ static constexpr ValueWithOverflow ReadUnsigned(
+ const char *&pp, std::uint64_t base = 10) {
+ Integer result;
+ bool overflow{false};
+ const char *p{pp};
+ while (*p == ' ' || *p == '\t') {
+ ++p;
+ }
+ if (*p == '+') {
+ ++p;
+ }
+ Integer radix{base};
+ for (; unsigned char ch = *p; ++p) {
+ std::uint64_t digit;
+ if (ch >= '0' && ch < '0' + base) {
+ digit = ch - '0';
+ } else if (base > 10 && ch >= 'A' && ch < 'A' + base - 10) {
+ digit = ch - 'A' + 10;
+ } else if (base > 10 && ch >= 'a' && ch < 'a' + base - 10) {
+ digit = ch - 'a' + 10;
+ } else {
+ break;
+ }
+ Product shifted{result.MultiplyUnsigned(radix)};
+ overflow |= !shifted.upper.IsZero();
+ ValueWithCarry next{shifted.lower.AddUnsigned(Integer{digit})};
+ overflow |= next.carry;
+ result = next.value;
+ }
+ pp = p;
+ return {result, overflow};
+ }
+
static constexpr Integer HUGE() { return MASKR(bits - 1); }
// Returns the number of full decimal digits that can be represented.
// Two's-complement negation (-x = ~x + 1).
// An overflow flag accompanies the result, and will be true when the
// operand is the most negative signed number (MASKL(1)).
- struct ValueWithOverflow {
- Integer value;
- bool overflow;
- };
constexpr ValueWithOverflow Negate() const {
Integer result{nullptr};
Part carry{1};
}
// Unsigned addition with carry.
- struct ValueWithCarry {
- Integer value;
- bool carry;
- };
constexpr ValueWithCarry AddUnsigned(
const Integer &y, bool carryIn = false) const {
Integer sum{nullptr};
}
}
- struct Product {
- Integer upper, lower;
- };
constexpr Product MultiplyUnsigned(const Integer &y) const {
Part product[2 * parts]{}; // little-endian full product
for (int j{0}; j < parts; ++j) {
return product;
}
- struct QuotientWithRemainder {
- Integer quotient, remainder;
- bool divisionByZero, overflow;
- };
constexpr QuotientWithRemainder DivideUnsigned(const Integer &divisor) const {
if (divisor.IsZero()) {
return {MASKR(bits), Integer{}, true, false}; // overflow to max value
)
add_executable(leading-zero-bit-count-test
- leading-zero-bit-count-test.cc
+ leading-zero-bit-count.cc
)
target_link_libraries(leading-zero-bit-count-test
)
add_executable(bit-population-count-test
- bit-population-count-test.cc
+ bit-population-count.cc
)
target_link_libraries(bit-population-count-test
)
add_executable(integer-test
- integer-test.cc
+ integer.cc
)
target_link_libraries(integer-test
+++ /dev/null
-// 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"
-#include "../../lib/evaluate/bit-population-count.h"
-
-using Fortran::evaluate::BitPopulationCount;
-using Fortran::evaluate::Parity;
-
-int main() {
- MATCH(0, BitPopulationCount(std::uint64_t{0}));
- MATCH(false, Parity(std::uint64_t{0}));
- MATCH(64, BitPopulationCount(~std::uint64_t{0}));
- MATCH(false, Parity(~std::uint64_t{0}));
- for (int j{0}; j < 64; ++j) {
- std::uint64_t x = std::uint64_t{1} << j;
- MATCH(1, BitPopulationCount(x));
- MATCH(true, Parity(x));
- MATCH(63, BitPopulationCount(~x));
- MATCH(true, Parity(~x));
- for (int k{0}; k < j; ++k) {
- std::uint64_t y = x | (std::uint64_t{1} << k);
- MATCH(2, BitPopulationCount(y));
- MATCH(false, Parity(y));
- MATCH(62, BitPopulationCount(~y));
- MATCH(false, Parity(~y));
- }
- }
- MATCH(0, BitPopulationCount(std::uint32_t{0}));
- MATCH(false, Parity(std::uint32_t{0}));
- MATCH(32, BitPopulationCount(~std::uint32_t{0}));
- MATCH(false, Parity(~std::uint32_t{0}));
- for (int j{0}; j < 32; ++j) {
- std::uint32_t x = std::uint32_t{1} << j;
- MATCH(1, BitPopulationCount(x));
- MATCH(true, Parity(x));
- MATCH(31, BitPopulationCount(~x));
- MATCH(true, Parity(~x));
- for (int k{0}; k < j; ++k) {
- std::uint32_t y = x | (std::uint32_t{1} << k);
- MATCH(2, BitPopulationCount(y));
- MATCH(false, Parity(y));
- MATCH(30, BitPopulationCount(~y));
- MATCH(false, Parity(~y));
- }
- }
- MATCH(0, BitPopulationCount(std::uint16_t{0}));
- MATCH(false, Parity(std::uint16_t{0}));
- MATCH(16, BitPopulationCount(static_cast<std::uint16_t>(~0)));
- MATCH(false, Parity(static_cast<std::uint16_t>(~0)));
- for (int j{0}; j < 16; ++j) {
- std::uint16_t x = std::uint16_t{1} << j;
- MATCH(1, BitPopulationCount(x));
- MATCH(true, Parity(x));
- MATCH(15, BitPopulationCount(static_cast<std::uint16_t>(~x)));
- MATCH(true, Parity(static_cast<std::uint16_t>(~x)));
- for (int k{0}; k < j; ++k) {
- std::uint16_t y = x | (std::uint16_t{1} << k);
- MATCH(2, BitPopulationCount(y));
- MATCH(false, Parity(y));
- MATCH(14, BitPopulationCount(static_cast<std::uint16_t>(~y)));
- MATCH(false, Parity(static_cast<std::uint16_t>(~y)));
- }
- }
- MATCH(0, BitPopulationCount(std::uint8_t{0}));
- MATCH(false, Parity(std::uint8_t{0}));
- MATCH(8, BitPopulationCount(static_cast<std::uint8_t>(~0)));
- MATCH(false, Parity(static_cast<std::uint8_t>(~0)));
- for (int j{0}; j < 8; ++j) {
- std::uint8_t x = std::uint8_t{1} << j;
- MATCH(1, BitPopulationCount(x));
- MATCH(true, Parity(x));
- MATCH(7, BitPopulationCount(static_cast<std::uint8_t>(~x)));
- MATCH(true, Parity(static_cast<std::uint8_t>(~x)));
- for (int k{0}; k < j; ++k) {
- std::uint8_t y = x | (std::uint8_t{1} << k);
- MATCH(2, BitPopulationCount(y));
- MATCH(false, Parity(y));
- MATCH(6, BitPopulationCount(static_cast<std::uint8_t>(~y)));
- MATCH(false, Parity(static_cast<std::uint8_t>(~y)));
- }
- }
- return testing::Complete();
-}
--- /dev/null
+// 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/bit-population-count.h"
+#include "testing.h"
+
+using Fortran::evaluate::BitPopulationCount;
+using Fortran::evaluate::Parity;
+
+int main() {
+ MATCH(0, BitPopulationCount(std::uint64_t{0}));
+ MATCH(false, Parity(std::uint64_t{0}));
+ MATCH(64, BitPopulationCount(~std::uint64_t{0}));
+ MATCH(false, Parity(~std::uint64_t{0}));
+ for (int j{0}; j < 64; ++j) {
+ std::uint64_t x = std::uint64_t{1} << j;
+ MATCH(1, BitPopulationCount(x));
+ MATCH(true, Parity(x));
+ MATCH(63, BitPopulationCount(~x));
+ MATCH(true, Parity(~x));
+ for (int k{0}; k < j; ++k) {
+ std::uint64_t y = x | (std::uint64_t{1} << k);
+ MATCH(2, BitPopulationCount(y));
+ MATCH(false, Parity(y));
+ MATCH(62, BitPopulationCount(~y));
+ MATCH(false, Parity(~y));
+ }
+ }
+ MATCH(0, BitPopulationCount(std::uint32_t{0}));
+ MATCH(false, Parity(std::uint32_t{0}));
+ MATCH(32, BitPopulationCount(~std::uint32_t{0}));
+ MATCH(false, Parity(~std::uint32_t{0}));
+ for (int j{0}; j < 32; ++j) {
+ std::uint32_t x = std::uint32_t{1} << j;
+ MATCH(1, BitPopulationCount(x));
+ MATCH(true, Parity(x));
+ MATCH(31, BitPopulationCount(~x));
+ MATCH(true, Parity(~x));
+ for (int k{0}; k < j; ++k) {
+ std::uint32_t y = x | (std::uint32_t{1} << k);
+ MATCH(2, BitPopulationCount(y));
+ MATCH(false, Parity(y));
+ MATCH(30, BitPopulationCount(~y));
+ MATCH(false, Parity(~y));
+ }
+ }
+ MATCH(0, BitPopulationCount(std::uint16_t{0}));
+ MATCH(false, Parity(std::uint16_t{0}));
+ MATCH(16, BitPopulationCount(static_cast<std::uint16_t>(~0)));
+ MATCH(false, Parity(static_cast<std::uint16_t>(~0)));
+ for (int j{0}; j < 16; ++j) {
+ std::uint16_t x = std::uint16_t{1} << j;
+ MATCH(1, BitPopulationCount(x));
+ MATCH(true, Parity(x));
+ MATCH(15, BitPopulationCount(static_cast<std::uint16_t>(~x)));
+ MATCH(true, Parity(static_cast<std::uint16_t>(~x)));
+ for (int k{0}; k < j; ++k) {
+ std::uint16_t y = x | (std::uint16_t{1} << k);
+ MATCH(2, BitPopulationCount(y));
+ MATCH(false, Parity(y));
+ MATCH(14, BitPopulationCount(static_cast<std::uint16_t>(~y)));
+ MATCH(false, Parity(static_cast<std::uint16_t>(~y)));
+ }
+ }
+ MATCH(0, BitPopulationCount(std::uint8_t{0}));
+ MATCH(false, Parity(std::uint8_t{0}));
+ MATCH(8, BitPopulationCount(static_cast<std::uint8_t>(~0)));
+ MATCH(false, Parity(static_cast<std::uint8_t>(~0)));
+ for (int j{0}; j < 8; ++j) {
+ std::uint8_t x = std::uint8_t{1} << j;
+ MATCH(1, BitPopulationCount(x));
+ MATCH(true, Parity(x));
+ MATCH(7, BitPopulationCount(static_cast<std::uint8_t>(~x)));
+ MATCH(true, Parity(static_cast<std::uint8_t>(~x)));
+ for (int k{0}; k < j; ++k) {
+ std::uint8_t y = x | (std::uint8_t{1} << k);
+ MATCH(2, BitPopulationCount(y));
+ MATCH(false, Parity(y));
+ MATCH(6, BitPopulationCount(static_cast<std::uint8_t>(~y)));
+ MATCH(false, Parity(static_cast<std::uint8_t>(~y)));
+ }
+ }
+ return testing::Complete();
+}
+++ /dev/null
-// 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"
-#include "../../lib/evaluate/integer.h"
-#include <cstdio>
-
-using Fortran::evaluate::Integer;
-using Fortran::evaluate::Ordering;
-
-template<int BITS, typename INT = Integer<BITS>> 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<int>(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) {
- 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);
- 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);
- exhaustiveTesting<1>();
- exhaustiveTesting<2>();
- exhaustiveTesting<7>();
- exhaustiveTesting<8>();
- exhaustiveTesting<9>();
- exhaustiveTesting<9, Integer<9, 1>>();
- exhaustiveTesting<9, Integer<9, 1, std::uint8_t, std::uint16_t>>();
- exhaustiveTesting<9, Integer<9, 2>>();
- exhaustiveTesting<9, Integer<9, 2, std::uint8_t, std::uint16_t>>();
- exhaustiveTesting<9, Integer<9, 8, std::uint8_t, std::uint16_t>>();
- exhaustiveTesting<9, Integer<9, 8, std::uint8_t, std::uint16_t, false>>();
- return testing::Complete();
-}
--- /dev/null
+// 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 <cstdio>
+
+using Fortran::evaluate::Integer;
+using Fortran::evaluate::Ordering;
+
+template<int BITS, typename INT = Integer<BITS>> 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<int>(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);
+ 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);
+ exhaustiveTesting<1>();
+ exhaustiveTesting<2>();
+ exhaustiveTesting<7>();
+ exhaustiveTesting<8>();
+ exhaustiveTesting<9>();
+ exhaustiveTesting<9, Integer<9, 1>>();
+ exhaustiveTesting<9, Integer<9, 1, std::uint8_t, std::uint16_t>>();
+ exhaustiveTesting<9, Integer<9, 2>>();
+ exhaustiveTesting<9, Integer<9, 2, std::uint8_t, std::uint16_t>>();
+ exhaustiveTesting<9, Integer<9, 8, std::uint8_t, std::uint16_t>>();
+ exhaustiveTesting<9, Integer<9, 8, std::uint8_t, std::uint16_t, false>>();
+ return testing::Complete();
+}
+++ /dev/null
-// 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"
-#include "../../lib/evaluate/leading-zero-bit-count.h"
-
-using Fortran::evaluate::LeadingZeroBitCount;
-
-int main() {
- MATCH(64, LeadingZeroBitCount(std::uint64_t{0}));
- for (int j{0}; j < 64; ++j) {
- for (int k{0}; k < j; ++k) {
- std::uint64_t x = (std::uint64_t{1} << j) | (std::uint64_t{1} << k);
- MATCH(63 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
- }
- }
- MATCH(32, LeadingZeroBitCount(std::uint32_t{0}));
- for (int j{0}; j < 32; ++j) {
- for (int k{0}; k < j; ++k) {
- std::uint32_t x = (std::uint32_t{1} << j) | (std::uint32_t{1} << k);
- MATCH(31 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
- }
- }
- MATCH(16, LeadingZeroBitCount(std::uint16_t{0}));
- for (int j{0}; j < 16; ++j) {
- for (int k{0}; k < j; ++k) {
- std::uint16_t x = (std::uint16_t{1} << j) | (std::uint16_t{1} << k);
- MATCH(15 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
- }
- }
- MATCH(8, LeadingZeroBitCount(std::uint8_t{0}));
- for (int j{0}; j < 8; ++j) {
- for (int k{0}; k < j; ++k) {
- std::uint8_t x = (std::uint8_t{1} << j) | (std::uint8_t{1} << k);
- MATCH(7 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
- }
- }
- return testing::Complete();
-}
--- /dev/null
+// 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/leading-zero-bit-count.h"
+#include "testing.h"
+
+using Fortran::evaluate::LeadingZeroBitCount;
+
+int main() {
+ MATCH(64, LeadingZeroBitCount(std::uint64_t{0}));
+ for (int j{0}; j < 64; ++j) {
+ for (int k{0}; k < j; ++k) {
+ std::uint64_t x = (std::uint64_t{1} << j) | (std::uint64_t{1} << k);
+ MATCH(63 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
+ }
+ }
+ MATCH(32, LeadingZeroBitCount(std::uint32_t{0}));
+ for (int j{0}; j < 32; ++j) {
+ for (int k{0}; k < j; ++k) {
+ std::uint32_t x = (std::uint32_t{1} << j) | (std::uint32_t{1} << k);
+ MATCH(31 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
+ }
+ }
+ MATCH(16, LeadingZeroBitCount(std::uint16_t{0}));
+ for (int j{0}; j < 16; ++j) {
+ for (int k{0}; k < j; ++k) {
+ std::uint16_t x = (std::uint16_t{1} << j) | (std::uint16_t{1} << k);
+ MATCH(15 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
+ }
+ }
+ MATCH(8, LeadingZeroBitCount(std::uint8_t{0}));
+ for (int j{0}; j < 8; ++j) {
+ for (int k{0}; k < j; ++k) {
+ std::uint8_t x = (std::uint8_t{1} << j) | (std::uint8_t{1} << k);
+ MATCH(7 - j, LeadingZeroBitCount(x))("j=%d, k=%d", j, k);
+ }
+ }
+ return testing::Complete();
+}