[libc-commits] [libc] [libc] Fix AVX2 compare_and_mask broadcasting byte needle with epi16 (PR #235246)
Aman Maurya via libc-commits
libc-commits at lists.llvm.org
Sat Oct 24 00:19:33 PDT 2026
https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/235246
>From 4452021033a30d93479c6dca909f8044c4aa4c07 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Sat, 24 Oct 2026 12:41:42 +0530
Subject: [PATCH 1/2] [libc] Fix AVX2 compare_and_mask broadcasting byte needle
with epi16
In libc/src/string/memory_utils/x86_64/inline_strlen.h, the AVX2
specialization of compare_and_mask used _mm256_set1_epi16(c) instead of
_mm256_set1_epi8(c). Because compare_and_mask is used by find_first_character
(memchr), this caused matches at odd offsets to be missed and false matches
on 0x00 bytes at odd offsets.
Fix the broadcast to use _mm256_set1_epi8(c) and add regression tests in
memchr_test.
Fixes #226787.
---
.../memory_utils/x86_64/inline_strlen.h | 2 +-
libc/test/src/string/memchr_test.cpp | 24 +++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/libc/src/string/memory_utils/x86_64/inline_strlen.h b/libc/src/string/memory_utils/x86_64/inline_strlen.h
index 0343e22f3e58e3..3c31d38706816a 100644
--- a/libc/src/string/memory_utils/x86_64/inline_strlen.h
+++ b/libc/src/string/memory_utils/x86_64/inline_strlen.h
@@ -110,7 +110,7 @@ template <>
LIBC_INLINE uint32_t
compare_and_mask<__m256i, uint32_t>(const __m256i *block_ptr, char c) {
__m256i b = _mm256_load_si256(block_ptr);
- __m256i set = _mm256_set1_epi16(c);
+ __m256i set = _mm256_set1_epi8(c);
__m256i cmp = _mm256_cmpeq_epi8(b, set);
return _mm256_movemask_epi8(cmp);
}
diff --git a/libc/test/src/string/memchr_test.cpp b/libc/test/src/string/memchr_test.cpp
index a92c5fe80be98b..9a3f21e47ba989 100644
--- a/libc/test/src/string/memchr_test.cpp
+++ b/libc/test/src/string/memchr_test.cpp
@@ -131,6 +131,30 @@ TEST(LlvmLibcMemChrTest, SignedCharacterFound) {
ASSERT_EQ(actual[0], c);
}
+TEST(LlvmLibcMemChrTest, MatchesAtOddAndEvenOffsets) {
+ alignas(32) unsigned char buf[64];
+ for (size_t i = 0; i < sizeof(buf); ++i)
+ buf[i] = 'x';
+
+ for (size_t offset = 0; offset < sizeof(buf); ++offset) {
+ buf[offset] = 'A';
+ const char *actual = call_memchr(buf, 'A', sizeof(buf));
+ ASSERT_EQ(actual, reinterpret_cast<const char *>(buf + offset));
+ buf[offset] = 'x';
+ }
+}
+
+TEST(LlvmLibcMemChrTest, NoFalseMatchWithZeroOrNegativeByteAtOddOffset) {
+ alignas(32) unsigned char buf[64];
+ for (size_t i = 0; i < sizeof(buf); ++i)
+ buf[i] = 0x11;
+
+ // Odd offset has 0x00 and 0xFF; searching for 'A' (0x41) must not false-match.
+ buf[1] = 0x00;
+ buf[3] = 0xFF;
+ ASSERT_STREQ(call_memchr(buf, 'A', sizeof(buf)), nullptr);
+}
+
#if defined(LIBC_ADD_NULL_CHECKS)
TEST(LlvmLibcMemChrTest, CrashOnNullPtr) {
>From af82bebfb333076ccbdd2fb151ef688fee3e0450 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Sat, 24 Oct 2026 12:49:03 +0530
Subject: [PATCH 2/2] [libc] Fix formatting in memchr_test.cpp
---
libc/test/src/string/memchr_test.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libc/test/src/string/memchr_test.cpp b/libc/test/src/string/memchr_test.cpp
index 9a3f21e47ba989..d7ef354271e754 100644
--- a/libc/test/src/string/memchr_test.cpp
+++ b/libc/test/src/string/memchr_test.cpp
@@ -149,7 +149,8 @@ TEST(LlvmLibcMemChrTest, NoFalseMatchWithZeroOrNegativeByteAtOddOffset) {
for (size_t i = 0; i < sizeof(buf); ++i)
buf[i] = 0x11;
- // Odd offset has 0x00 and 0xFF; searching for 'A' (0x41) must not false-match.
+ // Odd offset has 0x00 and 0xFF; searching for 'A' (0x41) must not
+ // false-match.
buf[1] = 0x00;
buf[3] = 0xFF;
ASSERT_STREQ(call_memchr(buf, 'A', sizeof(buf)), nullptr);
More information about the libc-commits
mailing list