1/*
2   Copyright (c) 2015-2024, Synopsys, Inc. All rights reserved.
3
4   Redistribution and use in source and binary forms, with or without
5   modification, are permitted provided that the following conditions are met:
6
7   1) Redistributions of source code must retain the above copyright notice,
8   this list of conditions and the following disclaimer.
9
10   2) Redistributions in binary form must reproduce the above copyright notice,
11   this list of conditions and the following disclaimer in the documentation
12   and/or other materials provided with the distribution.
13
14   3) Neither the name of the Synopsys, Inc., nor the names of its contributors
15   may be used to endorse or promote products derived from this software
16   without specific prior written permission.
17
18   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28   POSSIBILITY OF SUCH DAMAGE.
29*/
30
31/* This implementation is optimized for performance.  For code size a generic
32   implementation of this function from newlib/libc/string/strchr.c will be
33   used.  */
34#include <picolibc.h>
35
36#if !defined (__OPTIMIZE_SIZE__) && !defined (PREFER_SIZE_OVER_SPEED) \
37    && !defined (__ARC_RF16__)
38
39/* ARC700 has a relatively long pipeline and branch prediction, so we want
40   to avoid branches that are hard to predict.  On the other hand, the
41   presence of the norm instruction makes it easier to operate on whole
42   words branch-free.  */
43#include "asm.h"
44
45#if (defined (__ARC700__) || defined (__ARCEM__) || defined (__ARCHS__)) \
46    && defined (__ARC_NORM__) && defined (__ARC_BARREL_SHIFTER__)
47
48ENTRY (strchr)
49	extb_s	r1,r1
50	asl	r5,r1,8
51	bmsk	r2,r0,1
52	or	r5,r5,r1
53	mov_s	r3,0x01010101
54	breq.d	r2,r0,.Laligned
55	asl	r4,r5,16
56	sub_s	r0,r0,r2
57	asl	r7,r2,3
58	ld_s	r2,[r0]
59#ifdef __LITTLE_ENDIAN__
60	asl	r7,r3,r7
61#else
62	lsr	r7,r3,r7
63#endif
64	or	r5,r5,r4
65	ror	r4,r3
66	sub	r12,r2,r7
67	bic_s	r12,r12,r2
68	and	r12,r12,r4
69	brne.d	r12,0,.Lfound0_ua
70	xor	r6,r2,r5
71	ld.a	r2,[r0,4]
72	sub	r12,r6,r7
73	bic	r12,r12,r6
74#ifdef __LITTLE_ENDIAN__
75	and	r7,r12,r4
76	breq	r7,0,.Loop ; For speed, we want this branch to be unaligned.
77	b_l	.Lfound_char ; Likewise this one.
78#else
79	and	r12,r12,r4
80	breq_l	r12,0,.Loop ; For speed, we want this branch to be unaligned.
81	lsr_s	r12,r12,7
82	bic	r2,r7,r6
83	b.d	.Lfound_char_b
84	and_s	r2,r2,r12
85#endif
86; /* We require this code address to be unaligned for speed...  */
87.Laligned:
88	ld_s	r2,[r0]
89	or	r5,r5,r4
90	ror	r4,r3
91; /* ... so that this code address is aligned, for itself and ...  */
92.Loop:
93	sub	r12,r2,r3
94	bic_s	r12,r12,r2
95	and	r12,r12,r4
96	brne.d	r12,0,.Lfound0
97	xor	r6,r2,r5
98	ld.a	r2,[r0,4]
99	sub	r12,r6,r3
100	bic	r12,r12,r6
101	and	r7,r12,r4
102	breq	r7,0,.Loop /* ... so that this branch is unaligned.  */
103	; Found searched-for character.  r0 has already advanced to next word.
104#ifdef __LITTLE_ENDIAN__
105/* We only need the information about the first matching byte
106   (i.e. the least significant matching byte) to be exact,
107   hence there is no problem with carry effects.  */
108.Lfound_char:
109	sub	r3,r7,1
110	bic	r3,r3,r7
111	norm	r2,r3
112	sub_s	r0,r0,1
113	asr_s	r2,r2,3
114	j_l.d	[blink]
115	sub_s	r0,r0,r2
116
117	.balign	4
118.Lfound0_ua:
119	mov_l	r3,r7
120.Lfound0:
121	sub	r3,r6,r3
122	bic	r3,r3,r6
123	and	r2,r3,r4
124	or_s	r12,r12,r2
125	sub_s	r3,r12,1
126	bic_s	r3,r3,r12
127	norm	r3,r3
128	add_s	r0,r0,3
129	asr_s	r12,r3,3
130	asl.f	0,r2,r3
131	sub_s	r0,r0,r12
132	j_s.d	[blink]
133	mov.pl	r0,0
134#else /* BIG ENDIAN */
135.Lfound_char:
136	lsr	r7,r7,7
137
138	bic	r2,r7,r6
139.Lfound_char_b:
140	norm	r2,r2
141	sub_s	r0,r0,4
142	asr_s	r2,r2,3
143	j_l.d	[blink]
144	add_s	r0,r0,r2
145
146.Lfound0_ua:
147	mov_s	r3,r7
148.Lfound0:
149	asl_s	r2,r2,7
150	or	r7,r6,r4
151	bic_s	r12,r12,r2
152	sub	r2,r7,r3
153	or	r2,r2,r6
154	bic	r12,r2,r12
155	bic.f	r3,r4,r12
156	norm	r3,r3
157
158	add.pl	r3,r3,1
159	asr_s	r12,r3,3
160	asl.f	0,r2,r3
161	add_s	r0,r0,r12
162	j_s.d	[blink]
163	mov.mi	r0,0
164#endif /* ENDIAN */
165ENDFUNC (strchr)
166#endif /* (__ARC700__ || __ARCEM__ || __ARCHS__) && __ARC_NORM__
167    && __ARC_BARREL_SHIFTER__ */
168
169#endif /* !__OPTIMIZE_SIZE__ && !PREFER_SIZE_OVER_SPEED */
170