more changes on original files
[linux-2.4.git] / arch / alpha / lib / ev67-strlen_user.S
1 /*
2  * arch/alpha/lib/ev67-strlen_user.S
3  * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
4  *
5  * Return the length of the string including the NULL terminator
6  * (strlen+1) or zero if an error occurred.
7  *
8  * In places where it is critical to limit the processing time,
9  * and the data is not trusted, strnlen_user() should be used.
10  * It will return a value greater than its second argument if
11  * that limit would be exceeded. This implementation is allowed
12  * to access memory beyond the limit, but will not cross a page
13  * boundary when doing so.
14  *
15  * Much of the information about 21264 scheduling/coding comes from:
16  *      Compiler Writer's Guide for the Alpha 21264
17  *      abbreviated as 'CWG' in other comments here
18  *      ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
19  * Scheduling notation:
20  *      E       - either cluster
21  *      U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
22  *      L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
23  * Try not to change the actual algorithm if possible for consistency.
24  */
25
26 #include <asm/regdef.h>
27
28
29 /* Allow an exception for an insn; exit if we get one.  */
30 #define EX(x,y...)                      \
31         99: x,##y;                      \
32         .section __ex_table,"a";        \
33         .gprel32 99b;                   \
34         lda v0, $exception-99b(zero);   \
35         .previous
36
37
38         .set noreorder
39         .set noat
40         .text
41
42         .globl __strlen_user
43         .ent __strlen_user
44         .frame sp, 0, ra
45
46         .align 4
47 __strlen_user:
48         ldah    a1, 32767(zero) # do not use plain strlen_user() for strings
49                                 # that might be almost 2 GB long; you should
50                                 # be using strnlen_user() instead
51         nop
52         nop
53         nop
54
55         .globl __strnlen_user
56
57         .align 4
58 __strnlen_user:
59         ldgp    $29,0($27)      # E E : we do exceptions -- we need the gp.
60                                 /* Decomposes into lda/ldah */
61         .prologue 1
62         EX( ldq_u t0, 0(a0) )   # L : load first quadword (a0 may be misaligned)
63         lda     t1, -1(zero)    # E :
64
65         insqh   t1, a0, t1      # U :
66         andnot  a0, 7, v0       # E :
67         or      t1, t0, t0      # E :
68         subq    a0, 1, a0       # E : get our +1 for the return 
69
70         cmpbge  zero, t0, t1    # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0
71         subq    a1, 7, t2       # E :
72         subq    a0, v0, t0      # E :
73         bne     t1, $found      # U :
74
75         addq    t2, t0, t2      # E :
76         addq    a1, 1, a1       # E :
77         nop                     # E :
78         nop                     # E :
79
80         .align 4
81 $loop:  ble     t2, $limit      # U :
82         EX( ldq t0, 8(v0) )     # L :
83         nop                     # E :
84         nop                     # E :
85
86         cmpbge  zero, t0, t1    # E :
87         subq    t2, 8, t2       # E :
88         addq    v0, 8, v0       # E : addr += 8
89         beq     t1, $loop       # U :
90
91 $found: cttz    t1, t2          # U0 :
92         addq    v0, t2, v0      # E :
93         subq    v0, a0, v0      # E :
94         ret                     # L0 :
95
96 $exception:
97         nop
98         nop
99         nop
100         ret
101
102         .align 4                # currently redundant
103 $limit:
104         nop
105         nop
106         subq    a1, t2, v0
107         ret
108
109         .end __strlen_user