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 
43 ENTRY (__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
53 L(loop_aligned):
54 	/* Bytes 0-7.  */
55 	ldrd	data1a, data1b, [src]
56 	pld	[src, #64]
57 	add	result, result, #8
58 L(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 
94 L(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 
107 L(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 
122 END (__strlen_armv6t2)
123 
124 #endif /* __ARM_ARCH >= 6 && __ARM_ARCH_ISA_THUMB == 2  */
125