/*
 * Copyright (C) 2004, 2007-2010, 2011-2014 Synopsys, Inc. All rights reserved.
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

/*
 * ARC700 has a relatively long pipeline and branch prediction, so we want
 * to avoid branches that are hard to predict.  On the other hand, the
 * presence of the norm instruction makes it easier to operate on whole
 * words branch-free.
 */

.global strchr
.align 4
strchr:
	extb_s	%r1, %r1
	asl	%r5, %r1, 8
	bmsk	%r2, %r0, 1
	or	%r5, %r5, %r1
	mov_s	%r3, 0x01010101
	breq.d	%r2, %r0, .Laligned
	asl	%r4, %r5, 16
	sub_s	%r0, %r0, %r2
	asl	%r7, %r2, 3
	ld_s	%r2, [%r0]
#ifdef __LITTLE_ENDIAN__
	asl	%r7, %r3, %r7
#else /* __BIG_ENDIAN__ */
	lsr	%r7, %r3, %r7
#endif /* _ENDIAN__ */
	or	%r5, %r5, %r4
	ror	%r4, %r3
	sub	%r12, %r2, %r7
	bic_s	%r12, %r12, %r2
	and	%r12, %r12, %r4
	brne.d	%r12, 0, .Lfound0_ua
	xor	%r6, %r2, %r5
	ld.a	%r2, [%r0, 4]
	sub	%r12, %r6, %r7
	bic	%r12, %r12, %r6
#ifdef __LITTLE_ENDIAN__
	and	%r7, %r12, %r4
	/* For speed, we want this branch to be unaligned. */
	breq	%r7, 0, .Loop
	/* Likewise this one */
	b	.Lfound_char
#else /* __BIG_ENDIAN__ */
	and	%r12, %r12, %r4
	/* For speed, we want this branch to be unaligned. */
	breq	%r12, 0, .Loop
	lsr_s	%r12, %r12, 7
	bic 	%r2, %r7, %r6
	b.d	.Lfound_char_b
	and_s	%r2, %r2, %r12
#endif /* _ENDIAN__ */
	/* We require this code address to be unaligned for speed...  */
.Laligned:
	ld_s	%r2, [%r0]
	or	%r5, %r5, %r4
	ror	%r4, %r3
	/* ... so that this code address is aligned, for itself and ...  */
.Loop:
	sub	%r12, %r2, %r3
	bic_s	%r12, %r12, %r2
	and	%r12, %r12, %r4
	brne.d	%r12, 0, .Lfound0
	xor	%r6, %r2, %r5
	ld.a	%r2, [%r0, 4]
	sub	%r12, %r6, %r3
	bic	%r12, %r12, %r6
	and	%r7, %r12, %r4
	breq	%r7, 0, .Loop
	/*
	 *... so that this branch is unaligned.
	 * Found searched-for character.
	 * r0 has already advanced to next word.
	 */
#ifdef __LITTLE_ENDIAN__
	/*
	 * We only need the information about the first matching byte
	 * (i.e. the least significant matching byte) to be exact,
	 * hence there is no problem with carry effects.
	 */
.Lfound_char:
	sub	%r3, %r7, 1
	bic	%r3, %r3, %r7
	norm	%r2, %r3
	sub_s	%r0, %r0, 1
	asr_s	%r2, %r2, 3
	j.d	[%blink]
	sub_s	%r0, %r0, %r2

	.balign	4
.Lfound0_ua:
	mov	%r3, %r7
.Lfound0:
	sub	%r3, %r6, %r3
	bic	%r3, %r3, %r6
	and	%r2, %r3, %r4
	or_s	%r12, %r12, %r2
	sub_s	%r3, %r12, 1
	bic_s	%r3, %r3, %r12
	norm	%r3, %r3
	add_s	%r0, %r0, 3
	asr_s	%r12, %r3, 3
	asl.f	0, %r2, %r3
	sub_s	%r0, %r0, %r12
	j_s.d	[%blink]
	mov.pl	%r0, 0
#else /* __BIG_ENDIAN__ */
.Lfound_char:
	lsr	%r7, %r7, 7

	bic	%r2, %r7, %r6
.Lfound_char_b:
	norm	%r2, %r2
	sub_s	%r0, %r0, 4
	asr_s	%r2, %r2, 3
	j.d	[%blink]
	add_s	%r0, %r0, %r2

.Lfound0_ua:
	mov_s	%r3, %r7
.Lfound0:
	asl_s	%r2, %r2, 7
	or	%r7, %r6, %r4
	bic_s	%r12, %r12, %r2
	sub	%r2, %r7, %r3
	or	%r2, %r2, %r6
	bic	%r12, %r2, %r12
	bic.f	%r3, %r4, %r12
	norm	%r3, %r3

	add.pl	%r3, %r3, 1
	asr_s	%r12, %r3, 3
	asl.f	0, %r2, %r3
	add_s	%r0, %r0, %r12
	j_s.d	[%blink]
	mov.mi	%r0, 0
#endif /* _ENDIAN__ */
