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