1/*
2 *  (c) Copyright 1986 HEWLETT-PACKARD COMPANY
3 *
4 *  To anyone who acknowledges that this file is provided "AS IS"
5 *  without any express or implied warranty:
6 *      permission to use, copy, modify, and distribute this file
7 *  for any purpose is hereby granted without fee, provided that
8 *  the above copyright notice and this notice appears in all
9 *  copies, and that the name of Hewlett-Packard Company not be
10 *  used in advertising or publicity pertaining to distribution
11 *  of the software without specific, written prior permission.
12 *  Hewlett-Packard Company makes no representations about the
13 *  suitability of this software for any purpose.
14 */
15
16/* HPUX_ID = "@(#) $Revision$" */
17/* strlen(s): Return length of string s */
18
19#define start   arg0
20#define end     ret0
21#define tmp1    arg1
22#define tmp2    arg2
23
24#include "DEFS.h"
25
26ENTRY(strlen)
27        movb,=,n        start,end,$null_ptr
28        depi            0,31,2,end
29        comb,<>         start,end,$not_aligned
30        ldws,ma         4(end),tmp1
31        comib,tr        0,0,$loop       /* avoid INDIGO two register interlock */
32        uxor,nbz        0,tmp1,0
33$not_aligned:
34        /*
35        ;       Tricky code.  The problem is that the value of of the word
36        ;       including the start of the string has some garbage bytes that
37        ;       may be 0.  We don't want them to stop the string scan.  So
38        ;       we make those bytes non-zero (and any old non-zero value
39        ;       will do).  Notice that the end pointer has been rounded
40        ;       down to a word boundary, and then incremented to the next
41        ;       word by the time we get here.  Therefore, (start-end) has
42        ;       one of the values (-3, -2, or -1).  Use uaddcm to do the
43        ;       subtraction (instead of sub), and the result will be
44        ;       (-4, -3, or -2).  Multiply this by 8, and put into the
45        ;       shift register (which truncates to the last 5 bits) and
46        ;       the value will be (0, 8, or 16).  Use this as a bit position,
47        ;       and drop a mask down into tmp1.  All the garbage bytes will
48        ;       have at least 1 bit affected by the vdepi, so all the garbage
49        ;       in this first word will be non-zero garbage.
50        */
51        uaddcm          start,end,tmp2  /*  tmp2 <- {  -4,  -3,  -2 } */
52        sh3add          tmp2,0,tmp2     /*  tmp2 <- { -32, -24, -16 } */
53        mtsar           tmp2            /*  sar  <- {   0,   8,  16 } */
54        vdepi           -1,32,tmp1
55        uxor,nbz        0,tmp1,0
56$loop:
57        b,n             $end_loop
58        ldws,ma         4(end),tmp1
59        comib,tr        0,0,$loop       /* avoid INDIGO two register interlock */
60        uxor,nbz        0,tmp1,0
61$end_loop:
62        /*       adjust the end pointer to one past the end of the string */
63        extru,<>        tmp1,7,8,0
64        addib,tr,n      -3,end,$out
65        extru,<>        tmp1,15,8,0
66        addib,tr,n      -2,end,$out
67        extru,<>        tmp1,23,8,0
68        addi            -1,end,end
69$out:
70        bv              0(rp)
71        /*
72        ;       tricky code.  the end pointer is just beyond the terminating
73        ;       null byte, so the length is (end-start-1).  use uaddcm
74        ;       to do this in 1 instruction
75        */
76        uaddcm          end,start,ret0
77
78$null_ptr:
79EXIT(strlen)
80