Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / arch / ia64 / lib / strlen_user.S
1 /*
2  * Optimized version of the strlen_user() function
3  *
4  * Inputs:
5  *      in0     address of buffer
6  *
7  * Outputs:
8  *      ret0    0 in case of fault, strlen(buffer)+1 otherwise
9  *
10  * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
11  *      David Mosberger-Tang <davidm@hpl.hp.com>
12  *      Stephane Eranian <eranian@hpl.hp.com>
13  *
14  * 01/19/99 S.Eranian heavily enhanced version (see details below)
15  * 09/24/99 S.Eranian added speculation recovery code
16  */
17
18 #include <asm/asmmacro.h>
19 #include <asm/export.h>
20
21 //
22 // int strlen_user(char *)
23 // ------------------------
24 // Returns:
25 //      - length of string + 1
26 //      - 0 in case an exception is raised
27 //
28 // This is an enhanced version of the basic strlen_user. it includes a
29 // combination of compute zero index (czx), parallel comparisons, speculative
30 // loads and loop unroll using rotating registers.
31 //
32 // General Ideas about the algorithm:
33 //        The goal is to look at the string in chunks of 8 bytes.
34 //        so we need to do a few extra checks at the beginning because the
35 //        string may not be 8-byte aligned. In this case we load the 8byte
36 //        quantity which includes the start of the string and mask the unused
37 //        bytes with 0xff to avoid confusing czx.
38 //        We use speculative loads and software pipelining to hide memory
39 //        latency and do read ahead safely. This way we defer any exception.
40 //
41 //        Because we don't want the kernel to be relying on particular
42 //        settings of the DCR register, we provide recovery code in case
43 //        speculation fails. The recovery code is going to "redo" the work using
44 //        only normal loads. If we still get a fault then we return an
45 //        error (ret0=0). Otherwise we return the strlen+1 as usual.
46 //        The fact that speculation may fail can be caused, for instance, by
47 //        the DCR.dm bit being set. In this case TLB misses are deferred, i.e.,
48 //        a NaT bit will be set if the translation is not present. The normal
49 //        load, on the other hand, will cause the translation to be inserted
50 //        if the mapping exists.
51 //
52 //        It should be noted that we execute recovery code only when we need
53 //        to use the data that has been speculatively loaded: we don't execute
54 //        recovery code on pure read ahead data.
55 //
56 // Remarks:
57 //      - the cmp r0,r0 is used as a fast way to initialize a predicate
58 //        register to 1. This is required to make sure that we get the parallel
59 //        compare correct.
60 //
61 //      - we don't use the epilogue counter to exit the loop but we need to set
62 //        it to zero beforehand.
63 //
64 //      - after the loop we must test for Nat values because neither the
65 //        czx nor cmp instruction raise a NaT consumption fault. We must be
66 //        careful not to look too far for a Nat for which we don't care.
67 //        For instance we don't need to look at a NaT in val2 if the zero byte
68 //        was in val1.
69 //
70 //      - Clearly performance tuning is required.
71 //
72
73 #define saved_pfs       r11
74 #define tmp             r10
75 #define base            r16
76 #define orig            r17
77 #define saved_pr        r18
78 #define src             r19
79 #define mask            r20
80 #define val             r21
81 #define val1            r22
82 #define val2            r23
83
84 GLOBAL_ENTRY(__strlen_user)
85         .prologue
86         .save ar.pfs, saved_pfs
87         alloc saved_pfs=ar.pfs,11,0,0,8
88
89         .rotr v[2], w[2]        // declares our 4 aliases
90
91         extr.u tmp=in0,0,3      // tmp=least significant 3 bits
92         mov orig=in0            // keep trackof initial byte address
93         dep src=0,in0,0,3       // src=8byte-aligned in0 address
94         .save pr, saved_pr
95         mov saved_pr=pr         // preserve predicates (rotation)
96         ;;
97
98         .body
99
100         ld8.s v[1]=[src],8      // load the initial 8bytes (must speculate)
101         shl tmp=tmp,3           // multiply by 8bits/byte
102         mov mask=-1             // our mask
103         ;;
104         ld8.s w[1]=[src],8      // load next 8 bytes in 2nd pipeline
105         cmp.eq p6,p0=r0,r0      // sets p6 (required because of // cmp.and)
106         sub tmp=64,tmp          // how many bits to shift our mask on the right
107         ;;
108         shr.u   mask=mask,tmp   // zero enough bits to hold v[1] valuable part
109         mov ar.ec=r0            // clear epilogue counter (saved in ar.pfs)
110         ;;
111         add base=-16,src        // keep track of aligned base
112         chk.s v[1], .recover    // if already NaT, then directly skip to recover
113         or v[1]=v[1],mask       // now we have a safe initial byte pattern
114         ;;
115 1:
116         ld8.s v[0]=[src],8      // speculatively load next
117         czx1.r val1=v[1]        // search 0 byte from right
118         czx1.r val2=w[1]        // search 0 byte from right following 8bytes
119         ;;
120         ld8.s w[0]=[src],8      // speculatively load next to next
121         cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8
122         cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8
123 (p6)    br.wtop.dptk.few 1b     // loop until p6 == 0
124         ;;
125         //
126         // We must return try the recovery code iff
127         // val1_is_nat || (val1==8 && val2_is_nat)
128         //
129         // XXX Fixme
130         //      - there must be a better way of doing the test
131         //
132         cmp.eq  p8,p9=8,val1    // p6 = val1 had zero (disambiguate)
133         tnat.nz p6,p7=val1      // test NaT on val1
134 (p6)    br.cond.spnt .recover   // jump to recovery if val1 is NaT
135         ;;
136         //
137         // if we come here p7 is true, i.e., initialized for // cmp
138         //
139         cmp.eq.and  p7,p0=8,val1// val1==8?
140         tnat.nz.and p7,p0=val2  // test NaT if val2
141 (p7)    br.cond.spnt .recover   // jump to recovery if val2 is NaT
142         ;;
143 (p8)    mov val1=val2           // val2 contains the value
144 (p8)    adds src=-16,src        // correct position when 3 ahead
145 (p9)    adds src=-24,src        // correct position when 4 ahead
146         ;;
147         sub ret0=src,orig       // distance from origin
148         sub tmp=7,val1          // 7=8-1 because this strlen returns strlen+1
149         mov pr=saved_pr,0xffffffffffff0000
150         ;;
151         sub ret0=ret0,tmp       // length=now - back -1
152         mov ar.pfs=saved_pfs    // because of ar.ec, restore no matter what
153         br.ret.sptk.many rp     // end of normal execution
154
155         //
156         // Outlined recovery code when speculation failed
157         //
158         // This time we don't use speculation and rely on the normal exception
159         // mechanism. that's why the loop is not as good as the previous one
160         // because read ahead is not possible
161         //
162         // XXX Fixme
163         //      - today we restart from the beginning of the string instead
164         //        of trying to continue where we left off.
165         //
166 .recover:
167         EX(.Lexit1, ld8 val=[base],8)   // load the initial bytes
168         ;;
169         or val=val,mask                 // remask first bytes
170         cmp.eq p0,p6=r0,r0              // nullify first ld8 in loop
171         ;;
172         //
173         // ar.ec is still zero here
174         //
175 2:
176         EX(.Lexit1, (p6) ld8 val=[base],8)
177         ;;
178         czx1.r val1=val         // search 0 byte from right
179         ;;
180         cmp.eq p6,p0=8,val1     // val1==8 ?
181 (p6)    br.wtop.dptk.few 2b     // loop until p6 == 0
182         ;;
183         sub ret0=base,orig      // distance from base
184         sub tmp=7,val1          // 7=8-1 because this strlen returns strlen+1
185         mov pr=saved_pr,0xffffffffffff0000
186         ;;
187         sub ret0=ret0,tmp       // length=now - back -1
188         mov ar.pfs=saved_pfs    // because of ar.ec, restore no matter what
189         br.ret.sptk.many rp     // end of successful recovery code
190
191         //
192         // We failed even on the normal load (called from exception handler)
193         //
194 .Lexit1:
195         mov ret0=0
196         mov pr=saved_pr,0xffffffffffff0000
197         mov ar.pfs=saved_pfs    // because of ar.ec, restore no matter what
198         br.ret.sptk.many rp
199 END(__strlen_user)
200 EXPORT_SYMBOL(__strlen_user)