[flang] Reading numbers from strings.
authorpeter klausler <pklausler@nvidia.com>
Fri, 1 Jun 2018 19:37:23 +0000 (12:37 -0700)
committerpeter klausler <pklausler@nvidia.com>
Thu, 14 Jun 2018 20:52:35 +0000 (13:52 -0700)
Original-commit: flang-compiler/f18@8cbadfe7778a400756bc34dcbb5fe39334a742f8
Reviewed-on: https://github.com/flang-compiler/f18/pull/101
Tree-same-pre-rewrite: false

flang/lib/evaluate/integer.h
flang/test/evaluate/CMakeLists.txt
flang/test/evaluate/bit-population-count-test.cc [deleted file]
flang/test/evaluate/bit-population-count.cc [new file with mode: 0644]
flang/test/evaluate/integer-test.cc [deleted file]
flang/test/evaluate/integer.cc [new file with mode: 0644]
flang/test/evaluate/leading-zero-bit-count-test.cc [deleted file]
flang/test/evaluate/leading-zero-bit-count.cc [new file with mode: 0644]

index df5053c98b2ba00f36930fd5b7318a0d111c726e..13cfcbc9ba61600f4a3a1af6b28dddc7f8a5f86f 100644 (file)
@@ -77,6 +77,25 @@ private:
   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;
@@ -140,6 +159,39 @@ public:
     }
   }
 
+  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.
@@ -287,10 +339,6 @@ public:
   // 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};
@@ -531,10 +579,6 @@ public:
   }
 
   // Unsigned addition with carry.
-  struct ValueWithCarry {
-    Integer value;
-    bool carry;
-  };
   constexpr ValueWithCarry AddUnsigned(
       const Integer &y, bool carryIn = false) const {
     Integer sum{nullptr};
@@ -587,9 +631,6 @@ public:
     }
   }
 
-  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) {
@@ -645,10 +686,6 @@ public:
     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
index f6fbbb367df0c04858abea70fd85c4fd9c55e974..4009641e752569feb1be9d689b787877999b2cd1 100644 (file)
@@ -17,7 +17,7 @@ add_library(FortranEvaluateTesting
 )
 
 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
@@ -26,7 +26,7 @@ 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
@@ -35,7 +35,7 @@ target_link_libraries(bit-population-count-test
 )
 
 add_executable(integer-test
-  integer-test.cc
+  integer.cc
 )
 
 target_link_libraries(integer-test
diff --git a/flang/test/evaluate/bit-population-count-test.cc b/flang/test/evaluate/bit-population-count-test.cc
deleted file mode 100644 (file)
index 21dc433..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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();
-}
diff --git a/flang/test/evaluate/bit-population-count.cc b/flang/test/evaluate/bit-population-count.cc
new file mode 100644 (file)
index 0000000..1498812
--- /dev/null
@@ -0,0 +1,95 @@
+// 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();
+}
diff --git a/flang/test/evaluate/integer-test.cc b/flang/test/evaluate/integer-test.cc
deleted file mode 100644 (file)
index db4ca7d..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-// 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();
-}
diff --git a/flang/test/evaluate/integer.cc b/flang/test/evaluate/integer.cc
new file mode 100644 (file)
index 0000000..d10ea80
--- /dev/null
@@ -0,0 +1,261 @@
+// 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();
+}
diff --git a/flang/test/evaluate/leading-zero-bit-count-test.cc b/flang/test/evaluate/leading-zero-bit-count-test.cc
deleted file mode 100644 (file)
index fae7918..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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();
-}
diff --git a/flang/test/evaluate/leading-zero-bit-count.cc b/flang/test/evaluate/leading-zero-bit-count.cc
new file mode 100644 (file)
index 0000000..3d87a43
--- /dev/null
@@ -0,0 +1,50 @@
+// 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();
+}