]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/string/ia64/bzero.S
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / string / ia64 / bzero.S
1 /* Optimized version of the standard bzero() function.
2    This file is part of the GNU C Library.
3    Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
4    Contributed by Dan Pop for Itanium <Dan.Pop@cern.ch>.
5    Rewritten for McKinley by Sverre Jarp, HP Labs/CERN <Sverre.Jarp@cern.ch>
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 /* Return: dest
22
23    Inputs:
24         in0:    dest
25         in1:    count
26
27    The algorithm is fairly straightforward: set byte by byte until we
28    we get to a 16B-aligned address, then loop on 128 B chunks using an
29    early store as prefetching, then loop on 32B chucks, then clear remaining
30    words, finally clear remaining bytes.
31    Since a stf.spill f0 can store 16B in one go, we use this instruction
32    to get peak speed.  */
33
34 #include <sysdep.h>
35
36 #ifdef __UCLIBC_SUSV3_LEGACY__
37
38 #undef ret
39
40 #define dest            in0
41 #define cnt             in1
42
43 #define tmp             r31
44 #define save_lc         r30
45 #define ptr0            r29
46 #define ptr1            r28
47 #define ptr2            r27
48 #define ptr3            r26
49 #define ptr9            r24
50 #define loopcnt         r23
51 #define linecnt         r22
52 #define bytecnt         r21
53
54 /* This routine uses only scratch predicate registers (p6 - p15) */
55 #define p_scr           p6      /* default register for same-cycle branches */
56 #define p_unalgn        p9
57 #define p_y             p11
58 #define p_n             p12
59 #define p_yy            p13
60 #define p_nn            p14
61
62 #define movi0           mov
63
64 #define MIN1            15
65 #define MIN1P1HALF      8
66 #define LINE_SIZE       128
67 #define LSIZE_SH        7                       /* shift amount */
68 #define PREF_AHEAD      8
69
70 #define USE_FLP
71 #if defined(USE_INT)
72 #define store           st8
73 #define myval           r0
74 #elif defined(USE_FLP)
75 #define store           stf8
76 #define myval           f0
77 #endif
78
79 .align  64
80 ENTRY(bzero)
81 { .mmi
82         .prologue
83         alloc   tmp = ar.pfs, 2, 0, 0, 0
84         lfetch.nt1 [dest]
85         .save   ar.lc, save_lc
86         movi0   save_lc = ar.lc
87 } { .mmi
88         .body
89         mov     ret0 = dest             /* return value */
90         nop.m   0
91         cmp.eq  p_scr, p0 = cnt, r0
92 ;; }
93 { .mmi
94         and     ptr2 = -(MIN1+1), dest  /* aligned address */
95         and     tmp = MIN1, dest        /* prepare to check for alignment */
96         tbit.nz p_y, p_n = dest, 0      /* Do we have an odd address? (M_B_U) */
97 } { .mib
98         mov     ptr1 = dest
99         nop.i   0
100 (p_scr) br.ret.dpnt.many rp             /* return immediately if count = 0 */
101 ;; }
102 { .mib
103         cmp.ne  p_unalgn, p0 = tmp, r0
104 } { .mib                                        /* NB: # of bytes to move is 1 */
105         sub     bytecnt = (MIN1+1), tmp         /*     higher than loopcnt */
106         cmp.gt  p_scr, p0 = 16, cnt             /* is it a minimalistic task? */
107 (p_scr) br.cond.dptk.many .move_bytes_unaligned /* go move just a few (M_B_U) */
108 ;; }
109 { .mmi
110 (p_unalgn) add  ptr1 = (MIN1+1), ptr2           /* after alignment */
111 (p_unalgn) add  ptr2 = MIN1P1HALF, ptr2         /* after alignment */
112 (p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 3    /* should we do a st8 ? */
113 ;; }
114 { .mib
115 (p_y)   add     cnt = -8, cnt
116 (p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 2  /* should we do a st4 ? */
117 } { .mib
118 (p_y)   st8     [ptr2] = r0,-4
119 (p_n)   add     ptr2 = 4, ptr2
120 ;; }
121 { .mib
122 (p_yy)  add     cnt = -4, cnt
123 (p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 1    /* should we do a st2 ? */
124 } { .mib
125 (p_yy)  st4     [ptr2] = r0,-2
126 (p_nn)  add     ptr2 = 2, ptr2
127 ;; }
128 { .mmi
129         mov     tmp = LINE_SIZE+1               /* for compare */
130 (p_y)   add     cnt = -2, cnt
131 (p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 0  /* should we do a st1 ? */
132 } { .mmi
133         nop.m   0
134 (p_y)   st2     [ptr2] = r0,-1
135 (p_n)   add     ptr2 = 1, ptr2
136 ;; }
137
138 { .mmi
139 (p_yy)  st1     [ptr2] = r0
140         cmp.gt  p_scr, p0 = tmp, cnt            /* is it a minimalistic task? */
141 } { .mbb
142 (p_yy)  add     cnt = -1, cnt
143 (p_scr) br.cond.dpnt.many .fraction_of_line     /* go move just a few */
144 ;; }
145 { .mib
146         nop.m   0
147         shr.u   linecnt = cnt, LSIZE_SH
148         nop.b   0
149 ;; }
150
151         .align 32
152 .l1b:   /* ------------------  L1B: store ahead into cache lines; fill later */
153 { .mmi
154         and     tmp = -(LINE_SIZE), cnt         /* compute end of range */
155         mov     ptr9 = ptr1                     /* used for prefetching */
156         and     cnt = (LINE_SIZE-1), cnt        /* remainder */
157 } { .mmi
158         mov     loopcnt = PREF_AHEAD-1          /* default prefetch loop */
159         cmp.gt  p_scr, p0 = PREF_AHEAD, linecnt /* check against actual value */
160 ;; }
161 { .mmi
162 (p_scr) add     loopcnt = -1, linecnt
163         add     ptr2 = 16, ptr1 /* start of stores (beyond prefetch stores) */
164         add     ptr1 = tmp, ptr1        /* first address beyond total range */
165 ;; }
166 { .mmi
167         add     tmp = -1, linecnt       /* next loop count */
168         movi0   ar.lc = loopcnt
169 ;; }
170 .pref_l1b:
171 { .mib
172         stf.spill [ptr9] = f0, 128      /* Do stores one cache line apart */
173         nop.i   0
174         br.cloop.dptk.few .pref_l1b
175 ;; }
176 { .mmi
177         add     ptr0 = 16, ptr2         /* Two stores in parallel */
178         movi0   ar.lc = tmp
179 ;; }
180 .l1bx:
181  { .mmi
182         stf.spill [ptr2] = f0, 32
183         stf.spill [ptr0] = f0, 32
184  ;; }
185  { .mmi
186         stf.spill [ptr2] = f0, 32
187         stf.spill [ptr0] = f0, 32
188  ;; }
189  { .mmi
190         stf.spill [ptr2] = f0, 32
191         stf.spill [ptr0] = f0, 64
192         cmp.lt  p_scr, p0 = ptr9, ptr1  /* do we need more prefetching? */
193  ;; }
194 { .mmb
195         stf.spill [ptr2] = f0, 32
196 (p_scr) stf.spill [ptr9] = f0, 128
197         br.cloop.dptk.few .l1bx
198 ;; }
199 { .mib
200         cmp.gt  p_scr, p0 = 8, cnt      /* just a few bytes left ? */
201 (p_scr) br.cond.dpnt.many  .move_bytes_from_alignment
202 ;; }
203
204 .fraction_of_line:
205 { .mib
206         add     ptr2 = 16, ptr1
207         shr.u   loopcnt = cnt, 5        /* loopcnt = cnt / 32 */
208 ;; }
209 { .mib
210         cmp.eq  p_scr, p0 = loopcnt, r0
211         add     loopcnt = -1, loopcnt
212 (p_scr) br.cond.dpnt.many .store_words
213 ;; }
214 { .mib
215         and     cnt = 0x1f, cnt         /* compute the remaining cnt */
216         movi0   ar.lc = loopcnt
217 ;; }
218         .align 32
219 .l2:    /* -----------------------------  L2A:  store 32B in 2 cycles */
220 { .mmb
221         store   [ptr1] = myval, 8
222         store   [ptr2] = myval, 8
223 ;; } { .mmb
224         store   [ptr1] = myval, 24
225         store   [ptr2] = myval, 24
226         br.cloop.dptk.many .l2
227 ;; }
228 .store_words:
229 { .mib
230         cmp.gt  p_scr, p0 = 8, cnt      /* just a few bytes left ? */
231 (p_scr) br.cond.dpnt.many .move_bytes_from_alignment    /* Branch */
232 ;; }
233
234 { .mmi
235         store   [ptr1] = myval, 8       /* store */
236         cmp.le  p_y, p_n = 16, cnt      /* */
237         add     cnt = -8, cnt           /* subtract */
238 ;; }
239 { .mmi
240 (p_y)   store   [ptr1] = myval, 8       /* store */
241 (p_y)   cmp.le.unc p_yy, p_nn = 16, cnt
242 (p_y)   add     cnt = -8, cnt           /* subtract */
243 ;; }
244 { .mmi                                  /* store */
245 (p_yy)  store   [ptr1] = myval, 8
246 (p_yy)  add     cnt = -8, cnt           /* subtract */
247 ;; }
248
249 .move_bytes_from_alignment:
250 { .mib
251         cmp.eq  p_scr, p0 = cnt, r0
252         tbit.nz.unc p_y, p0 = cnt, 2    /* should we terminate with a st4 ? */
253 (p_scr) br.cond.dpnt.few .restore_and_exit
254 ;; }
255 { .mib
256 (p_y)   st4     [ptr1] = r0,4
257         tbit.nz.unc p_yy, p0 = cnt, 1   /* should we terminate with a st2 ? */
258 ;; }
259 { .mib
260 (p_yy)  st2     [ptr1] = r0,2
261         tbit.nz.unc p_y, p0 = cnt, 0    /* should we terminate with a st1 ? */
262 ;; }
263
264 { .mib
265 (p_y)   st1     [ptr1] = r0
266 ;; }
267 .restore_and_exit:
268 { .mib
269         nop.m   0
270         movi0   ar.lc = save_lc
271         br.ret.sptk.many rp
272 ;; }
273
274 .move_bytes_unaligned:
275 { .mmi
276        .pred.rel "mutex",p_y, p_n
277        .pred.rel "mutex",p_yy, p_nn
278 (p_n)   cmp.le  p_yy, p_nn = 4, cnt
279 (p_y)   cmp.le  p_yy, p_nn = 5, cnt
280 (p_n)   add     ptr2 = 2, ptr1
281 } { .mmi
282 (p_y)   add     ptr2 = 3, ptr1
283 (p_y)   st1     [ptr1] = r0, 1          /* fill 1 (odd-aligned) byte */
284 (p_y)   add     cnt = -1, cnt           /* [15, 14 (or less) left] */
285 ;; }
286 { .mmi
287 (p_yy)  cmp.le.unc p_y, p0 = 8, cnt
288         add     ptr3 = ptr1, cnt        /* prepare last store */
289         movi0   ar.lc = save_lc
290 } { .mmi
291 (p_yy)  st2     [ptr1] = r0, 4          /* fill 2 (aligned) bytes */
292 (p_yy)  st2     [ptr2] = r0, 4          /* fill 2 (aligned) bytes */
293 (p_yy)  add     cnt = -4, cnt           /* [11, 10 (o less) left] */
294 ;; }
295 { .mmi
296 (p_y)   cmp.le.unc p_yy, p0 = 8, cnt
297         add     ptr3 = -1, ptr3         /* last store */
298         tbit.nz p_scr, p0 = cnt, 1      /* will there be a st2 at the end ? */
299 } { .mmi
300 (p_y)   st2     [ptr1] = r0, 4          /* fill 2 (aligned) bytes */
301 (p_y)   st2     [ptr2] = r0, 4          /* fill 2 (aligned) bytes */
302 (p_y)   add     cnt = -4, cnt           /* [7, 6 (or less) left] */
303 ;; }
304 { .mmi
305 (p_yy)  st2     [ptr1] = r0, 4          /* fill 2 (aligned) bytes */
306 (p_yy)  st2     [ptr2] = r0, 4          /* fill 2 (aligned) bytes */
307                                         /* [3, 2 (or less) left] */
308         tbit.nz p_y, p0 = cnt, 0        /* will there be a st1 at the end ? */
309 } { .mmi
310 (p_yy)  add     cnt = -4, cnt
311 ;; }
312 { .mmb
313 (p_scr) st2     [ptr1] = r0             /* fill 2 (aligned) bytes */
314 (p_y)   st1     [ptr3] = r0             /* fill last byte (using ptr3) */
315         br.ret.sptk.many rp
316 ;; }
317 END(bzero)
318
319 #endif