Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions libs/libc/machine/risc-v/arch_memcmp.S
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
37 changes: 36 additions & 1 deletion libs/libc/machine/risc-v/arch_strcmp.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion libs/libc/machine/risc-v/arch_strlcpy.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 26 additions & 3 deletions libs/libc/machine/risc-v/arch_strncmp.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading