The vector implementation uses a fault-only-first (vle8ff.v) scan to find
candidate positions of the needle's first byte, then verifies each
candidate with a byte loop that stops at the needle's NUL or at a
mismatch; both phases stop at a NUL, so no load ever crosses past the end
of either string into an unmapped page. This provides significant
performance improvements on RVV-capable hardware. Use conditional
compilation to fall back to the generic implementation when __riscv_vector
is not available, maintaining compatibility with non-vector RISC-V
systems.
Signed-off-by: Pincheng Wang <pincheng.plct@isrc.iscas.ac.cn>
---
newlib/libc/machine/riscv/Makefile.inc | 4 +-
newlib/libc/machine/riscv/strstr-asm.S | 55 ++++++++++++++++++++++++++
newlib/libc/machine/riscv/strstr.c | 5 +++
3 files changed, 63 insertions(+), 1 deletion(-)
create mode 100644 newlib/libc/machine/riscv/strstr-asm.S
create mode 100644 newlib/libc/machine/riscv/strstr.c
@@ -47,4 +47,6 @@ libc_a_SOURCES += \
%D%/strrchr-asm.S \
%D%/strrchr.c \
%D%/strspn-asm.S \
- %D%/strspn.c
+ %D%/strspn.c \
+ %D%/strstr-asm.S \
+ %D%/strstr.c
new file mode 100644
@@ -0,0 +1,55 @@
+#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+.text
+.option push
+.option arch, +v
+/* char *strstr(const char *a0, const char *a1)
+ Locate substring a1 in a0. A vectorized scan (vle8ff, page-boundary safe)
+ finds candidate positions of needle[0]; each candidate is verified with a
+ byte loop that stops at the needle's NUL (match) or at a mismatch/the
+ haystack NUL. Both phases stop at a NUL, so no load ever crosses past the
+ end of either string into an unmapped page. */
+.global strstr
+.type strstr, @function
+strstr:
+ lbu t0, 0(a1) /* c0 = needle[0] */
+ beqz t0, .Lret_h /* empty needle -> return haystack */
+.Lloop:
+ vsetvli t1, zero, e8, m1, ta, ma
+ vle8ff.v v8, (a0)
+ csrr t1, vl
+ vmseq.vx v1, v8, t0 /* lanes == c0 */
+ vmseq.vi v2, v8, 0 /* NUL lanes */
+ vfirst.m t2, v1
+ vfirst.m t3, v2
+ bltz t2, .Lno_c0 /* no c0 in this chunk */
+ bltz t3, .Lcandidate /* c0 present, no NUL -> candidate */
+ bltu t2, t3, .Lcandidate /* c0 occurs before NUL */
+ /* NUL at or before c0 -> end of haystack reached */
+.Lnotfound:
+ li a0, 0
+ ret
+.Lno_c0:
+ bgez t3, .Lnotfound /* hit NUL with no c0 -> not found */
+ add a0, a0, t1
+ j .Lloop
+.Lcandidate:
+ add a0, a0, t2 /* a0 -> candidate (h[*]==c0) */
+ mv t4, a0 /* haystack cursor */
+ mv t5, a1 /* needle cursor */
+.Lverify:
+ lbu t6, 0(t5)
+ beqz t6, .Lmatch /* needle exhausted -> match at a0 */
+ lbu a2, 0(t4)
+ bne a2, t6, .Ladvance /* mismatch (a2 may be NUL) */
+ addi t4, t4, 1
+ addi t5, t5, 1
+ j .Lverify
+.Ladvance:
+ addi a0, a0, 1 /* slide one byte and rescan */
+ j .Lloop
+.Lmatch:
+.Lret_h:
+ ret
+.size strstr, .-strstr
+.option pop
+#endif
new file mode 100644
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64
+# include "../../string/strstr.c"
+#else
+/* strstr defined in strstr-asm.S */
+#endif