[PATCH] riscv: avoid vle8ff in vector strcmp loop
Carlos O'Donell
carlos@redhat.com
Mon Jun 15 13:06:46 GMT 2026
On 6/14/26 6:55 AM, daichengrong wrote:
> Limit vl by the minimum distance from the input pointers to the next 4K
> boundary, and use normal vle8.v loads in the main loop. This keeps the
> loads page-safe while avoiding the vl update dependency from vle8ff.v.
Do you have microbenchmark data that supports this change?
Generally for such changes we would like to see "make bench" showing a difference.
> Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
> ---
> sysdeps/riscv/rvv/strcmp.S | 110 +++++++++++++++++++++----------------
> 1 file changed, 64 insertions(+), 46 deletions(-)
>
> diff --git a/sysdeps/riscv/rvv/strcmp.S b/sysdeps/riscv/rvv/strcmp.S
> index a2f6865581..d32d8f490a 100644
> --- a/sysdeps/riscv/rvv/strcmp.S
> +++ b/sysdeps/riscv/rvv/strcmp.S
> @@ -35,59 +35,77 @@
> #define vstr1 v0
> #define vstr2 v8
> #define vmask1 v16
> -#define vmask2 v17
> +#define vmask2 v24
>
> ENTRY (STRCMP)
> .option push
> .option arch, +v
> - /* lmul=1 */
> -L(Loop):
> - vsetvli ivl, zero, e8, m1, ta, ma
> - vle8ff.v vstr1, (str1)
> - /* Check if vstr1[i] == 0 */
> - vmseq.vx vmask1, vstr1, zero
> -
> - vle8ff.v vstr2, (str2)
> - /* Check if vstr1[i] != vstr2[i] */
> - vmsne.vv vmask2, vstr1, vstr2
> -
> - /* Find the index x for vstr1[x] == 0 */
> - vfirst.m temp1, vmask1
> - /* Find the index x for vstr1[x] != vstr2[x] */
> - vfirst.m temp2, vmask2
> -
> - bgez temp1, L(check1)
> - bgez temp2, L(check2)
> -
> - /* Get the current vl updated by vle8ff. */
> - csrr ivl, vl
> - add str1, str1, ivl
> - add str2, str2, ivl
> - j L(Loop)
> -
> - /* temp1 >= 0 */
> -L(check1):
> - bltz temp2, L(return_at_nul)
> - blt temp2, temp1, L(check2)
> -L(return_at_nul):
> - /* temp2 < 0 */
> - /* temp2 >= 0 && temp1 < temp2 */
> - add str1, str1, temp1
> - add str2, str2, temp1
> - lbu temp1, 0(str1)
> - lbu temp2, 0(str2)
> - sub result, temp1, temp2
> + li t0, 4095
> + li t3, 4096
> +L(loop):
> + and t1, str1, t0 /* t1 = str1 offset in 4K page */
> + and t2, str2, t0 /* t2 = str2 offset in 4K page */
> + sub t4, t3, t1 /* t4 = bytes from str1 to page end */
> + sub t5, t3, t2 /* t5 = bytes from str2 to page end */
> + /*
> + * t3 = min(dist1, dist2)
> + */
> + bltu t5, t4, 1f
> + mv t5, t4
> +1:
> + /*
> + * Set vl to min(dist, VLMAX).
> + *
> + * If far from page boundary, vl = VLMAX.
> + * If close to page boundary, vl = dist.
> + */
> +
> + vsetvli ivl, t5, e8, m4, ta, ma
> + /*
> + * This load will not cross a 4K boundary for either pointer.
> + */
> + vle8.v vstr1, (str1)
> + vle8.v vstr2, (str2)
> +
> + /*
> + * str1 == 0 means string ended.
> + * str1 != str2 means strcmp result is decided.
> + */
> + vmseq.vx vmask1, vstr1, zero
> + vmsne.vv vmask2, vstr1, vstr2
> +
> + vfirst.m temp2, vmask2
> + vfirst.m temp1, vmask1
> +
> + bgez temp2, L(check_nul)
> + bgez temp1, L(ret)
> +
> + /*
> + * No NUL and no difference in this chunk.
> + * Advance by actual vl.
> + *
> + * If this was a page-boundary-limited load, one of str1/str2 now
> + * reaches the next 4K boundary. The next loop recomputes distance.
> + */
> + add str1, str1, ivl
> + add str2, str2, ivl
> + j L(loop)
> +
> +L(check_nul):
> + bltz temp1, L(found)
> + blt temp1, temp2, L(ret)
> +L(found):
> + add str1, str1, temp2
> + add str2, str2, temp2
> + lbu temp1, 0(str1)
> + lbu temp2, 0(str2)
> + sub result, temp1, temp2
> ret
>
> - /* temp1 < 0 */
> - /* temp2 >= 0 */
> -L(check2):
> - add str1, str1, temp2
> - add str2, str2, temp2
> - lbu temp1, 0(str1)
> - lbu temp2, 0(str2)
> - sub result, temp1, temp2
> +L(ret):
> + li result, 0
> ret
> +
> .option pop
> END (STRCMP)
> libc_hidden_builtin_def (strcmp)
--
Cheers,
Carlos.
More information about the Libc-alpha
mailing list