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