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#include <picolibc.h>
20
21#define start   arg0
22#define end     ret0
23#define tmp1    arg1
24#define tmp2    arg2
25
26#include "DEFS.h"
27
28ENTRY(strlen)
29        movb,=,n        start,end,$null_ptr
30        depi            0,31,2,end
31        comb,<>         start,end,$not_aligned
32        ldws,ma         4(end),tmp1
33        comib,tr        0,0,$loop       /* avoid INDIGO two register interlock */
34        uxor,nbz        0,tmp1,0
35$not_aligned:
36        /*
37        ;       Tricky code.  The problem is that the value of of the word
38        ;       including the start of the string has some garbage bytes that
39        ;       may be 0.  We don't want them to stop the string scan.  So
40        ;       we make those bytes non-zero (and any old non-zero value
41        ;       will do).  Notice that the end pointer has been rounded
42        ;       down to a word boundary, and then incremented to the next
43        ;       word by the time we get here.  Therefore, (start-end) has
44        ;       one of the values (-3, -2, or -1).  Use uaddcm to do the
45        ;       subtraction (instead of sub), and the result will be
46        ;       (-4, -3, or -2).  Multiply this by 8, and put into the
47        ;       shift register (which truncates to the last 5 bits) and
48        ;       the value will be (0, 8, or 16).  Use this as a bit position,
49        ;       and drop a mask down into tmp1.  All the garbage bytes will
50        ;       have at least 1 bit affected by the vdepi, so all the garbage
51        ;       in this first word will be non-zero garbage.
52        */
53        uaddcm          start,end,tmp2  /*  tmp2 <- {  -4,  -3,  -2 } */
54        sh3add          tmp2,0,tmp2     /*  tmp2 <- { -32, -24, -16 } */
55        mtsar           tmp2            /*  sar  <- {   0,   8,  16 } */
56        vdepi           -1,32,tmp1
57        uxor,nbz        0,tmp1,0
58$loop:
59        b,n             $end_loop
60        ldws,ma         4(end),tmp1
61        comib,tr        0,0,$loop       /* avoid INDIGO two register interlock */
62        uxor,nbz        0,tmp1,0
63$end_loop:
64        /*       adjust the end pointer to one past the end of the string */
65        extru,<>        tmp1,7,8,0
66        addib,tr,n      -3,end,$out
67        extru,<>        tmp1,15,8,0
68        addib,tr,n      -2,end,$out
69        extru,<>        tmp1,23,8,0
70        addi            -1,end,end
71$out:
72        bv              0(rp)
73        /*
74        ;       tricky code.  the end pointer is just beyond the terminating
75        ;       null byte, so the length is (end-start-1).  use uaddcm
76        ;       to do this in 1 instruction
77        */
78        uaddcm          end,start,ret0
79
80$null_ptr:
81EXIT(strlen)
82