xref: /freebsd/lib/libc/riscv/string/strchrnul.S (revision 08af0bbc9c7d71bbaadb31ad31f8492f40537c5c)
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2024 Strahinja Stanisic <strajabot@FreeBSD.org>
5 */
6
7#include <machine/asm.h>
8
9        .weak   strchrnul
10        .set    strchrnul, __strchrnul
11
12/*
13 * a0 - const char *str
14 * a1 - int c;
15 */
16ENTRY(__strchrnul)
17	/*
18	 * a0 - const char *ptr;
19	 * a1 - char cccccccc[8];
20	 * a2 - char iter[8];
21	 * a3 - char mask_end
22	 */
23
24	/* int to char */
25	andi a1, a1, 0xFF
26
27	/* t0 = 0x0101010101010101 */
28	li t0, 0x01010101
29	slli t1, t0, 32
30	or t0, t0, t1
31
32	/* t1 = 0x8080808080808080 */
33	slli t1, t0, 7
34
35	/* spread char across bytes */
36	mul a1, a1, t0
37
38	/* align_offset */
39	andi t2, a0, 0b111
40
41	/* align pointer */
42	andi a0, a0, ~0b111
43
44	/* if pointer is aligned skip to loop */
45	beqz t2, .Lloop
46
47	ld a2, (a0)
48
49	/* mask_start calculation */
50	slli t2, t2, 3
51	neg t2, t2
52	srl t2, t0, t2
53
54	/* fill bytes before start with non-zero */
55	or a3, a2, t2
56
57	xor a2, a2, a1
58	or a2, a2, t2
59
60	/* has_zero for \0 */
61	not t3, a3
62	not t2, a2
63	sub a3, a3, t0
64	sub a2, a2, t0
65	and a3, a3, t3
66	and a2, a2, t2
67	and a3, a3, t1
68	and a2, a2, t1
69
70
71	/* if \0 or c was found, exit */
72	or a2, a2, a3
73	addi a0, a0, 8
74	bnez a2, .Lfind_char
75
76
77.Lloop:
78	ld a2, (a0)
79
80	/* has_zero for both \0 or c */
81	xor a3, a2, a1
82
83	not t2, a2
84	not t3, a3
85	sub a2, a2, t0
86	sub a3, a3, t0
87	and a2, a2, t2
88	and a3, a3, t3
89	and a2, a2, t1
90	and a3, a3, t1
91
92	/* if \0 or c was found, exit */
93	or a2, a2, a3
94	addi a0, a0, 8
95	beqz a2, .Lloop
96
97.Lfind_char:
98	addi a0, a0, -8
99
100	/* isolate lowest set bit */
101	neg t0, a2
102	and a2, a2, t0
103
104	li t0, 0x0001020304050607
105	srli a2, a2, 7
106
107	/* lowest set bit is 2^(8*k)
108	 * multiplying by it shifts the idx array in t0 by k bytes to the left */
109	mul	a2, a2, t0
110
111	/* highest byte contains idx of first zero */
112	srli a2, a2, 56
113
114	add a0, a0, a2
115	ret
116END(__strchrnul)
117