1/* Copyright (C) 2010-2021 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3
4   The GNU C Library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8
9   The GNU C Library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with the GNU C Library.  If not, see
16   <https://www.gnu.org/licenses/>.  */
17
18/*
19   Assumes:
20   ARMv6T2, AArch32
21
22 */
23
24#include <arm-features.h>
25#include <sysdep.h>
26
27#ifdef __ARMEB__
28#define S2LO		lsl
29#define S2HI		lsr
30#else
31#define S2LO		lsr
32#define S2HI		lsl
33#endif
34
35/* This code is best on Thumb.  */
36	.thumb
37
38/* Parameters and result.  */
39#define srcin		r0
40#define result		r0
41
42/* Internal variables.  */
43#define src		r1
44#define data1a		r2
45#define data1b		r3
46#define const_m1	r12
47#define const_0		r4
48#define tmp1		r4		/* Overlaps const_0  */
49#define tmp2		r5
50
51	.text
52	.p2align 6
53ENTRY(strlen)
54	pld	[srcin, #0]
55	strd	r4, r5, [sp, #-8]!
56	cfi_adjust_cfa_offset (8)
57	cfi_rel_offset (r4, 0)
58	cfi_rel_offset (r5, 4)
59	cfi_remember_state
60	bic	src, srcin, #7
61	mvn	const_m1, #0
62	ands	tmp1, srcin, #7		/* (8 - bytes) to alignment.  */
63	pld	[src, #32]
64	bne.w	.Lmisaligned8
65	mov	const_0, #0
66	mov	result, #-8
67.Lloop_aligned:
68	/* Bytes 0-7.  */
69	ldrd	data1a, data1b, [src]
70	pld	[src, #64]
71	add	result, result, #8
72.Lstart_realigned:
73	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
74	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
75	uadd8	data1b, data1b, const_m1
76	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
77	cbnz	data1b, .Lnull_found
78
79	/* Bytes 8-15.  */
80	ldrd	data1a, data1b, [src, #8]
81	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
82	add	result, result, #8
83	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
84	uadd8	data1b, data1b, const_m1
85	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
86	cbnz	data1b, .Lnull_found
87
88	/* Bytes 16-23.  */
89	ldrd	data1a, data1b, [src, #16]
90	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
91	add	result, result, #8
92	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
93	uadd8	data1b, data1b, const_m1
94	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
95	cbnz	data1b, .Lnull_found
96
97	/* Bytes 24-31.  */
98	ldrd	data1a, data1b, [src, #24]
99	add	src, src, #32
100	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
101	add	result, result, #8
102	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
103	uadd8	data1b, data1b, const_m1
104	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
105	cmp	data1b, #0
106	beq	.Lloop_aligned
107
108.Lnull_found:
109	cmp	data1a, #0
110	itt	eq
111	addeq	result, result, #4
112	moveq	data1a, data1b
113#ifndef __ARMEB__
114	rev	data1a, data1a
115#endif
116	clz	data1a, data1a
117	ldrd	r4, r5, [sp], #8
118	cfi_adjust_cfa_offset (-8)
119	cfi_restore (r4)
120	cfi_restore (r5)
121	add	result, result, data1a, lsr #3	/* Bits -> Bytes.  */
122	DO_RET(lr)
123
124.Lmisaligned8:
125	cfi_restore_state
126	ldrd	data1a, data1b, [src]
127	and	tmp2, tmp1, #3
128	rsb	result, tmp1, #0
129	lsl	tmp2, tmp2, #3			/* Bytes -> bits.  */
130	tst	tmp1, #4
131	pld	[src, #64]
132	S2HI	tmp2, const_m1, tmp2
133	orn	data1a, data1a, tmp2
134	itt	ne
135	ornne	data1b, data1b, tmp2
136	movne	data1a, const_m1
137	mov	const_0, #0
138	b	.Lstart_realigned
139
140END(strlen)
141libc_hidden_builtin_def (strlen)
142