/* SH5 code Copyright 2002 SuperH Ltd. */

#include <picolibc.h>

#include "asm.h"

ENTRY(strcmp)

#if __SHMEDIA__
	ld.ub	r2,0,r4
	pt/l	quickret0,tr0
	ld.ub	r3,0,r5
	ptabs	r18,tr2
	beqi/u	r4,0,tr0
	ld.ub	r2,1,r6
	bne/u	r4,r5,tr0
	pt/l	quickret1,tr1
	ld.ub	r3,1,r7
	beqi/u	r6,0,tr1
	ld.ub	r2,2,r4
	bne/u	r6,r7,tr1
	ld.ub	r3,2,r5
	beqi/u	r4,0,tr0
	ld.ub	r2,3,r6
	bne/u	r4,r5,tr0
	ld.ub	r3,3,r7
	beqi/u	r6,0,tr1
	ld.ub	r2,4,r4
	bne/u	r6,r7,tr1
	ld.ub	r3,4,r5
	beqi/u	r4,0,tr0
	ld.ub	r2,5,r6
	bne/u	r4,r5,tr0
	ld.ub	r3,5,r7
	beqi/u	r6,0,tr1
	ld.ub	r2,6,r4
	bne/u	r6,r7,tr1
	ld.ub	r3,6,r5
	beqi/u	r4,0,tr0
	ld.ub	r2,7,r6
	bne/u	r4,r5,tr0
	ld.ub	r3,7,r7
	beqi/u	r6,0,tr1
	sub	r3,r2,r3
	bne/u	r6,r7,tr1

	andi	r2,-8,r2
	add	r3,r2,r3
	ldlo.q	r3,8,r23
	pt	r23_zero,tr0
	shlli	r3,3,r22
	sub	r63,r22,r20
	movi	0x101,r6
	mperm.w	r6,r63,r6
	SHLO	r6,r22,r7
	msubs.ub r7,r23,r8
	pt	loop,tr1
	bnei/u	r8,0,tr0 // r23_zero
	pt	found_zero,tr0
	addi	r3,15,r3
	andi	r3,-8,r3
	sub	r3,r2,r3
	bne/l	r7,r6,tr1 // loop
	/* The strings are aligned to each other.  */
	/* It is possible to have a loop with six cycles / iteration
	   by re-ordering the exit conditions, but then it needs extra
	   time and/or code to sort out the r4 != r5 case.  */
	pt	al_loop,tr1
	pt	al_found_zero,tr0
al_loop:
	ld.q	r2,8,r4
	ldx.q	r2,r3,r5
	addi	r2,8,r2
	mcmpeq.b r63,r4,r8
	pt	cmp_quad,tr3
	bnei/u	r8,0,tr0  // al_found_zero
	beq/l	r4,r5,tr1 // al_loop
	blink	tr3,r63   // cmp_quad

	.balign 8
quickret0:
	sub	r4,r5,r2
	blink	tr2,r63
quickret1:
	sub	r6,r7,r2
	blink	tr2,r63

loop:
	ld.q	r2,8,r4
	ldx.q	r2,r3,r19
	addi	r2,8,r2
	msubs.ub r6,r4,r8
	mcmpeq.b r63,r19,r9
	SHHI	r19,r20,r21
	or	r21,r23,r5
	SHLO	r19,r22,r23
	bne/u	r8,r9,tr0 // found_zero
	beq/l	r4,r5,tr1 // loop
cmp_quad:
#ifdef __LITTLE_ENDIAN__
	byterev r4,r4
	byterev r5,r5
#endif
	cmpgtu	r4,r5,r6
	cmpgtu	r5,r4,r7
	sub	r6,r7,r2
	blink tr2,r63
found_zero:
	pt	zero_now,tr0
	pt	cmp_quad,tr1
	SHHI	r9,r20,r7
	bne/u	r8,r7,tr0 // zero_now
	bne/u	r4,r5,tr1 // cmp_quad
	SHLO	r9,r22,r8
r23_zero:
	ld.q	r2,8,r4
	add	r23,r63,r5
zero_now:
al_found_zero:
/* We konw that one of the values has at lest one zero, and r8 holds
   an 0x01 or 0xff mask for every zero found in one of the operands.
   If both operands have the first zero in the same place, this mask
   allows us to truncate the comparison to the valid bytes in the
   strings.  If the first zero is in different places, it doesn't
   matter if some invalid bytes are included, since the comparison
   of the zero with the non-zero will determine the outcome.  */
#ifdef __LITTLE_ENDIAN__
	shlli	r8,8,r8
	addi	r8,-1,r9
	andc	r9,r8,r8
	and	r8,r4,r4
	and	r8,r5,r5
#else
	shlri r8,1,r8
	nsb	r8,r8
	addi	r8,8,r8
	andi	r8,56,r8
	sub	r63,r8,r8
	shlrd	r4,r8,r4
	shlrd	r5,r8,r5
#endif
#ifdef __LITTLE_ENDIAN__
	byterev r4,r4
	byterev r5,r5
#endif
	cmpgtu	r4,r5,r6
	cmpgtu	r5,r4,r7
	sub	r6,r7,r2
	blink tr2,r63

#else /* ! __SHMEDIA__, i.e. SH 1..4 / SHcompact */

#ifdef __SH5__
#define STR1 r2
#define STR2 r3
#define RESULT r2
#define TMP r4
#else
! Entry: r4: string1
!        r5: string2
! Exit:  r0: result
!        r1-r2,r4-r5: clobbered
#define STR1 r4
#define STR2 r5
#define RESULT r0
#define TMP r2
#endif /* __SH5__ */

	mov     STR1,r0
	or      STR2,r0
	tst	#3,r0
	bf	L_setup_char_loop
	mov	#0,r0
#ifdef DELAYED_BRANCHES
	mov.l	@STR1+,r1
	.align  2
Longword_loop:
	mov.l	@STR2+,TMP
	cmp/str	r0,r1
	bt	Longword_loop_end
	cmp/eq	r1,TMP
	bt.s	Longword_loop
	mov.l	@STR1+,r1
	add #-4, STR1
Longword_loop_end:
	add #-4, STR1
	add #-4, STR2
L_setup_char_loop:
	mov.b	@STR1+,r0
	.align  2
L_char_loop:
	mov.b	@STR2+,r1
	tst	r0,r0
	bt	L_return
	cmp/eq	r0,r1
	bt.s L_char_loop
	mov.b	@STR1+,r0
	add	#-2,STR1
	mov.b	@STR1,r0
#else /* ! DELAYED_BRANCHES */
	.align  2
Longword_loop:
	mov.l	@r4+,r1
	mov.l	@r5+,r2
	cmp/str	r0,r1
	bt	Longword_loop_end
	cmp/eq	r1,r2
	bt	Longword_loop
Longword_loop_end:
	add #-4, r4
	add #-4, r5
	.align  2
L_setup_char_loop:
L_char_loop:
	mov.b	@r4+,r0
	mov.b	@r5+,r1
	tst	r0,r0
	bt	L_return
	cmp/eq	r0,r1
	bt L_char_loop
#endif
L_return:
	extu.b	r0,RESULT
	extu.b	r1,r1
	rts
	sub	r1,RESULT
#endif /* ! __SHMEDIA__ */
