[libc-commits] [libc] [libc][MVE] implement MVE accelerated memcmp (PR #224857)
via libc-commits
libc-commits at lists.llvm.org
Sat Sep 19 13:31:01 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Schrodinger ZHU Yifan (SchrodingerZhu)
<details>
<summary>Changes</summary>
This PR adds an MVE accelerated memcmp implementation for arm targets. The original implementation on arm only uses a byte-per-iteration implementation.
On RA8M2 (1Ghz) with TCM and D-Cache, DWT cycle counts:
| Distribution | Byte loop | MVE | Speedup |
|---|---:|---:|---:|
| GoogleA | 126 | 49 | 2.57× |
| GoogleB | 397 | 83 | 4.78× |
| GoogleD | 229 | 57 | 4.02× |
| GoogleL | 193 | 60 | 3.22× |
| GoogleM | 109 | 46 | 2.37× |
| GoogleQ | 219 | 60 | 3.65× |
| GoogleS | 360 | 76 | 4.74× |
| GoogleU | 245 | 63 | 3.89× |
| GoogleW | 144 | 52 | 2.77× |
| Uniform384To4096 | 21,227 | 2,677 | 7.93× |
Note that there is a small regression (`40` to `55` cycles) in first-byte being zero cases.
The assembly remains short in terms of space:
```asm
memcmp: @ @<!-- -->memcmp
.fnstart
@ %bb.0:
.p2align 3
.LBB0_1: @ =>This Inner Loop Header: Depth=1
cbz r2, .LBB0_4
@ %bb.2: @ in Loop: Header=BB0_1 Depth=1
vctp.8 r2
vpsttt
vldrbt.u8 q0, [r0]
vldrbt.u8 q1, [r1]
vcmpt.i8 ne, q0, q1
vmrs r3, p0
cbnz r3, .LBB0_5
@ %bb.3: @ in Loop: Header=BB0_1 Depth=1
adds r0, #<!-- -->16
cmp r2, #<!-- -->16
add.w r1, r1, #<!-- -->16
sub.w r2, r2, #<!-- -->16
bhs .LBB0_1
.LBB0_4:
movs r0, #<!-- -->0
bx lr
.LBB0_5:
vmrs r2, p0
rbit r2, r2
clz r2, r2
ldrb r0, [r0, r2]
ldrb r1, [r1, r2]
subs r0, r0, r1
bx lr
```
Assisted-by: Codex with gpt-6-astra
---
Full diff: https://github.com/llvm/llvm-project/pull/224857.diff
3 Files Affected:
- (modified) libc/src/string/memory_utils/CMakeLists.txt (+2)
- (added) libc/src/string/memory_utils/arm/inline_memcmp.h (+64)
- (modified) libc/src/string/memory_utils/inline_memcmp.h (+3)
``````````diff
diff --git a/libc/src/string/memory_utils/CMakeLists.txt b/libc/src/string/memory_utils/CMakeLists.txt
index 510546d79988a..17da91e15a686 100644
--- a/libc/src/string/memory_utils/CMakeLists.txt
+++ b/libc/src/string/memory_utils/CMakeLists.txt
@@ -10,6 +10,7 @@ add_header_library(
arm/common.h
arm/inline_memcpy.h
arm/inline_memset.h
+ arm/inline_memcmp.h
generic/aligned_access.h
generic/byte_per_byte.h
inline_bcmp.h
@@ -44,6 +45,7 @@ add_header_library(
libc.src.__support.macros.optimization
libc.src.__support.macros.properties.architectures
libc.src.__support.macros.properties.compiler
+ libc.src.__support.macros.properties.cpu_features
)
add_header_library(
diff --git a/libc/src/string/memory_utils/arm/inline_memcmp.h b/libc/src/string/memory_utils/arm/inline_memcmp.h
new file mode 100644
index 0000000000000..96f2b906f2bb4
--- /dev/null
+++ b/libc/src/string/memory_utils/arm/inline_memcmp.h
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the memcmp implementations for arm.
+///
+///===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ARM_INLINE_MEMCMP_H
+#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ARM_INLINE_MEMCMP_H
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/cpu_features.h"
+#include "src/__support/math_extras.h"
+#include "src/string/memory_utils/generic/byte_per_byte.h"
+#include "src/string/memory_utils/utils.h"
+
+#if defined(LIBC_TARGET_CPU_HAS_MVE)
+#include <arm_mve.h>
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+// We limit code size and don't aggressively expand the loop to multiway
+// parallel comparison.
+[[maybe_unused]] LIBC_INLINE MemcmpReturnType inline_memcmp_arm(CPtr p1,
+ CPtr p2,
+ size_t count) {
+#if defined(LIBC_TARGET_CPU_HAS_MVE)
+ // Cast to raw address to avoid ub:expr.add.out.of.bounds
+ uintptr_t p1_addr = cpp::bit_cast<uintptr_t>(p1);
+ uintptr_t p2_addr = cpp::bit_cast<uintptr_t>(p2);
+ while (count != 0) {
+ // Predication handles the final partial vector without reading past count.
+ mve_pred16_t active = vctp8q(count);
+ uint8x16_t a = vldrbq_z_u8(cpp::bit_cast<const uint8_t *>(p1_addr), active);
+ uint8x16_t b = vldrbq_z_u8(cpp::bit_cast<const uint8_t *>(p2_addr), active);
+ unsigned mismatches = vcmpneq_m_u8(a, b, active);
+ if (mismatches != 0) {
+ const size_t offset = cpp::countr_zero(mismatches);
+ return static_cast<int32_t>(cpp::bit_cast<CPtr>(p1_addr)[offset]) -
+ static_cast<int32_t>(cpp::bit_cast<CPtr>(p2_addr)[offset]);
+ }
+ // optimistically increase the address
+ p1_addr += 16;
+ p2_addr += 16;
+ if (sub_overflow(count, size_t{16}, count))
+ break;
+ }
+ return MemcmpReturnType::zero();
+#else
+ return inline_memcmp_byte_per_byte(p1, p2, count);
+#endif
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ARM_INLINE_MEMCMP_H
diff --git a/libc/src/string/memory_utils/inline_memcmp.h b/libc/src/string/memory_utils/inline_memcmp.h
index a98f7ac51648e..ac071f2ac2309 100644
--- a/libc/src/string/memory_utils/inline_memcmp.h
+++ b/libc/src/string/memory_utils/inline_memcmp.h
@@ -21,6 +21,9 @@
#elif defined(LIBC_TARGET_ARCH_IS_X86)
#include "src/string/memory_utils/x86_64/inline_memcmp.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCMP inline_memcmp_x86
+#elif defined(LIBC_TARGET_ARCH_IS_ARM)
+#include "src/string/memory_utils/arm/inline_memcmp.h"
+#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCMP inline_memcmp_arm
#elif defined(LIBC_TARGET_ARCH_IS_AARCH64)
#include "src/string/memory_utils/aarch64/inline_memcmp.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCMP inline_memcmp_aarch64_dispatch
``````````
</details>
https://github.com/llvm/llvm-project/pull/224857
More information about the libc-commits
mailing list