1/*
2 * strlen - calculate the length of a string
3 *
4 * Copyright (c) 2010-2022, Arm Limited.
5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
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/* Ensure the .cantunwind directive is prepended to .fnend.
27   Leaf functions cannot throw exceptions - EHABI only supports
28   synchronous exceptions.  */
29#define IS_LEAF
30
31	/* This code requires Thumb.  */
32	.thumb
33	.syntax unified
34
35/* Parameters and result.  */
36#define srcin		r0
37#define result		r0
38
39/* Internal variables.  */
40#define src		r1
41#define data1a		r2
42#define data1b		r3
43#define const_m1	r12
44#define const_0		r4
45#define tmp1		r4		/* Overlaps const_0  */
46#define tmp2		r5
47
48ENTRY (__strlen_armv6t2)
49	prologue 4 5 push_ip=HAVE_PAC_LEAF
50	pld	[srcin, #0]
51	bic	src, srcin, #7
52	mvn	const_m1, #0
53	ands	tmp1, srcin, #7		/* (8 - bytes) to alignment.  */
54	pld	[src, #32]
55	bne.w	L(misaligned8)
56	mov	const_0, #0
57	mov	result, #-8
58L(loop_aligned):
59	/* Bytes 0-7.  */
60	ldrd	data1a, data1b, [src]
61	pld	[src, #64]
62	add	result, result, #8
63L(start_realigned):
64	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
65	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
66	uadd8	data1b, data1b, const_m1
67	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
68	cbnz	data1b, L(null_found)
69
70	/* Bytes 8-15.  */
71	ldrd	data1a, data1b, [src, #8]
72	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
73	add	result, result, #8
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, L(null_found)
78
79	/* Bytes 16-23.  */
80	ldrd	data1a, data1b, [src, #16]
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, L(null_found)
87
88	/* Bytes 24-31.  */
89	ldrd	data1a, data1b, [src, #24]
90	add	src, src, #32
91	uadd8	data1a, data1a, const_m1	/* Saturating GE<0:3> set.  */
92	add	result, result, #8
93	sel	data1a, const_0, const_m1	/* Select based on GE<0:3>.  */
94	uadd8	data1b, data1b, const_m1
95	sel	data1b, data1a, const_m1	/* Only used if d1a == 0.  */
96	cmp	data1b, #0
97	beq	L(loop_aligned)
98
99L(null_found):
100	.cfi_remember_state
101	cmp	data1a, #0
102	itt	eq
103	addeq	result, result, #4
104	moveq	data1a, data1b
105#ifndef __ARMEB__
106	rev	data1a, data1a
107#endif
108	clz	data1a, data1a
109	add	result, result, data1a, lsr #3	/* Bits -> Bytes.  */
110	epilogue 4 5 push_ip=HAVE_PAC_LEAF
111
112L(misaligned8):
113	.cfi_restore_state
114	ldrd	data1a, data1b, [src]
115	and	tmp2, tmp1, #3
116	rsb	result, tmp1, #0
117	lsl	tmp2, tmp2, #3			/* Bytes -> bits.  */
118	tst	tmp1, #4
119	pld	[src, #64]
120	S2HI	tmp2, const_m1, tmp2
121	orn	data1a, data1a, tmp2
122	itt	ne
123	ornne	data1b, data1b, tmp2
124	movne	data1a, const_m1
125	mov	const_0, #0
126	b	L(start_realigned)
127
128END (__strlen_armv6t2)
129
130#endif /* __ARM_ARCH >= 6 && __ARM_ARCH_ISA_THUMB == 2  */
131