| /* |
| * strlen - calculate the length of a string |
| * |
| * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| * See https://llvm.org/LICENSE.txt for license information. |
| * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| */ |
| |
| #if __ARM_ARCH >= 6 && __ARM_ARCH_ISA_THUMB == 2 |
| |
| /* |
| Assumes: |
| ARMv6T2, AArch32 |
| |
| */ |
| |
| #include "../asmdefs.h" |
| |
| #ifdef __ARMEB__ |
| #define S2LO lsl |
| #define S2HI lsr |
| #else |
| #define S2LO lsr |
| #define S2HI lsl |
| #endif |
| |
| /* This code requires Thumb. */ |
| .thumb |
| .syntax unified |
| |
| /* Parameters and result. */ |
| #define srcin r0 |
| #define result r0 |
| |
| /* Internal variables. */ |
| #define src r1 |
| #define data1a r2 |
| #define data1b r3 |
| #define const_m1 r12 |
| #define const_0 r4 |
| #define tmp1 r4 /* Overlaps const_0 */ |
| #define tmp2 r5 |
| |
| ENTRY (__strlen_armv6t2) |
| pld [srcin, #0] |
| strd r4, r5, [sp, #-8]! |
| bic src, srcin, #7 |
| mvn const_m1, #0 |
| ands tmp1, srcin, #7 /* (8 - bytes) to alignment. */ |
| pld [src, #32] |
| bne.w L(misaligned8) |
| mov const_0, #0 |
| mov result, #-8 |
| L(loop_aligned): |
| /* Bytes 0-7. */ |
| ldrd data1a, data1b, [src] |
| pld [src, #64] |
| add result, result, #8 |
| L(start_realigned): |
| uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ |
| sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ |
| uadd8 data1b, data1b, const_m1 |
| sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ |
| cbnz data1b, L(null_found) |
| |
| /* Bytes 8-15. */ |
| ldrd data1a, data1b, [src, #8] |
| uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ |
| add result, result, #8 |
| sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ |
| uadd8 data1b, data1b, const_m1 |
| sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ |
| cbnz data1b, L(null_found) |
| |
| /* Bytes 16-23. */ |
| ldrd data1a, data1b, [src, #16] |
| uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ |
| add result, result, #8 |
| sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ |
| uadd8 data1b, data1b, const_m1 |
| sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ |
| cbnz data1b, L(null_found) |
| |
| /* Bytes 24-31. */ |
| ldrd data1a, data1b, [src, #24] |
| add src, src, #32 |
| uadd8 data1a, data1a, const_m1 /* Saturating GE<0:3> set. */ |
| add result, result, #8 |
| sel data1a, const_0, const_m1 /* Select based on GE<0:3>. */ |
| uadd8 data1b, data1b, const_m1 |
| sel data1b, data1a, const_m1 /* Only used if d1a == 0. */ |
| cmp data1b, #0 |
| beq L(loop_aligned) |
| |
| L(null_found): |
| cmp data1a, #0 |
| itt eq |
| addeq result, result, #4 |
| moveq data1a, data1b |
| #ifndef __ARMEB__ |
| rev data1a, data1a |
| #endif |
| clz data1a, data1a |
| ldrd r4, r5, [sp], #8 |
| add result, result, data1a, lsr #3 /* Bits -> Bytes. */ |
| bx lr |
| |
| L(misaligned8): |
| ldrd data1a, data1b, [src] |
| and tmp2, tmp1, #3 |
| rsb result, tmp1, #0 |
| lsl tmp2, tmp2, #3 /* Bytes -> bits. */ |
| tst tmp1, #4 |
| pld [src, #64] |
| S2HI tmp2, const_m1, tmp2 |
| orn data1a, data1a, tmp2 |
| itt ne |
| ornne data1b, data1b, tmp2 |
| movne data1a, const_m1 |
| mov const_0, #0 |
| b L(start_realigned) |
| |
| END (__strlen_armv6t2) |
| |
| #endif /* __ARM_ARCH >= 6 && __ARM_ARCH_ISA_THUMB == 2 */ |