diff options
Diffstat (limited to 'newlib/libc/machine/hppa/strlen.S')
-rw-r--r-- | newlib/libc/machine/hppa/strlen.S | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/newlib/libc/machine/hppa/strlen.S b/newlib/libc/machine/hppa/strlen.S new file mode 100644 index 0000000..301ead5 --- /dev/null +++ b/newlib/libc/machine/hppa/strlen.S @@ -0,0 +1,79 @@ +/* + * (c) Copyright 1986 HEWLETT-PACKARD COMPANY + * + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: + * permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies, and that the name of Hewlett-Packard Company not be + * used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Hewlett-Packard Company makes no representations about the + * suitability of this software for any purpose. + */ + +/* HPUX_ID = "@(#) $Revision: 1.1 $" */ +/* strlen(s): Return length of string s */ + +#define start arg0 +#define end ret0 +#define tmp1 arg1 +#define tmp2 arg2 + +#include "DEFS.h" + +ENTRY(strlen) + movb,=,n start,end,$null_ptr + depi 0,31,2,end + comb,<> start,end,$not_aligned + ldws,ma 4(end),tmp1 + comib,tr 0,0,$loop /* avoid INDIGO two register interlock */ + uxor,nbz 0,tmp1,0 +$not_aligned: + /* + ; Tricky code. The problem is that the value of of the word + ; including the start of the string has some garbage bytes that + ; may be 0. We don't want them to stop the string scan. So + ; we make those bytes non-zero (and any old non-zero value + ; will do). Notice that the end pointer has been rounded + ; down to a word boundary, and then incremented to the next + ; word by the time we get here. Therefore, (start-end) has + ; one of the values (-3, -2, or -1). Use uaddcm to do the + ; subtraction (instead of sub), and the result will be + ; (-4, -3, or -2). Multiply this by 8, and put into the + ; shift register (which truncates to the last 5 bits) and + ; the value will be (0, 8, or 16). Use this as a bit position, + ; and drop a mask down into tmp1. All the garbage bytes will + ; have at least 1 bit affected by the vdepi, so all the garbage + ; in this first word will be non-zero garbage. + */ + uaddcm start,end,tmp2 /* tmp2 <- { -4, -3, -2 } */ + sh3add tmp2,0,tmp2 /* tmp2 <- { -32, -24, -16 } */ + mtsar tmp2 /* sar <- { 0, 8, 16 } */ + vdepi -1,32,tmp1 + uxor,nbz 0,tmp1,0 +$loop: + b,n $end_loop + ldws,ma 4(end),tmp1 + comib,tr 0,0,$loop /* avoid INDIGO two register interlock */ + uxor,nbz 0,tmp1,0 +$end_loop: + /* adjust the end pointer to one past the end of the string */ + extru,<> tmp1,7,8,0 + addib,tr,n -3,end,$out + extru,<> tmp1,15,8,0 + addib,tr,n -2,end,$out + extru,<> tmp1,23,8,0 + addi -1,end,end +$out: + bv 0(rp) + /* + ; tricky code. the end pointer is just beyond the terminating + ; null byte, so the length is (end-start-1). use uaddcm + ; to do this in 1 instruction + */ + uaddcm end,start,ret0 + +$null_ptr: +EXIT(strlen) |