1/*
2 * strlen - calculate the length of a string
3 *
4 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 * See https://llvm.org/LICENSE.txt for license information.
6 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 */
8
9#if __ARM_ARCH >= 6 && __ARM_ARCH_ISA_THUMB == 2
10
11/*
12   Assumes:
13   ARMv6T2, AArch32
14
15 */
16
17#include "../asmdefs.h"
18
19#ifdef __ARMEB__
20#define S2LO		lsl
21#define S2HI		lsr
22#else
23#define S2LO		lsr
24#define S2HI		lsl
25#endif
26
27	/* This code requires Thumb.  */
28	.thumb
29	.syntax unified
30
31/* Parameters and result.  */
32#define srcin		r0
33#define result		r0
34
35/* Internal variables.  */
36#define src		r1
37#define data1a		r2
38#define data1b		r3
39#define const_m1	r12
40#define const_0		r4
41#define tmp1		r4		/* Overlaps const_0  */
42#define tmp2		r5
43
44ENTRY (__strlen_armv6t2)
45	pld	[srcin, #0]
46	strd	r4, r5, [sp, #-8]!
47	bic	src, srcin, #7
48	mvn	const_m1, #0
49	ands	tmp1, srcin, #7		/* (8 - bytes) to alignment.  */
50	pld	[src, #32]
51	bne.w	L(misaligned8)
52	mov	const_0, #0
53	mov	result, #-8
54L(loop_aligned):
55	/* Bytes 0-7.  */
56	ldrd	data1a, data1b, [src]
57	pld	[src, #64]
58	add	result, result, #8
59L(start_realigned):
60	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
61	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
62	uadd8	data1b, data1b, const_m1
63	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
64	cbnz	data1b, L(null_found)
65
66	/* Bytes 8-15.  */
67	ldrd	data1a, data1b, [src, #8]
68	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
69	add	result, result, #8
70	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
71	uadd8	data1b, data1b, const_m1
72	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
73	cbnz	data1b, L(null_found)
74
75	/* Bytes 16-23.  */
76	ldrd	data1a, data1b, [src, #16]
77	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
78	add	result, result, #8
79	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
80	uadd8	data1b, data1b, const_m1
81	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
82	cbnz	data1b, L(null_found)
83
84	/* Bytes 24-31.  */
85	ldrd	data1a, data1b, [src, #24]
86	add	src, src, #32
87	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
88	add	result, result, #8
89	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
90	uadd8	data1b, data1b, const_m1
91	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
92	cmp	data1b, #0
93	beq	L(loop_aligned)
94
95L(null_found):
96	cmp	data1a, #0
97	itt	eq
98	addeq	result, result, #4
99	moveq	data1a, data1b
100#ifndef __ARMEB__
101	rev	data1a, data1a
102#endif
103	clz	data1a, data1a
104	ldrd	r4, r5, [sp], #8
105	add	result, result, data1a, lsr #3	/* Bits -> Bytes.  */
106	bx	lr
107
108L(misaligned8):
109	ldrd	data1a, data1b, [src]
110	and	tmp2, tmp1, #3
111	rsb	result, tmp1, #0
112	lsl	tmp2, tmp2, #3			/* Bytes -> bits.  */
113	tst	tmp1, #4
114	pld	[src, #64]
115	S2HI	tmp2, const_m1, tmp2
116	orn	data1a, data1a, tmp2
117	itt	ne
118	ornne	data1b, data1b, tmp2
119	movne	data1a, const_m1
120	mov	const_0, #0
121	b	L(start_realigned)
122
123END (__strlen_armv6t2)
124
125#endif /* __ARM_ARCH >= 6 && __ARM_ARCH_ISA_THUMB == 2  */
126