diff --git a/BUILD.bazel b/BUILD.bazel index cf4560b703..5dc5fcf726 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -128,6 +128,7 @@ BUTIL_SRCS = [ "src/butil/third_party/icu/icu_utf.cc", "src/butil/third_party/superfasthash/superfasthash.c", "src/butil/third_party/modp_b64/modp_b64.cc", + "src/butil/third_party/modp_b64/modp_b64_rvv.cc", "src/butil/third_party/symbolize/demangle.cc", "src/butil/third_party/symbolize/symbolize.cc", "src/butil/third_party/snappy/snappy-sinksource.cc", diff --git a/src/butil/string_compare_rvv.cc b/src/butil/string_compare_rvv.cc index 3f7985e1c8..6373e83d26 100644 --- a/src/butil/string_compare_rvv.cc +++ b/src/butil/string_compare_rvv.cc @@ -15,10 +15,9 @@ // specific language governing permissions and limitations // under the License. -// RVV-accelerated memcmp for StringPiece operations. -// Algorithm follows glibc's RVV memcmp pattern: -// - e8m8 LMUL with hardware-adaptive VL via vsetvl -// - vfirst.m for early-out on first mismatch +// RVV-accelerated memcmp and memchr for StringPiece operations. +// memcmp: follows glibc's RVV memcmp pattern (e8m8 LMUL, vfirst.m early-out). +// memchr: uses vmseq + vfirst.m to locate first matching byte. #include "butil/strings/string_piece.h" @@ -50,6 +49,27 @@ int rvv_memcmp(const void* p1, const void* p2, size_t n) { return 0; } +const void* rvv_memchr(const void* s, int c, size_t n) { + const uint8_t* src = static_cast(s); + uint8_t ch = static_cast(c); + size_t remaining = n; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m8(remaining); + vuint8m8_t v = __riscv_vle8_v_u8m8(src, vl); + vbool1_t eq = __riscv_vmseq_vx_u8m8_b1(v, ch, vl); + long first = __riscv_vfirst_m_b1(eq, vl); + + if (first >= 0) { + return src + first; + } + + src += vl; + remaining -= vl; + } + return nullptr; +} + } // namespace butil #endif // __riscv && __riscv_vector diff --git a/src/butil/strings/string_piece.cc b/src/butil/strings/string_piece.cc index 2d249243b2..a96d6ad056 100644 --- a/src/butil/strings/string_piece.cc +++ b/src/butil/strings/string_piece.cc @@ -134,7 +134,18 @@ size_t findT(const BasicStringPiece& self, } size_t find(const StringPiece& self, char c, size_t pos) { +#if defined(__riscv) && defined(__riscv_vector) + if (pos < self.size()) { + const void* result = butil::rvv_memchr(self.data() + pos, c, self.size() - pos); + if (result != nullptr) { + return static_cast(static_cast(result) - self.data()); + } + return BasicStringPiece::npos; + } + return BasicStringPiece::npos; +#else return findT(self, c, pos); +#endif } size_t find(const StringPiece16& self, char16 c, size_t pos) { diff --git a/src/butil/strings/string_piece.h b/src/butil/strings/string_piece.h index b1a4ed73a5..808ccbb19f 100644 --- a/src/butil/strings/string_piece.h +++ b/src/butil/strings/string_piece.h @@ -43,9 +43,10 @@ namespace butil { -// RVV-accelerated byte comparison (implemented in string_compare_rvv.cc) +// RVV-accelerated byte comparison and search (implemented in string_compare_rvv.cc) #if defined(__riscv) && defined(__riscv_vector) BUTIL_EXPORT int rvv_memcmp(const void* p1, const void* p2, size_t n); +BUTIL_EXPORT const void* rvv_memchr(const void* s, int c, size_t n); #endif template class BasicStringPiece;