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