1 1.5 jakllsch /* $NetBSD: strlen.S,v 1.5 2020/09/09 14:49:27 jakllsch Exp $ */ 2 1.1 matt 3 1.1 matt /*- 4 1.1 matt * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 1.1 matt * All rights reserved. 6 1.1 matt * 7 1.1 matt * This code is derived from software contributed to The NetBSD Foundation 8 1.1 matt * by Matt Thomas of 3am Software Foundry. 9 1.1 matt * 10 1.1 matt * Redistribution and use in source and binary forms, with or without 11 1.1 matt * modification, are permitted provided that the following conditions 12 1.1 matt * are met: 13 1.1 matt * 1. Redistributions of source code must retain the above copyright 14 1.1 matt * notice, this list of conditions and the following disclaimer. 15 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 matt * notice, this list of conditions and the following disclaimer in the 17 1.1 matt * documentation and/or other materials provided with the distribution. 18 1.1 matt * 19 1.1 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 matt * POSSIBILITY OF SUCH DAMAGE. 30 1.1 matt */ 31 1.1 matt 32 1.1 matt #include <machine/asm.h> 33 1.1 matt 34 1.5 jakllsch RCSID("$NetBSD: strlen.S,v 1.5 2020/09/09 14:49:27 jakllsch Exp $") 35 1.1 matt 36 1.1 matt #ifdef STRNLEN 37 1.1 matt #define FUNCNAME strnlen 38 1.1 matt /* LINTSTUB: size_t strnlen(const char *, size_t); */ 39 1.1 matt #else 40 1.1 matt #define FUNCNAME strlen 41 1.1 matt /* LINTSTUB: size_t strlen(const char *); */ 42 1.1 matt #endif 43 1.1 matt 44 1.1 matt #define MASK8_0x01 0x0101010101010101 45 1.1 matt #define MASK8_0x7f 0x7f7f7f7f7f7f7f7f 46 1.1 matt 47 1.1 matt ENTRY(FUNCNAME) 48 1.1 matt mov x4, x0 /* need x0 for return */ 49 1.1 matt add x9, x0, #8 /* start + dword */ 50 1.2 ryo bic x9, x9, #7 /* and aligned */ 51 1.1 matt #ifdef STRNLEN 52 1.3 ryo adds x10, x0, x1 /* x10 = s + maxlen */ 53 1.3 ryo b.cc 1f /* if go past, */ 54 1.3 ryo mvn x10, xzr /* set limit 0xffffffffffffffff */ 55 1.3 ryo 1: 56 1.1 matt #endif 57 1.1 matt mov x11, #MASK8_0x01 /* test mask */ 58 1.1 matt 59 1.1 matt ands x3, x4, #7 /* extract alignment */ 60 1.1 matt neg x0, x3 /* alignment fixup */ 61 1.1 matt b.eq .Lstrlen_dword_loop /* already dword aligned */ 62 1.1 matt 63 1.1 matt /* 64 1.1 matt * Load the dword containing the leading bytes. Make sure bytes 65 1.1 matt * before the data won't match as NUL. 66 1.1 matt */ 67 1.1 matt add x4, x4, x0 /* make dword aligned */ 68 1.1 matt ldr x7, [x4], #8 /* load dword */ 69 1.5 jakllsch #ifdef __AARCH64EB__ 70 1.5 jakllsch rev x7, x7 /* convert to LE */ 71 1.5 jakllsch #endif 72 1.1 matt lsl x3, x3, #3 /* convert bytes to bits */ 73 1.1 matt lsl x5, x11, x3 /* make mask for LE */ 74 1.1 matt eor x5, x5, x11 /* invert mask */ 75 1.1 matt orr x7, x7, x5 /* prevent NULs */ 76 1.1 matt b .Lstrlen_dword_loop_noload 77 1.1 matt 78 1.1 matt .Lstrlen_dword_loop: 79 1.1 matt #ifdef STRNLEN 80 1.1 matt cmp x4, x10 81 1.3 ryo b.hs .Lstrlen_done 82 1.1 matt #endif 83 1.1 matt ldr x7, [x4], #8 /* load dword */ 84 1.5 jakllsch #ifdef __AARCH64EB__ 85 1.5 jakllsch rev x7, x7 /* convert to LE */ 86 1.5 jakllsch #endif 87 1.1 matt .Lstrlen_dword_loop_noload: 88 1.1 matt /* 89 1.1 matt * Use the formula (X - 1) & ~(X | 0x7f) to find NUL bytes. 90 1.1 matt * Any NUL byte found will be replaced by 0x80 otherwise any byte 91 1.1 matt * will be replaced by 0x00. 92 1.1 matt */ 93 1.1 matt sub x6, x7, x11 /* a = X - 1 */ 94 1.1 matt orr x7, x7, #MASK8_0x7f /* b = X | 0x7f */ 95 1.1 matt bic x6, x6, x7 /* a & ~b */ 96 1.1 matt cbz x6, .Lstrlen_dword_loop /* no NULs so get next dword */ 97 1.1 matt 98 1.1 matt /* 99 1.1 matt * We know there is a NUL in this dword. Use clz to find it. 100 1.1 matt */ 101 1.2 ryo rev x6, x6 /* convert to BE */ 102 1.2 ryo clz x6, x6 /* find null byte */ 103 1.2 ryo add x0, x0, x6, lsr #3 /* add offset to the length */ 104 1.1 matt 105 1.1 matt add x0, x0, x4 /* add end to the length */ 106 1.1 matt sub x0, x0, x9 /* subtract start from the length */ 107 1.1 matt #ifdef STRNLEN 108 1.1 matt cmp x0, x1 /* did we go too far? */ 109 1.3 ryo csel x0, x0, x1, lo /* yes, return max length */ 110 1.1 matt #endif 111 1.1 matt ret 112 1.1 matt #ifdef STRNLEN 113 1.1 matt .Lstrlen_done: 114 1.1 matt mov x0, x1 115 1.1 matt ret 116 1.1 matt #endif 117 1.1 matt END(FUNCNAME) 118