diff --git a/libs/libc/machine/risc-v/arch_memcmp.S b/libs/libc/machine/risc-v/arch_memcmp.S index 3af0a4602ca82..2110c283a134a 100644 --- a/libs/libc/machine/risc-v/arch_memcmp.S +++ b/libs/libc/machine/risc-v/arch_memcmp.S @@ -45,12 +45,33 @@ ARCH_LIBCFUN(memcmp): beqz a2, .Lequal - /* Check if both pointers share alignment */ + /* The loops below load from both pointers at a boundary, which asks + * that the two agree about where a boundary falls, not that either + * is already on one. Test the difference of the pointers, not their + * union. + */ - or t0, a0, a1 + xor t0, a0, a1 andi t0, t0, SZREG-1 bnez t0, .Lbyte_cmp + /* Same offset: walk both up to the boundary a byte at a time, + * stopping early on a difference. + */ + +.Lalign_head: + andi t0, a0, SZREG-1 + beqz t0, .Laligned + lbu t1, 0(a0) + lbu t2, 0(a1) + bne t1, t2, .Ldiff + addi a0, a0, 1 + addi a1, a1, 1 + addi a2, a2, -1 + beqz a2, .Lequal + j .Lalign_head + +.Laligned: li t0, SZREG bltu a2, t0, .Lbyte_cmp diff --git a/libs/libc/machine/risc-v/arch_strcmp.S b/libs/libc/machine/risc-v/arch_strcmp.S index a0bad30f602c5..3ccbcfbc47b02 100644 --- a/libs/libc/machine/risc-v/arch_strcmp.S +++ b/libs/libc/machine/risc-v/arch_strcmp.S @@ -26,11 +26,46 @@ ARCH_LIBCFUN(strcmp): .cfi_sections .debug_frame .cfi_startproc - or a4, a0, a1 li t2, -1 + + /* Two pointers the same distance past a boundary can be compared + * a register at a time once both are walked up to it. Only + * pointers that disagree about where the boundary falls need the + * byte loop, since no single aligned load serves both. Test the + * difference of the pointers, not their union. + */ + + xor a4, a0, a1 and a4, a4, SZREG-1 bnez a4, .Lmisaligned + /* Same offset: walk both up to the boundary a byte at a time, + * stopping early on a difference or a terminator. + */ + + and a4, a0, SZREG-1 + beqz a4, .Laligned +.Lhead: + lbu a2, 0(a0) + lbu a3, 0(a1) + bne a2, a3, .Lheaddiff + addi a0, a0, 1 + addi a1, a1, 1 + beqz a2, .Lheadeq + and a4, a0, SZREG-1 + bnez a4, .Lhead + j .Laligned + +.Lheaddiff: + sub a0, a2, a3 + ret + +.Lheadeq: + li a0, 0 + ret + +.Laligned: + #if SZREG == 4 li a5, 0x7f7f7f7f #else diff --git a/libs/libc/machine/risc-v/arch_strlcpy.S b/libs/libc/machine/risc-v/arch_strlcpy.S index 6d18cf40e731d..ac90a89dae50a 100644 --- a/libs/libc/machine/risc-v/arch_strlcpy.S +++ b/libs/libc/machine/risc-v/arch_strlcpy.S @@ -72,7 +72,17 @@ ARCH_LIBCFUN(strlcpy): addi a2, a2, -1 /* reserve space for null terminator */ - /* Bytewise copy head: align src to SZREG boundary */ + /* The word loop below aligns src and then stores a register at a + * time to dst, so it is safe only where the two pointers agree about + * where a boundary falls. Where they do not, no single boundary + * serves both and the copy goes a byte at a time. + */ + + xor t0, a0, a1 + andi t0, t0, SZREG-1 + bnez t0, .Lcopy_tail + + /* Bytewise copy head: align src, and with it dst */ .Lcopy_head: beqz a2, .Ltruncated diff --git a/libs/libc/machine/risc-v/arch_strncmp.S b/libs/libc/machine/risc-v/arch_strncmp.S index df03d5fe13f24..52bc2688d03df 100644 --- a/libs/libc/machine/risc-v/arch_strncmp.S +++ b/libs/libc/machine/risc-v/arch_strncmp.S @@ -44,13 +44,36 @@ ARCH_LIBCFUN(strncmp): beqz a2, .Lequal - /* Check alignment consistency */ + /* The word loop below loads from both pointers at a boundary, which + * asks that the two agree about where a boundary falls, not that + * either is already on one. Test the difference of the pointers, + * not their union. + */ - or t0, a0, a1 + xor t0, a0, a1 andi t0, t0, SZREG-1 bnez t0, .Lbyte_loop - /* Both aligned - load masks */ + /* Same offset: walk both up to the boundary a byte at a time, + * stopping early on a difference or a terminator. + */ + +.Lsnc_align_head: + andi t0, a0, SZREG-1 + beqz t0, .Lsnc_aligned + lbu t0, 0(a0) + lbu t1, 0(a1) + bne t0, t1, .Ldiff + beqz t0, .Lequal + addi a0, a0, 1 + addi a1, a1, 1 + addi a2, a2, -1 + beqz a2, .Lequal + j .Lsnc_align_head + +.Lsnc_aligned: + + /* Load masks */ #if SZREG == 8 lla t2, .Lsnc_mask01