about summary refs log tree commit diff
path: root/absl/container
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container')
-rw-r--r--absl/container/internal/raw_hash_set.h28
-rw-r--r--absl/container/internal/raw_hash_set_test.cc67
2 files changed, 57 insertions, 38 deletions
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index aa423b25df5b..78382a35aed4 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -337,10 +337,10 @@ inline bool IsDeleted(ctrl_t c) { return c == kDeleted; }
 inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; }
 
 #if SWISSTABLE_HAVE_SSE2
-struct Group {
+struct GroupSse2Impl {
   static constexpr size_t kWidth = 16;  // the number of slots per group
 
-  explicit Group(const ctrl_t* pos) {
+  explicit GroupSse2Impl(const ctrl_t* pos) {
     ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
   }
 
@@ -390,11 +390,13 @@ struct Group {
 
   __m128i ctrl;
 };
-#else
-struct Group {
+#endif  // SWISSTABLE_HAVE_SSE2
+
+struct GroupPortableImpl {
   static constexpr size_t kWidth = 8;
 
-  explicit Group(const ctrl_t* pos) : ctrl(little_endian::Load64(pos)) {}
+  explicit GroupPortableImpl(const ctrl_t* pos)
+      : ctrl(little_endian::Load64(pos)) {}
 
   BitMask<uint64_t, kWidth, 3> Match(h2_t hash) const {
     // For the technique, see:
@@ -441,12 +443,24 @@ struct Group {
 
   uint64_t ctrl;
 };
-#endif  // SWISSTABLE_HAVE_SSE2
+
+#if SWISSTABLE_HAVE_SSE2 && defined(__GNUC__) && !defined(__clang__)
+// https://github.com/abseil/abseil-cpp/issues/209
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
+// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char
+// Work around this by using the portable implementation of Group
+// when using -funsigned-char under GCC.
+using Group = std::conditional<std::is_signed<char>::value, GroupSse2Impl,
+                               GroupPortableImpl>::type;
+#elif SWISSTABLE_HAVE_SSE2
+using Group = GroupSse2Impl;
+#else
+using Group = GroupPortableImpl;
+#endif
 
 template <class Policy, class Hash, class Eq, class Alloc>
 class raw_hash_set;
 
-
 inline bool IsValidCapacity(size_t n) {
   return ((n + 1) & n) == 0 && n >= Group::kWidth - 1;
 }
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index f48578eb1495..b66a8f16444f 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -130,45 +130,50 @@ TEST(Group, EmptyGroup) {
   for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h));
 }
 
-#if SWISSTABLE_HAVE_SSE2
 TEST(Group, Match) {
-  ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
-                    7,      5, 3,        1, 1,      1, 1,         1};
-  EXPECT_THAT(Group{group}.Match(0), ElementsAre());
-  EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
-  EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
-  EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
-  EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
+  if (Group::kWidth == 16) {
+    ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
+                      7,      5, 3,        1, 1,      1, 1,         1};
+    EXPECT_THAT(Group{group}.Match(0), ElementsAre());
+    EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
+    EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
+    EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
+    EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
+  } else if (Group::kWidth == 8) {
+    ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
+    EXPECT_THAT(Group{group}.Match(0), ElementsAre());
+    EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
+    EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
+  }
 }
 
 TEST(Group, MatchEmpty) {
-  ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
-                    7,      5, 3,        1, 1,      1, 1,         1};
-  EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4));
-}
-
-TEST(Group, MatchEmptyOrDeleted) {
-  ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
-                    7,      5, 3,        1, 1,      1, 1,         1};
-  EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4));
-}
-#else
-TEST(Group, Match) {
-  ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
-  EXPECT_THAT(Group{group}.Match(0), ElementsAre());
-  EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
-  EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
-}
-TEST(Group, MatchEmpty) {
-  ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
-  EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0));
+  if (Group::kWidth == 16) {
+    ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
+                      7,      5, 3,        1, 1,      1, 1,         1};
+    EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4));
+  } else if (Group::kWidth == 8) {
+    ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
+    EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0));
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
+  }
 }
 
 TEST(Group, MatchEmptyOrDeleted) {
-  ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
-  EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3));
+  if (Group::kWidth == 16) {
+    ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
+                      7,      5, 3,        1, 1,      1, 1,         1};
+    EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4));
+  } else if (Group::kWidth == 8) {
+    ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
+    EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3));
+  } else {
+    FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
+  }
 }
-#endif
 
 TEST(Batch, DropDeletes) {
   constexpr size_t kCapacity = 63;