1 |
1275 |
phoenix |
/*
|
2 |
|
|
* This routine clears to zero a linear memory buffer in user space.
|
3 |
|
|
*
|
4 |
|
|
* Inputs:
|
5 |
|
|
* in0: address of buffer
|
6 |
|
|
* in1: length of buffer in bytes
|
7 |
|
|
* Outputs:
|
8 |
|
|
* r8: number of bytes that didn't get cleared due to a fault
|
9 |
|
|
*
|
10 |
|
|
* Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
|
11 |
|
|
* Stephane Eranian
|
12 |
|
|
*/
|
13 |
|
|
|
14 |
|
|
#include
|
15 |
|
|
|
16 |
|
|
//
|
17 |
|
|
// arguments
|
18 |
|
|
//
|
19 |
|
|
#define buf r32
|
20 |
|
|
#define len r33
|
21 |
|
|
|
22 |
|
|
//
|
23 |
|
|
// local registers
|
24 |
|
|
//
|
25 |
|
|
#define cnt r16
|
26 |
|
|
#define buf2 r17
|
27 |
|
|
#define saved_lc r18
|
28 |
|
|
#define saved_pfs r19
|
29 |
|
|
#define tmp r20
|
30 |
|
|
#define len2 r21
|
31 |
|
|
#define len3 r22
|
32 |
|
|
|
33 |
|
|
//
|
34 |
|
|
// Theory of operations:
|
35 |
|
|
// - we check whether or not the buffer is small, i.e., less than 17
|
36 |
|
|
// in which case we do the byte by byte loop.
|
37 |
|
|
//
|
38 |
|
|
// - Otherwise we go progressively from 1 byte store to 8byte store in
|
39 |
|
|
// the head part, the body is a 16byte store loop and we finish we the
|
40 |
|
|
// tail for the last 15 bytes.
|
41 |
|
|
// The good point about this breakdown is that the long buffer handling
|
42 |
|
|
// contains only 2 branches.
|
43 |
|
|
//
|
44 |
|
|
// The reason for not using shifting & masking for both the head and the
|
45 |
|
|
// tail is to stay semantically correct. This routine is not supposed
|
46 |
|
|
// to write bytes outside of the buffer. While most of the time this would
|
47 |
|
|
// be ok, we can't tolerate a mistake. A classical example is the case
|
48 |
|
|
// of multithreaded code were to the extra bytes touched is actually owned
|
49 |
|
|
// by another thread which runs concurrently to ours. Another, less likely,
|
50 |
|
|
// example is with device drivers where reading an I/O mapped location may
|
51 |
|
|
// have side effects (same thing for writing).
|
52 |
|
|
//
|
53 |
|
|
|
54 |
|
|
GLOBAL_ENTRY(__do_clear_user)
|
55 |
|
|
.prologue
|
56 |
|
|
.save ar.pfs, saved_pfs
|
57 |
|
|
alloc saved_pfs=ar.pfs,2,0,0,0
|
58 |
|
|
cmp.eq p6,p0=r0,len // check for zero length
|
59 |
|
|
.save ar.lc, saved_lc
|
60 |
|
|
mov saved_lc=ar.lc // preserve ar.lc (slow)
|
61 |
|
|
.body
|
62 |
|
|
;; // avoid WAW on CFM
|
63 |
|
|
adds tmp=-1,len // br.ctop is repeat/until
|
64 |
|
|
mov ret0=len // return value is length at this point
|
65 |
|
|
(p6) br.ret.spnt.many rp
|
66 |
|
|
;;
|
67 |
|
|
cmp.lt p6,p0=16,len // if len > 16 then long memset
|
68 |
|
|
mov ar.lc=tmp // initialize lc for small count
|
69 |
|
|
(p6) br.cond.dptk .long_do_clear
|
70 |
|
|
;; // WAR on ar.lc
|
71 |
|
|
//
|
72 |
|
|
// worst case 16 iterations, avg 8 iterations
|
73 |
|
|
//
|
74 |
|
|
// We could have played with the predicates to use the extra
|
75 |
|
|
// M slot for 2 stores/iteration but the cost the initialization
|
76 |
|
|
// the various counters compared to how long the loop is supposed
|
77 |
|
|
// to last on average does not make this solution viable.
|
78 |
|
|
//
|
79 |
|
|
1:
|
80 |
|
|
EX( .Lexit1, st1 [buf]=r0,1 )
|
81 |
|
|
adds len=-1,len // countdown length using len
|
82 |
|
|
br.cloop.dptk 1b
|
83 |
|
|
;; // avoid RAW on ar.lc
|
84 |
|
|
//
|
85 |
|
|
// .Lexit4: comes from byte by byte loop
|
86 |
|
|
// len contains bytes left
|
87 |
|
|
.Lexit1:
|
88 |
|
|
mov ret0=len // faster than using ar.lc
|
89 |
|
|
mov ar.lc=saved_lc
|
90 |
|
|
br.ret.sptk.many rp // end of short clear_user
|
91 |
|
|
|
92 |
|
|
|
93 |
|
|
//
|
94 |
|
|
// At this point we know we have more than 16 bytes to copy
|
95 |
|
|
// so we focus on alignment (no branches required)
|
96 |
|
|
//
|
97 |
|
|
// The use of len/len2 for countdown of the number of bytes left
|
98 |
|
|
// instead of ret0 is due to the fact that the exception code
|
99 |
|
|
// changes the values of r8.
|
100 |
|
|
//
|
101 |
|
|
.long_do_clear:
|
102 |
|
|
tbit.nz p6,p0=buf,0 // odd alignment (for long_do_clear)
|
103 |
|
|
;;
|
104 |
|
|
EX( .Lexit3, (p6) st1 [buf]=r0,1 ) // 1-byte aligned
|
105 |
|
|
(p6) adds len=-1,len;; // sync because buf is modified
|
106 |
|
|
tbit.nz p6,p0=buf,1
|
107 |
|
|
;;
|
108 |
|
|
EX( .Lexit3, (p6) st2 [buf]=r0,2 ) // 2-byte aligned
|
109 |
|
|
(p6) adds len=-2,len;;
|
110 |
|
|
tbit.nz p6,p0=buf,2
|
111 |
|
|
;;
|
112 |
|
|
EX( .Lexit3, (p6) st4 [buf]=r0,4 ) // 4-byte aligned
|
113 |
|
|
(p6) adds len=-4,len;;
|
114 |
|
|
tbit.nz p6,p0=buf,3
|
115 |
|
|
;;
|
116 |
|
|
EX( .Lexit3, (p6) st8 [buf]=r0,8 ) // 8-byte aligned
|
117 |
|
|
(p6) adds len=-8,len;;
|
118 |
|
|
shr.u cnt=len,4 // number of 128-bit (2x64bit) words
|
119 |
|
|
;;
|
120 |
|
|
cmp.eq p6,p0=r0,cnt
|
121 |
|
|
adds tmp=-1,cnt
|
122 |
|
|
(p6) br.cond.dpnt .dotail // we have less than 16 bytes left
|
123 |
|
|
;;
|
124 |
|
|
adds buf2=8,buf // setup second base pointer
|
125 |
|
|
mov ar.lc=tmp
|
126 |
|
|
;;
|
127 |
|
|
|
128 |
|
|
//
|
129 |
|
|
// 16bytes/iteration core loop
|
130 |
|
|
//
|
131 |
|
|
// The second store can never generate a fault because
|
132 |
|
|
// we come into the loop only when we are 16-byte aligned.
|
133 |
|
|
// This means that if we cross a page then it will always be
|
134 |
|
|
// in the first store and never in the second.
|
135 |
|
|
//
|
136 |
|
|
//
|
137 |
|
|
// We need to keep track of the remaining length. A possible (optimistic)
|
138 |
|
|
// way would be to use ar.lc and derive how many byte were left by
|
139 |
|
|
// doing : left= 16*ar.lc + 16. this would avoid the addition at
|
140 |
|
|
// every iteration.
|
141 |
|
|
// However we need to keep the synchronization point. A template
|
142 |
|
|
// M;;MB does not exist and thus we can keep the addition at no
|
143 |
|
|
// extra cycle cost (use a nop slot anyway). It also simplifies the
|
144 |
|
|
// (unlikely) error recovery code
|
145 |
|
|
//
|
146 |
|
|
|
147 |
|
|
2: EX(.Lexit3, st8 [buf]=r0,16 )
|
148 |
|
|
;; // needed to get len correct when error
|
149 |
|
|
st8 [buf2]=r0,16
|
150 |
|
|
adds len=-16,len
|
151 |
|
|
br.cloop.dptk 2b
|
152 |
|
|
;;
|
153 |
|
|
mov ar.lc=saved_lc
|
154 |
|
|
//
|
155 |
|
|
// tail correction based on len only
|
156 |
|
|
//
|
157 |
|
|
// We alternate the use of len3,len2 to allow parallelism and correct
|
158 |
|
|
// error handling. We also reuse p6/p7 to return correct value.
|
159 |
|
|
// The addition of len2/len3 does not cost anything more compared to
|
160 |
|
|
// the regular memset as we had empty slots.
|
161 |
|
|
//
|
162 |
|
|
.dotail:
|
163 |
|
|
mov len2=len // for parallelization of error handling
|
164 |
|
|
mov len3=len
|
165 |
|
|
tbit.nz p6,p0=len,3
|
166 |
|
|
;;
|
167 |
|
|
EX( .Lexit2, (p6) st8 [buf]=r0,8 ) // at least 8 bytes
|
168 |
|
|
(p6) adds len3=-8,len2
|
169 |
|
|
tbit.nz p7,p6=len,2
|
170 |
|
|
;;
|
171 |
|
|
EX( .Lexit2, (p7) st4 [buf]=r0,4 ) // at least 4 bytes
|
172 |
|
|
(p7) adds len2=-4,len3
|
173 |
|
|
tbit.nz p6,p7=len,1
|
174 |
|
|
;;
|
175 |
|
|
EX( .Lexit2, (p6) st2 [buf]=r0,2 ) // at least 2 bytes
|
176 |
|
|
(p6) adds len3=-2,len2
|
177 |
|
|
tbit.nz p7,p6=len,0
|
178 |
|
|
;;
|
179 |
|
|
EX( .Lexit2, (p7) st1 [buf]=r0 ) // only 1 byte left
|
180 |
|
|
mov ret0=r0 // success
|
181 |
|
|
br.ret.sptk.many rp // end of most likely path
|
182 |
|
|
|
183 |
|
|
//
|
184 |
|
|
// Outlined error handling code
|
185 |
|
|
//
|
186 |
|
|
|
187 |
|
|
//
|
188 |
|
|
// .Lexit3: comes from core loop, need restore pr/lc
|
189 |
|
|
// len contains bytes left
|
190 |
|
|
//
|
191 |
|
|
//
|
192 |
|
|
// .Lexit2:
|
193 |
|
|
// if p6 -> coming from st8 or st2 : len2 contains what's left
|
194 |
|
|
// if p7 -> coming from st4 or st1 : len3 contains what's left
|
195 |
|
|
// We must restore lc/pr even though might not have been used.
|
196 |
|
|
.Lexit2:
|
197 |
|
|
.pred.rel "mutex", p6, p7
|
198 |
|
|
(p6) mov len=len2
|
199 |
|
|
(p7) mov len=len3
|
200 |
|
|
;;
|
201 |
|
|
//
|
202 |
|
|
// .Lexit4: comes from head, need not restore pr/lc
|
203 |
|
|
// len contains bytes left
|
204 |
|
|
//
|
205 |
|
|
.Lexit3:
|
206 |
|
|
mov ret0=len
|
207 |
|
|
mov ar.lc=saved_lc
|
208 |
|
|
br.ret.sptk.many rp
|
209 |
|
|
END(__do_clear_user)
|