2015-01-05 Steve Ellcey <sellcey@imgtec.com>
[platform/upstream/glibc.git] / sysdeps / mips / memset.S
1 /* Copyright (C) 2013-2015 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library.  If not, see
16    <http://www.gnu.org/licenses/>.  */
17
18 #ifdef ANDROID_CHANGES
19 # include "machine/asm.h"
20 # include "machine/regdef.h"
21 # define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
22 #elif _LIBC
23 # include <sysdep.h>
24 # include <regdef.h>
25 # include <sys/asm.h>
26 # define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
27 #elif _COMPILING_NEWLIB
28 # include "machine/asm.h"
29 # include "machine/regdef.h"
30 # define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
31 #else
32 # include <regdef.h>
33 # include <sys/asm.h>
34 #endif
35
36 /* Check to see if the MIPS architecture we are compiling for supports
37    prefetching.  */
38
39 #if (__mips == 4) || (__mips == 5) || (__mips == 32) || (__mips == 64)
40 # ifndef DISABLE_PREFETCH
41 #  define USE_PREFETCH
42 # endif
43 #endif
44
45 #if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32))
46 # ifndef DISABLE_DOUBLE
47 #  define USE_DOUBLE
48 # endif
49 #endif
50
51 #ifndef USE_DOUBLE
52 # ifndef DISABLE_DOUBLE_ALIGN
53 #  define DOUBLE_ALIGN
54 # endif
55 #endif
56
57 #if __mips_isa_rev > 5
58 # if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
59 #  undef PREFETCH_STORE_HINT
60 #  define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED
61 # endif
62 # define R6_CODE
63 #endif
64
65 /* Some asm.h files do not have the L macro definition.  */
66 #ifndef L
67 # if _MIPS_SIM == _ABIO32
68 #  define L(label) $L ## label
69 # else
70 #  define L(label) .L ## label
71 # endif
72 #endif
73
74 /* Some asm.h files do not have the PTR_ADDIU macro definition.  */
75 #ifndef PTR_ADDIU
76 # ifdef USE_DOUBLE
77 #  define PTR_ADDIU     daddiu
78 # else
79 #  define PTR_ADDIU     addiu
80 # endif
81 #endif
82
83 /* New R6 instructions that may not be in asm.h.  */
84 #ifndef PTR_LSA
85 # if _MIPS_SIM == _ABI64
86 #  define PTR_LSA        dlsa
87 # else
88 #  define PTR_LSA        lsa
89 # endif
90 #endif
91
92 /* Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
93    or PREFETCH_STORE_STREAMED offers a large performance advantage
94    but PREPAREFORSTORE has some special restrictions to consider.
95
96    Prefetch with the 'prepare for store' hint does not copy a memory
97    location into the cache, it just allocates a cache line and zeros
98    it out.  This means that if you do not write to the entire cache
99    line before writing it out to memory some data will get zero'ed out
100    when the cache line is written back to memory and data will be lost.
101
102    There are ifdef'ed sections of this memcpy to make sure that it does not
103    do prefetches on cache lines that are not going to be completely written.
104    This code is only needed and only used when PREFETCH_STORE_HINT is set to
105    PREFETCH_HINT_PREPAREFORSTORE.  This code assumes that cache lines are
106    less than MAX_PREFETCH_SIZE bytes and if the cache line is larger it will
107    not work correctly.  */
108
109 #ifdef USE_PREFETCH
110 # define PREFETCH_HINT_STORE            1
111 # define PREFETCH_HINT_STORE_STREAMED   5
112 # define PREFETCH_HINT_STORE_RETAINED   7
113 # define PREFETCH_HINT_PREPAREFORSTORE  30
114
115 /* If we have not picked out what hints to use at this point use the
116    standard load and store prefetch hints.  */
117 # ifndef PREFETCH_STORE_HINT
118 #  define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
119 # endif
120
121 /* We double everything when USE_DOUBLE is true so we do 2 prefetches to
122    get 64 bytes in that case.  The assumption is that each individual
123    prefetch brings in 32 bytes.  */
124 # ifdef USE_DOUBLE
125 #  define PREFETCH_CHUNK 64
126 #  define PREFETCH_FOR_STORE(chunk, reg) \
127     pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
128     pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
129 # else
130 #  define PREFETCH_CHUNK 32
131 #  define PREFETCH_FOR_STORE(chunk, reg) \
132     pref PREFETCH_STORE_HINT, (chunk)*32(reg)
133 # endif
134
135 /* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
136    than PREFETCH_CHUNK, the assumed size of each prefetch.  If the real size
137    of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
138    hint is used, the code will not work correctly.  If PREPAREFORSTORE is not
139    used than MAX_PREFETCH_SIZE does not matter.  */
140 # define MAX_PREFETCH_SIZE 128
141 /* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
142    than 5 on a STORE prefetch and that a single prefetch can never be larger
143    than MAX_PREFETCH_SIZE.  We add the extra 32 when USE_DOUBLE is set because
144    we actually do two prefetches in that case, one 32 bytes after the other.  */
145 # ifdef USE_DOUBLE
146 #  define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
147 # else
148 #  define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
149 # endif
150
151 # if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
152     && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
153 /* We cannot handle this because the initial prefetches may fetch bytes that
154    are before the buffer being copied.  We start copies with an offset
155    of 4 so avoid this situation when using PREPAREFORSTORE.  */
156 #  error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
157 # endif
158 #else /* USE_PREFETCH not defined */
159 # define PREFETCH_FOR_STORE(offset, reg)
160 #endif
161
162 /* Allow the routine to be named something else if desired.  */
163 #ifndef MEMSET_NAME
164 # define MEMSET_NAME memset
165 #endif
166
167 /* We load/store 64 bits at a time when USE_DOUBLE is true.
168    The C_ prefix stands for CHUNK and is used to avoid macro name
169    conflicts with system header files.  */
170
171 #ifdef USE_DOUBLE
172 # define C_ST   sd
173 # if __MIPSEB
174 #  define C_STHI        sdl     /* high part is left in big-endian      */
175 # else
176 #  define C_STHI        sdr     /* high part is right in little-endian  */
177 # endif
178 #else
179 # define C_ST   sw
180 # if __MIPSEB
181 #  define C_STHI        swl     /* high part is left in big-endian      */
182 # else
183 #  define C_STHI        swr     /* high part is right in little-endian  */
184 # endif
185 #endif
186
187 /* Bookkeeping values for 32 vs. 64 bit mode.  */
188 #ifdef USE_DOUBLE
189 # define NSIZE 8
190 # define NSIZEMASK 0x3f
191 # define NSIZEDMASK 0x7f
192 #else
193 # define NSIZE 4
194 # define NSIZEMASK 0x1f
195 # define NSIZEDMASK 0x3f
196 #endif
197 #define UNIT(unit) ((unit)*NSIZE)
198 #define UNITM1(unit) (((unit)*NSIZE)-1)
199
200 #ifdef ANDROID_CHANGES
201 LEAF(MEMSET_NAME,0)
202 #else
203 LEAF(MEMSET_NAME)
204 #endif
205
206         .set    nomips16
207         .set    noreorder
208 /* If the size is less than 2*NSIZE (8 or 16), go to L(lastb).  Regardless of
209    size, copy dst pointer to v0 for the return value.  */
210         slti    t2,a2,(2 * NSIZE)
211         bne     t2,zero,L(lastb)
212         move    v0,a0
213
214 /* If memset value is not zero, we copy it to all the bytes in a 32 or 64
215    bit word.  */
216         beq     a1,zero,L(set0)         /* If memset value is zero no smear  */
217         PTR_SUBU a3,zero,a0
218         nop
219
220         /* smear byte into 32 or 64 bit word */
221 #if ((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2)
222 # ifdef USE_DOUBLE
223         dins    a1, a1, 8, 8        /* Replicate fill byte into half-word.  */
224         dins    a1, a1, 16, 16      /* Replicate fill byte into word.       */
225         dins    a1, a1, 32, 32      /* Replicate fill byte into dbl word.   */
226 # else
227         ins     a1, a1, 8, 8        /* Replicate fill byte into half-word.  */
228         ins     a1, a1, 16, 16      /* Replicate fill byte into word.       */
229 # endif
230 #else
231 # ifdef USE_DOUBLE
232         and     a1,0xff
233         dsll    t2,a1,8
234         or      a1,t2
235         dsll    t2,a1,16
236         or      a1,t2
237         dsll    t2,a1,32
238         or      a1,t2
239 # else
240         and     a1,0xff
241         sll     t2,a1,8
242         or      a1,t2
243         sll     t2,a1,16
244         or      a1,t2
245 # endif
246 #endif
247
248 /* If the destination address is not aligned do a partial store to get it
249    aligned.  If it is already aligned just jump to L(aligned).  */
250 L(set0):
251 #ifndef R6_CODE
252         andi    t2,a3,(NSIZE-1)         /* word-unaligned address?          */
253         beq     t2,zero,L(aligned)      /* t2 is the unalignment count      */
254         PTR_SUBU a2,a2,t2
255         C_STHI  a1,0(a0)
256         PTR_ADDU a0,a0,t2
257 #else /* R6_CODE */
258         andi    t2,a0,(NSIZE-1)
259         lapc    t9,L(atable)
260         PTR_LSA t9,t2,t9,2
261         jrc     t9
262 L(atable):
263         bc      L(aligned)
264 # ifdef USE_DOUBLE
265         bc      L(lb7)
266         bc      L(lb6)
267         bc      L(lb5)
268         bc      L(lb4)
269 # endif
270         bc      L(lb3)
271         bc      L(lb2)
272         bc      L(lb1)
273 L(lb7):
274         sb      a1,6(a0)
275 L(lb6):
276         sb      a1,5(a0)
277 L(lb5):
278         sb      a1,4(a0)
279 L(lb4):
280         sb      a1,3(a0)
281 L(lb3):
282         sb      a1,2(a0)
283 L(lb2):
284         sb      a1,1(a0)
285 L(lb1):
286         sb      a1,0(a0)
287
288         li      t9,NSIZE
289         subu    t2,t9,t2
290         PTR_SUBU a2,a2,t2
291         PTR_ADDU a0,a0,t2
292 #endif /* R6_CODE */
293
294 L(aligned):
295 /* If USE_DOUBLE is not set we may still want to align the data on a 16
296    byte boundry instead of an 8 byte boundry to maximize the opportunity
297    of proAptiv chips to do memory bonding (combining two sequential 4
298    byte stores into one 8 byte store).  We know there are at least 4 bytes
299    left to store or we would have jumped to L(lastb) earlier in the code.  */
300 #ifdef DOUBLE_ALIGN
301         andi    t2,a3,4
302         beq     t2,zero,L(double_aligned)
303         PTR_SUBU a2,a2,t2
304         sw      a1,0(a0)
305         PTR_ADDU a0,a0,t2
306 L(double_aligned):
307 #endif
308
309 /* Now the destination is aligned to (word or double word) aligned address
310    Set a2 to count how many bytes we have to copy after all the 64/128 byte
311    chunks are copied and a3 to the dest pointer after all the 64/128 byte
312    chunks have been copied.  We will loop, incrementing a0 until it equals
313    a3.  */
314         andi    t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
315         beq     a2,t8,L(chkw)    /* if a2==t8, no 64-byte/128-byte chunks */
316         PTR_SUBU a3,a2,t8        /* subtract from a2 the reminder */
317         PTR_ADDU a3,a0,a3        /* Now a3 is the final dst after loop */
318
319 /* When in the loop we may prefetch with the 'prepare to store' hint,
320    in this case the a0+x should not be past the "t0-32" address.  This
321    means: for x=128 the last "safe" a0 address is "t0-160".  Alternatively,
322    for x=64 the last "safe" a0 address is "t0-96" In the current version we
323    will use "prefetch hint,128(a0)", so "t0-160" is the limit.  */
324 #if defined(USE_PREFETCH) \
325     && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
326         PTR_ADDU t0,a0,a2               /* t0 is the "past the end" address */
327         PTR_SUBU t9,t0,PREFETCH_LIMIT   /* t9 is the "last safe pref" address */
328 #endif
329 #if defined(USE_PREFETCH) \
330     && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
331         PREFETCH_FOR_STORE (1, a0)
332         PREFETCH_FOR_STORE (2, a0)
333         PREFETCH_FOR_STORE (3, a0)
334 #endif
335
336 L(loop16w):
337 #if defined(USE_PREFETCH) \
338     && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
339         sltu    v1,t9,a0                /* If a0 > t9 don't use next prefetch */
340         bgtz    v1,L(skip_pref)
341         nop
342 #endif
343 #ifdef R6_CODE
344         PREFETCH_FOR_STORE (2, a0)
345 #else
346         PREFETCH_FOR_STORE (4, a0)
347         PREFETCH_FOR_STORE (5, a0)
348 #endif
349 L(skip_pref):
350         C_ST    a1,UNIT(0)(a0)
351         C_ST    a1,UNIT(1)(a0)
352         C_ST    a1,UNIT(2)(a0)
353         C_ST    a1,UNIT(3)(a0)
354         C_ST    a1,UNIT(4)(a0)
355         C_ST    a1,UNIT(5)(a0)
356         C_ST    a1,UNIT(6)(a0)
357         C_ST    a1,UNIT(7)(a0)
358         C_ST    a1,UNIT(8)(a0)
359         C_ST    a1,UNIT(9)(a0)
360         C_ST    a1,UNIT(10)(a0)
361         C_ST    a1,UNIT(11)(a0)
362         C_ST    a1,UNIT(12)(a0)
363         C_ST    a1,UNIT(13)(a0)
364         C_ST    a1,UNIT(14)(a0)
365         C_ST    a1,UNIT(15)(a0)
366         PTR_ADDIU a0,a0,UNIT(16)        /* adding 64/128 to dest */
367         bne     a0,a3,L(loop16w)
368         nop
369         move    a2,t8
370
371 /* Here we have dest word-aligned but less than 64-bytes or 128 bytes to go.
372    Check for a 32(64) byte chunk and copy if if there is one.  Otherwise
373    jump down to L(chk1w) to handle the tail end of the copy.  */
374 L(chkw):
375         andi    t8,a2,NSIZEMASK /* is there a 32-byte/64-byte chunk.  */
376                                 /* the t8 is the reminder count past 32-bytes */
377         beq     a2,t8,L(chk1w)/* when a2==t8, no 32-byte chunk */
378         nop
379         C_ST    a1,UNIT(0)(a0)
380         C_ST    a1,UNIT(1)(a0)
381         C_ST    a1,UNIT(2)(a0)
382         C_ST    a1,UNIT(3)(a0)
383         C_ST    a1,UNIT(4)(a0)
384         C_ST    a1,UNIT(5)(a0)
385         C_ST    a1,UNIT(6)(a0)
386         C_ST    a1,UNIT(7)(a0)
387         PTR_ADDIU a0,a0,UNIT(8)
388
389 /* Here we have less than 32(64) bytes to set.  Set up for a loop to
390    copy one word (or double word) at a time.  Set a2 to count how many
391    bytes we have to copy after all the word (or double word) chunks are
392    copied and a3 to the dest pointer after all the (d)word chunks have
393    been copied.  We will loop, incrementing a0 until a0 equals a3.  */
394 L(chk1w):
395         andi    a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
396         beq     a2,t8,L(lastb)
397         PTR_SUBU a3,t8,a2       /* a3 is count of bytes in one (d)word chunks */
398         PTR_ADDU a3,a0,a3       /* a3 is the dst address after loop */
399
400 /* copying in words (4-byte or 8 byte chunks) */
401 L(wordCopy_loop):
402         PTR_ADDIU a0,a0,UNIT(1)
403         bne     a0,a3,L(wordCopy_loop)
404         C_ST    a1,UNIT(-1)(a0)
405
406 /* Copy the last 8 (or 16) bytes */
407 L(lastb):
408         blez    a2,L(leave)
409         PTR_ADDU a3,a0,a2       /* a3 is the last dst address */
410 L(lastbloop):
411         PTR_ADDIU a0,a0,1
412         bne     a0,a3,L(lastbloop)
413         sb      a1,-1(a0)
414 L(leave):
415         j       ra
416         nop
417
418         .set    at
419         .set    reorder
420 END(MEMSET_NAME)
421 #ifndef ANDROID_CHANGES
422 # ifdef _LIBC
423 libc_hidden_builtin_def (MEMSET_NAME)
424 # endif
425 #endif