xref: /aosp_15_r20/external/arm-optimized-routines/string/aarch64/strnlen.S (revision 412f47f9e737e10ed5cc46ec6a8d7fa2264f8a14)
1*412f47f9SXin Li/*
2*412f47f9SXin Li * strnlen - calculate the length of a string with limit.
3*412f47f9SXin Li *
4*412f47f9SXin Li * Copyright (c) 2020-2022, Arm Limited.
5*412f47f9SXin Li * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6*412f47f9SXin Li */
7*412f47f9SXin Li
8*412f47f9SXin Li/* Assumptions:
9*412f47f9SXin Li *
10*412f47f9SXin Li * ARMv8-a, AArch64, Advanced SIMD.
11*412f47f9SXin Li * MTE compatible.
12*412f47f9SXin Li */
13*412f47f9SXin Li
14*412f47f9SXin Li#include "asmdefs.h"
15*412f47f9SXin Li
16*412f47f9SXin Li#define srcin		x0
17*412f47f9SXin Li#define cntin		x1
18*412f47f9SXin Li#define result		x0
19*412f47f9SXin Li
20*412f47f9SXin Li#define src		x2
21*412f47f9SXin Li#define synd		x3
22*412f47f9SXin Li#define	shift		x4
23*412f47f9SXin Li#define tmp		x4
24*412f47f9SXin Li#define cntrem		x5
25*412f47f9SXin Li
26*412f47f9SXin Li#define qdata		q0
27*412f47f9SXin Li#define vdata		v0
28*412f47f9SXin Li#define vhas_chr	v1
29*412f47f9SXin Li#define vend		v2
30*412f47f9SXin Li#define dend		d2
31*412f47f9SXin Li
32*412f47f9SXin Li/*
33*412f47f9SXin Li   Core algorithm:
34*412f47f9SXin Li   Process the string in 16-byte aligned chunks. Compute a 64-bit mask with
35*412f47f9SXin Li   four bits per byte using the shrn instruction. A count trailing zeros then
36*412f47f9SXin Li   identifies the first zero byte.  */
37*412f47f9SXin Li
38*412f47f9SXin LiENTRY (__strnlen_aarch64)
39*412f47f9SXin Li	PTR_ARG (0)
40*412f47f9SXin Li	SIZE_ARG (1)
41*412f47f9SXin Li	bic	src, srcin, 15
42*412f47f9SXin Li	cbz	cntin, L(nomatch)
43*412f47f9SXin Li	ld1	{vdata.16b}, [src]
44*412f47f9SXin Li	cmeq	vhas_chr.16b, vdata.16b, 0
45*412f47f9SXin Li	lsl	shift, srcin, 2
46*412f47f9SXin Li	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
47*412f47f9SXin Li	fmov	synd, dend
48*412f47f9SXin Li	lsr	synd, synd, shift
49*412f47f9SXin Li	cbz	synd, L(start_loop)
50*412f47f9SXin LiL(finish):
51*412f47f9SXin Li	rbit	synd, synd
52*412f47f9SXin Li	clz	synd, synd
53*412f47f9SXin Li	lsr	result, synd, 2
54*412f47f9SXin Li	cmp	cntin, result
55*412f47f9SXin Li	csel	result, cntin, result, ls
56*412f47f9SXin Li	ret
57*412f47f9SXin Li
58*412f47f9SXin LiL(nomatch):
59*412f47f9SXin Li	mov	result, cntin
60*412f47f9SXin Li	ret
61*412f47f9SXin Li
62*412f47f9SXin LiL(start_loop):
63*412f47f9SXin Li	sub	tmp, src, srcin
64*412f47f9SXin Li	add	tmp, tmp, 17
65*412f47f9SXin Li	subs	cntrem, cntin, tmp
66*412f47f9SXin Li	b.lo	L(nomatch)
67*412f47f9SXin Li
68*412f47f9SXin Li	/* Make sure that it won't overread by a 16-byte chunk */
69*412f47f9SXin Li	tbz	cntrem, 4, L(loop32_2)
70*412f47f9SXin Li	sub	src, src, 16
71*412f47f9SXin Li	.p2align 5
72*412f47f9SXin LiL(loop32):
73*412f47f9SXin Li	ldr	qdata, [src, 32]!
74*412f47f9SXin Li	cmeq	vhas_chr.16b, vdata.16b, 0
75*412f47f9SXin Li	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
76*412f47f9SXin Li	fmov	synd, dend
77*412f47f9SXin Li	cbnz	synd, L(end)
78*412f47f9SXin LiL(loop32_2):
79*412f47f9SXin Li	ldr	qdata, [src, 16]
80*412f47f9SXin Li	subs	cntrem, cntrem, 32
81*412f47f9SXin Li	cmeq	vhas_chr.16b, vdata.16b, 0
82*412f47f9SXin Li	b.lo	L(end_2)
83*412f47f9SXin Li	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
84*412f47f9SXin Li	fmov	synd, dend
85*412f47f9SXin Li	cbz	synd, L(loop32)
86*412f47f9SXin LiL(end_2):
87*412f47f9SXin Li	add	src, src, 16
88*412f47f9SXin LiL(end):
89*412f47f9SXin Li	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
90*412f47f9SXin Li	sub	result, src, srcin
91*412f47f9SXin Li	fmov	synd, dend
92*412f47f9SXin Li#ifndef __AARCH64EB__
93*412f47f9SXin Li	rbit	synd, synd
94*412f47f9SXin Li#endif
95*412f47f9SXin Li	clz	synd, synd
96*412f47f9SXin Li	add	result, result, synd, lsr 2
97*412f47f9SXin Li	cmp	cntin, result
98*412f47f9SXin Li	csel	result, cntin, result, ls
99*412f47f9SXin Li	ret
100*412f47f9SXin Li
101*412f47f9SXin LiEND (__strnlen_aarch64)
102*412f47f9SXin Li
103