• R/O
  • HTTP
  • SSH
  • HTTPS

uclibc-ng: Commit


Commit MetaInfo

Revisionb778f37b8395a3258925e13a706dbc7d43c7c0ed (tree)
Time2015-12-27 04:24:49
AuthorSteve Ellcey <sellcey@imgt...>
CommiterWaldemar Brodkorb

Log Message

Replace MIPS specific memcpy.S/memset.S with version from glibc/newlib.

These MIPS specific versions of memcpy.S and memset.S are faster than
the current ones and match what is in newlib and glibc. They also have
support for the mips32r6 and mips64r6 architectures.

Signed-off-by: Steve Ellcey <sellcey@imgtec.com>

Change Summary

Incremental Difference

--- a/libc/string/mips/memcpy.S
+++ b/libc/string/mips/memcpy.S
@@ -1,6 +1,5 @@
1-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
1+/* Copyright (C) 2012-2015 Free Software Foundation, Inc.
22 This file is part of the GNU C Library.
3- Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
43
54 The GNU C Library is free software; you can redistribute it and/or
65 modify it under the terms of the GNU Lesser General Public
@@ -13,243 +12,861 @@
1312 Lesser General Public License for more details.
1413
1514 You should have received a copy of the GNU Lesser General Public
16- License along with the GNU C Library; if not, see
15+ License along with the GNU C Library. If not, see
1716 <http://www.gnu.org/licenses/>. */
1817
19-#include <features.h>
20-#include <sysdep.h>
21-#include <endian.h>
18+#ifdef ANDROID_CHANGES
19+# include "machine/asm.h"
20+# include "machine/regdef.h"
21+# define USE_MEMMOVE_FOR_OVERLAP
22+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED
23+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
24+#elif _LIBC
25+# include <sysdep.h>
26+# include <regdef.h>
27+# include <sys/asm.h>
28+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED
29+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
30+#elif defined _COMPILING_NEWLIB
31+# include "machine/asm.h"
32+# include "machine/regdef.h"
33+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED
34+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
35+#else
36+# include <regdef.h>
37+# include <sys/asm.h>
38+#endif
39+
40+#if (_MIPS_ISA == _MIPS_ISA_MIPS4) || (_MIPS_ISA == _MIPS_ISA_MIPS5) || \
41+ (_MIPS_ISA == _MIPS_ISA_MIPS32) || (_MIPS_ISA == _MIPS_ISA_MIPS64)
42+# ifndef DISABLE_PREFETCH
43+# define USE_PREFETCH
44+# endif
45+#endif
46+
47+#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32))
48+# ifndef DISABLE_DOUBLE
49+# define USE_DOUBLE
50+# endif
51+#endif
52+
53+/* Some asm.h files do not have the L macro definition. */
54+#ifndef L
55+# if _MIPS_SIM == _ABIO32
56+# define L(label) $L ## label
57+# else
58+# define L(label) .L ## label
59+# endif
60+#endif
61+
62+/* Some asm.h files do not have the PTR_ADDIU macro definition. */
63+#ifndef PTR_ADDIU
64+# ifdef USE_DOUBLE
65+# define PTR_ADDIU daddiu
66+# else
67+# define PTR_ADDIU addiu
68+# endif
69+#endif
70+
71+/* Some asm.h files do not have the PTR_SRA macro definition. */
72+#ifndef PTR_SRA
73+# ifdef USE_DOUBLE
74+# define PTR_SRA dsra
75+# else
76+# define PTR_SRA sra
77+# endif
78+#endif
79+
80+/* New R6 instructions that may not be in asm.h. */
81+#ifndef PTR_LSA
82+# if _MIPS_SIM == _ABI64
83+# define PTR_LSA dlsa
84+# else
85+# define PTR_LSA lsa
86+# endif
87+#endif
88+
89+/*
90+ * Using PREFETCH_HINT_LOAD_STREAMED instead of PREFETCH_LOAD on load
91+ * prefetches appears to offer a slight preformance advantage.
92+ *
93+ * Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
94+ * or PREFETCH_STORE_STREAMED offers a large performance advantage
95+ * but PREPAREFORSTORE has some special restrictions to consider.
96+ *
97+ * Prefetch with the 'prepare for store' hint does not copy a memory
98+ * location into the cache, it just allocates a cache line and zeros
99+ * it out. This means that if you do not write to the entire cache
100+ * line before writing it out to memory some data will get zero'ed out
101+ * when the cache line is written back to memory and data will be lost.
102+ *
103+ * Also if you are using this memcpy to copy overlapping buffers it may
104+ * not behave correctly when using the 'prepare for store' hint. If you
105+ * use the 'prepare for store' prefetch on a memory area that is in the
106+ * memcpy source (as well as the memcpy destination), then you will get
107+ * some data zero'ed out before you have a chance to read it and data will
108+ * be lost.
109+ *
110+ * If you are going to use this memcpy routine with the 'prepare for store'
111+ * prefetch you may want to set USE_MEMMOVE_FOR_OVERLAP in order to avoid
112+ * the problem of running memcpy on overlapping buffers.
113+ *
114+ * There are ifdef'ed sections of this memcpy to make sure that it does not
115+ * do prefetches on cache lines that are not going to be completely written.
116+ * This code is only needed and only used when PREFETCH_STORE_HINT is set to
117+ * PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are
118+ * 32 bytes and if the cache line is larger it will not work correctly.
119+ */
120+
121+#ifdef USE_PREFETCH
122+# define PREFETCH_HINT_LOAD 0
123+# define PREFETCH_HINT_STORE 1
124+# define PREFETCH_HINT_LOAD_STREAMED 4
125+# define PREFETCH_HINT_STORE_STREAMED 5
126+# define PREFETCH_HINT_LOAD_RETAINED 6
127+# define PREFETCH_HINT_STORE_RETAINED 7
128+# define PREFETCH_HINT_WRITEBACK_INVAL 25
129+# define PREFETCH_HINT_PREPAREFORSTORE 30
130+
131+/*
132+ * If we have not picked out what hints to use at this point use the
133+ * standard load and store prefetch hints.
134+ */
135+# ifndef PREFETCH_STORE_HINT
136+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
137+# endif
138+# ifndef PREFETCH_LOAD_HINT
139+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD
140+# endif
141+
142+/*
143+ * We double everything when USE_DOUBLE is true so we do 2 prefetches to
144+ * get 64 bytes in that case. The assumption is that each individual
145+ * prefetch brings in 32 bytes.
146+ */
147+
148+# ifdef USE_DOUBLE
149+# define PREFETCH_CHUNK 64
150+# define PREFETCH_FOR_LOAD(chunk, reg) \
151+ pref PREFETCH_LOAD_HINT, (chunk)*64(reg); \
152+ pref PREFETCH_LOAD_HINT, ((chunk)*64)+32(reg)
153+# define PREFETCH_FOR_STORE(chunk, reg) \
154+ pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
155+ pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
156+# else
157+# define PREFETCH_CHUNK 32
158+# define PREFETCH_FOR_LOAD(chunk, reg) \
159+ pref PREFETCH_LOAD_HINT, (chunk)*32(reg)
160+# define PREFETCH_FOR_STORE(chunk, reg) \
161+ pref PREFETCH_STORE_HINT, (chunk)*32(reg)
162+# endif
163+/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
164+ * than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size
165+ * of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
166+ * hint is used, the code will not work correctly. If PREPAREFORSTORE is not
167+ * used then MAX_PREFETCH_SIZE does not matter. */
168+# define MAX_PREFETCH_SIZE 128
169+/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
170+ * than 5 on a STORE prefetch and that a single prefetch can never be larger
171+ * than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because
172+ * we actually do two prefetches in that case, one 32 bytes after the other. */
173+# ifdef USE_DOUBLE
174+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
175+# else
176+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
177+# endif
178+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
179+ && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
180+/* We cannot handle this because the initial prefetches may fetch bytes that
181+ * are before the buffer being copied. We start copies with an offset
182+ * of 4 so avoid this situation when using PREPAREFORSTORE. */
183+#error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
184+# endif
185+#else /* USE_PREFETCH not defined */
186+# define PREFETCH_FOR_LOAD(offset, reg)
187+# define PREFETCH_FOR_STORE(offset, reg)
188+#endif
189+
190+#if __mips_isa_rev > 5
191+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
192+# undef PREFETCH_STORE_HINT
193+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED
194+# endif
195+# define R6_CODE
196+#endif
22197
23-/* void *memcpy(void *s1, const void *s2, size_t n); */
198+/* Allow the routine to be named something else if desired. */
199+#ifndef MEMCPY_NAME
200+# define MEMCPY_NAME memcpy
201+#endif
202+
203+/* We use these 32/64 bit registers as temporaries to do the copying. */
204+#define REG0 t0
205+#define REG1 t1
206+#define REG2 t2
207+#define REG3 t3
208+#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABIO32) || (_MIPS_SIM == _ABIO64))
209+# define REG4 t4
210+# define REG5 t5
211+# define REG6 t6
212+# define REG7 t7
213+#else
214+# define REG4 ta0
215+# define REG5 ta1
216+# define REG6 ta2
217+# define REG7 ta3
218+#endif
24219
25-#ifdef __mips64
220+/* We load/store 64 bits at a time when USE_DOUBLE is true.
221+ * The C_ prefix stands for CHUNK and is used to avoid macro name
222+ * conflicts with system header files. */
26223
27-#include <sys/asm.h>
224+#ifdef USE_DOUBLE
225+# define C_ST sd
226+# define C_LD ld
227+# ifdef __MIPSEB
228+# define C_LDHI ldl /* high part is left in big-endian */
229+# define C_STHI sdl /* high part is left in big-endian */
230+# define C_LDLO ldr /* low part is right in big-endian */
231+# define C_STLO sdr /* low part is right in big-endian */
232+# else
233+# define C_LDHI ldr /* high part is right in little-endian */
234+# define C_STHI sdr /* high part is right in little-endian */
235+# define C_LDLO ldl /* low part is left in little-endian */
236+# define C_STLO sdl /* low part is left in little-endian */
237+# endif
238+# define C_ALIGN dalign /* r6 align instruction */
239+#else
240+# define C_ST sw
241+# define C_LD lw
242+# ifdef __MIPSEB
243+# define C_LDHI lwl /* high part is left in big-endian */
244+# define C_STHI swl /* high part is left in big-endian */
245+# define C_LDLO lwr /* low part is right in big-endian */
246+# define C_STLO swr /* low part is right in big-endian */
247+# else
248+# define C_LDHI lwr /* high part is right in little-endian */
249+# define C_STHI swr /* high part is right in little-endian */
250+# define C_LDLO lwl /* low part is left in little-endian */
251+# define C_STLO swl /* low part is left in little-endian */
252+# endif
253+# define C_ALIGN align /* r6 align instruction */
254+#endif
28255
29-#if __BYTE_ORDER == __BIG_ENDIAN
30-# define LDHI ldl /* high part is left in big-endian */
31-# define SDHI sdl /* high part is left in big-endian */
32-# define LDLO ldr /* low part is right in big-endian */
33-# define SDLO sdr /* low part is right in big-endian */
256+/* Bookkeeping values for 32 vs. 64 bit mode. */
257+#ifdef USE_DOUBLE
258+# define NSIZE 8
259+# define NSIZEMASK 0x3f
260+# define NSIZEDMASK 0x7f
34261 #else
35-# define LDHI ldr /* high part is right in little-endian */
36-# define SDHI sdr /* high part is right in little-endian */
37-# define LDLO ldl /* low part is left in little-endian */
38-# define SDLO sdl /* low part is left in little-endian */
262+# define NSIZE 4
263+# define NSIZEMASK 0x1f
264+# define NSIZEDMASK 0x3f
39265 #endif
266+#define UNIT(unit) ((unit)*NSIZE)
267+#define UNITM1(unit) (((unit)*NSIZE)-1)
40268
41-ENTRY (memcpy)
269+#ifdef ANDROID_CHANGES
270+LEAF(MEMCPY_NAME, 0)
271+#else
272+LEAF(MEMCPY_NAME)
273+#endif
274+ .set nomips16
42275 .set noreorder
276+/*
277+ * Below we handle the case where memcpy is called with overlapping src and dst.
278+ * Although memcpy is not required to handle this case, some parts of Android
279+ * like Skia rely on such usage. We call memmove to handle such cases.
280+ */
281+#ifdef USE_MEMMOVE_FOR_OVERLAP
282+ PTR_SUBU t0,a0,a1
283+ PTR_SRA t2,t0,31
284+ xor t1,t0,t2
285+ PTR_SUBU t0,t1,t2
286+ sltu t2,t0,a2
287+ beq t2,zero,L(memcpy)
288+ la t9,memmove
289+ jr t9
290+ nop
291+L(memcpy):
292+#endif
293+/*
294+ * If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of
295+ * size, copy dst pointer to v0 for the return value.
296+ */
297+ slti t2,a2,(2 * NSIZE)
298+ bne t2,zero,L(lasts)
299+#if defined(RETURN_FIRST_PREFETCH) || defined(RETURN_LAST_PREFETCH)
300+ move v0,zero
301+#else
302+ move v0,a0
303+#endif
43304
44- slti t0, a2, 16 # Less than 16?
45- bne t0, zero, L(last16)
46- move v0, a0 # Setup exit value before too late
47-
48- xor t0, a1, a0 # Find a0/a1 displacement
49- andi t0, 0x7
50- bne t0, zero, L(shift) # Go handle the unaligned case
51- PTR_SUBU t1, zero, a1
52- andi t1, 0x7 # a0/a1 are aligned, but are we
53- beq t1, zero, L(chk8w) # starting in the middle of a word?
54- PTR_SUBU a2, t1
55- LDHI t0, 0(a1) # Yes we are... take care of that
56- PTR_ADDU a1, t1
57- SDHI t0, 0(a0)
58- PTR_ADDU a0, t1
59-
60-L(chk8w):
61- andi t0, a2, 0x3f # 64 or more bytes left?
62- beq t0, a2, L(chk1w)
63- PTR_SUBU a3, a2, t0 # Yes
64- PTR_ADDU a3, a1 # a3 = end address of loop
65- move a2, t0 # a2 = what will be left after loop
66-L(lop8w):
67- ld t0, 0(a1) # Loop taking 8 words at a time
68- ld t1, 8(a1)
69- ld t2, 16(a1)
70- ld t3, 24(a1)
71- ld ta0, 32(a1)
72- ld ta1, 40(a1)
73- ld ta2, 48(a1)
74- ld ta3, 56(a1)
75- PTR_ADDIU a0, 64
76- PTR_ADDIU a1, 64
77- sd t0, -64(a0)
78- sd t1, -56(a0)
79- sd t2, -48(a0)
80- sd t3, -40(a0)
81- sd ta0, -32(a0)
82- sd ta1, -24(a0)
83- sd ta2, -16(a0)
84- bne a1, a3, L(lop8w)
85- sd ta3, -8(a0)
305+#ifndef R6_CODE
86306
87-L(chk1w):
88- andi t0, a2, 0x7 # 8 or more bytes left?
89- beq t0, a2, L(last16)
90- PTR_SUBU a3, a2, t0 # Yes, handle them one dword at a time
91- PTR_ADDU a3, a1 # a3 again end address
92- move a2, t0
93-L(lop1w):
94- ld t0, 0(a1)
95- PTR_ADDIU a0, 8
96- PTR_ADDIU a1, 8
97- bne a1, a3, L(lop1w)
98- sd t0, -8(a0)
99-
100-L(last16):
101- blez a2, L(lst16e) # Handle last 16 bytes, one at a time
102- PTR_ADDU a3, a2, a1
103-L(lst16l):
104- lb t0, 0(a1)
105- PTR_ADDIU a0, 1
106- PTR_ADDIU a1, 1
107- bne a1, a3, L(lst16l)
108- sb t0, -1(a0)
109-L(lst16e):
110- jr ra # Bye, bye
111- nop
307+/*
308+ * If src and dst have different alignments, go to L(unaligned), if they
309+ * have the same alignment (but are not actually aligned) do a partial
310+ * load/store to make them aligned. If they are both already aligned
311+ * we can start copying at L(aligned).
312+ */
313+ xor t8,a1,a0
314+ andi t8,t8,(NSIZE-1) /* t8 is a0/a1 word-displacement */
315+ bne t8,zero,L(unaligned)
316+ PTR_SUBU a3, zero, a0
112317
113-L(shift):
114- PTR_SUBU a3, zero, a0 # Src and Dest unaligned
115- andi a3, 0x7 # (unoptimized case...)
116- beq a3, zero, L(shft1)
117- PTR_SUBU a2, a3 # a2 = bytes left
118- LDHI t0, 0(a1) # Take care of first odd part
119- LDLO t0, 7(a1)
120- PTR_ADDU a1, a3
121- SDHI t0, 0(a0)
122- PTR_ADDU a0, a3
123-L(shft1):
124- andi t0, a2, 0x7
125- PTR_SUBU a3, a2, t0
126- PTR_ADDU a3, a1
127-L(shfth):
128- LDHI t1, 0(a1) # Limp through, dword by dword
129- LDLO t1, 7(a1)
130- PTR_ADDIU a0, 8
131- PTR_ADDIU a1, 8
132- bne a1, a3, L(shfth)
133- sd t1, -8(a0)
134- b L(last16) # Handle anything which may be left
135- move a2, t0
318+ andi a3,a3,(NSIZE-1) /* copy a3 bytes to align a0/a1 */
319+ beq a3,zero,L(aligned) /* if a3=0, it is already aligned */
320+ PTR_SUBU a2,a2,a3 /* a2 is the remining bytes count */
136321
137- .set reorder
138-END (memcpy)
322+ C_LDHI t8,0(a1)
323+ PTR_ADDU a1,a1,a3
324+ C_STHI t8,0(a0)
325+ PTR_ADDU a0,a0,a3
326+
327+#else /* R6_CODE */
328+
329+/*
330+ * Align the destination and hope that the source gets aligned too. If it
331+ * doesn't we jump to L(r6_unaligned*) to do unaligned copies using the r6
332+ * align instruction.
333+ */
334+ andi t8,a0,7
335+ lapc t9,L(atable)
336+ PTR_LSA t9,t8,t9,2
337+ jrc t9
338+L(atable):
339+ bc L(lb0)
340+ bc L(lb7)
341+ bc L(lb6)
342+ bc L(lb5)
343+ bc L(lb4)
344+ bc L(lb3)
345+ bc L(lb2)
346+ bc L(lb1)
347+L(lb7):
348+ lb a3, 6(a1)
349+ sb a3, 6(a0)
350+L(lb6):
351+ lb a3, 5(a1)
352+ sb a3, 5(a0)
353+L(lb5):
354+ lb a3, 4(a1)
355+ sb a3, 4(a0)
356+L(lb4):
357+ lb a3, 3(a1)
358+ sb a3, 3(a0)
359+L(lb3):
360+ lb a3, 2(a1)
361+ sb a3, 2(a0)
362+L(lb2):
363+ lb a3, 1(a1)
364+ sb a3, 1(a0)
365+L(lb1):
366+ lb a3, 0(a1)
367+ sb a3, 0(a0)
368+
369+ li t9,8
370+ subu t8,t9,t8
371+ PTR_SUBU a2,a2,t8
372+ PTR_ADDU a0,a0,t8
373+ PTR_ADDU a1,a1,t8
374+L(lb0):
139375
140-#else /* !__mips64 */
376+ andi t8,a1,(NSIZE-1)
377+ lapc t9,L(jtable)
378+ PTR_LSA t9,t8,t9,2
379+ jrc t9
380+L(jtable):
381+ bc L(aligned)
382+ bc L(r6_unaligned1)
383+ bc L(r6_unaligned2)
384+ bc L(r6_unaligned3)
385+# ifdef USE_DOUBLE
386+ bc L(r6_unaligned4)
387+ bc L(r6_unaligned5)
388+ bc L(r6_unaligned6)
389+ bc L(r6_unaligned7)
390+# endif
391+#endif /* R6_CODE */
141392
142-#if __BYTE_ORDER == __BIG_ENDIAN
143-# define LWHI lwl /* high part is left in big-endian */
144-# define SWHI swl /* high part is left in big-endian */
145-# define LWLO lwr /* low part is right in big-endian */
146-# define SWLO swr /* low part is right in big-endian */
393+L(aligned):
394+
395+/*
396+ * Now dst/src are both aligned to (word or double word) aligned addresses
397+ * Set a2 to count how many bytes we have to copy after all the 64/128 byte
398+ * chunks are copied and a3 to the dst pointer after all the 64/128 byte
399+ * chunks have been copied. We will loop, incrementing a0 and a1 until a0
400+ * equals a3.
401+ */
402+
403+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
404+ beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */
405+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
406+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
407+
408+/* When in the loop we may prefetch with the 'prepare to store' hint,
409+ * in this case the a0+x should not be past the "t0-32" address. This
410+ * means: for x=128 the last "safe" a0 address is "t0-160". Alternatively,
411+ * for x=64 the last "safe" a0 address is "t0-96" In the current version we
412+ * will use "prefetch hint,128(a0)", so "t0-160" is the limit.
413+ */
414+#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
415+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
416+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
417+#endif
418+ PREFETCH_FOR_LOAD (0, a1)
419+ PREFETCH_FOR_LOAD (1, a1)
420+ PREFETCH_FOR_LOAD (2, a1)
421+ PREFETCH_FOR_LOAD (3, a1)
422+#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
423+ PREFETCH_FOR_STORE (1, a0)
424+ PREFETCH_FOR_STORE (2, a0)
425+ PREFETCH_FOR_STORE (3, a0)
426+#endif
427+#if defined(RETURN_FIRST_PREFETCH) && defined(USE_PREFETCH)
428+# if PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE
429+ sltu v1,t9,a0
430+ bgtz v1,L(skip_set)
431+ nop
432+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*4)
433+L(skip_set):
434+# else
435+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*1)
436+# endif
437+#endif
438+#if defined(RETURN_LAST_PREFETCH) && defined(USE_PREFETCH) \
439+ && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
440+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*3)
441+# ifdef USE_DOUBLE
442+ PTR_ADDIU v0,v0,32
443+# endif
444+#endif
445+L(loop16w):
446+ C_LD t0,UNIT(0)(a1)
447+#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
448+ sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */
449+ bgtz v1,L(skip_pref)
450+#endif
451+ C_LD t1,UNIT(1)(a1)
452+#ifdef R6_CODE
453+ PREFETCH_FOR_STORE (2, a0)
147454 #else
148-# define LWHI lwr /* high part is right in little-endian */
149-# define SWHI swr /* high part is right in little-endian */
150-# define LWLO lwl /* low part is left in little-endian */
151-# define SWLO swl /* low part is left in little-endian */
455+ PREFETCH_FOR_STORE (4, a0)
456+ PREFETCH_FOR_STORE (5, a0)
457+#endif
458+#if defined(RETURN_LAST_PREFETCH) && defined(USE_PREFETCH)
459+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*5)
460+# ifdef USE_DOUBLE
461+ PTR_ADDIU v0,v0,32
462+# endif
152463 #endif
464+L(skip_pref):
465+ C_LD REG2,UNIT(2)(a1)
466+ C_LD REG3,UNIT(3)(a1)
467+ C_LD REG4,UNIT(4)(a1)
468+ C_LD REG5,UNIT(5)(a1)
469+ C_LD REG6,UNIT(6)(a1)
470+ C_LD REG7,UNIT(7)(a1)
471+#ifdef R6_CODE
472+ PREFETCH_FOR_LOAD (3, a1)
473+#else
474+ PREFETCH_FOR_LOAD (4, a1)
475+#endif
476+ C_ST t0,UNIT(0)(a0)
477+ C_ST t1,UNIT(1)(a0)
478+ C_ST REG2,UNIT(2)(a0)
479+ C_ST REG3,UNIT(3)(a0)
480+ C_ST REG4,UNIT(4)(a0)
481+ C_ST REG5,UNIT(5)(a0)
482+ C_ST REG6,UNIT(6)(a0)
483+ C_ST REG7,UNIT(7)(a0)
153484
154-ENTRY (memcpy)
155- .set noreorder
485+ C_LD t0,UNIT(8)(a1)
486+ C_LD t1,UNIT(9)(a1)
487+ C_LD REG2,UNIT(10)(a1)
488+ C_LD REG3,UNIT(11)(a1)
489+ C_LD REG4,UNIT(12)(a1)
490+ C_LD REG5,UNIT(13)(a1)
491+ C_LD REG6,UNIT(14)(a1)
492+ C_LD REG7,UNIT(15)(a1)
493+#ifndef R6_CODE
494+ PREFETCH_FOR_LOAD (5, a1)
495+#endif
496+ C_ST t0,UNIT(8)(a0)
497+ C_ST t1,UNIT(9)(a0)
498+ C_ST REG2,UNIT(10)(a0)
499+ C_ST REG3,UNIT(11)(a0)
500+ C_ST REG4,UNIT(12)(a0)
501+ C_ST REG5,UNIT(13)(a0)
502+ C_ST REG6,UNIT(14)(a0)
503+ C_ST REG7,UNIT(15)(a0)
504+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
505+ bne a0,a3,L(loop16w)
506+ PTR_ADDIU a1,a1,UNIT(16) /* adding 64/128 to src */
507+ move a2,t8
508+
509+/* Here we have src and dest word-aligned but less than 64-bytes or
510+ * 128 bytes to go. Check for a 32(64) byte chunk and copy if if there
511+ * is one. Otherwise jump down to L(chk1w) to handle the tail end of
512+ * the copy.
513+ */
514+
515+L(chkw):
516+ PREFETCH_FOR_LOAD (0, a1)
517+ andi t8,a2,NSIZEMASK /* Is there a 32-byte/64-byte chunk. */
518+ /* The t8 is the reminder count past 32-bytes */
519+ beq a2,t8,L(chk1w) /* When a2=t8, no 32-byte chunk */
520+ nop
521+ C_LD t0,UNIT(0)(a1)
522+ C_LD t1,UNIT(1)(a1)
523+ C_LD REG2,UNIT(2)(a1)
524+ C_LD REG3,UNIT(3)(a1)
525+ C_LD REG4,UNIT(4)(a1)
526+ C_LD REG5,UNIT(5)(a1)
527+ C_LD REG6,UNIT(6)(a1)
528+ C_LD REG7,UNIT(7)(a1)
529+ PTR_ADDIU a1,a1,UNIT(8)
530+ C_ST t0,UNIT(0)(a0)
531+ C_ST t1,UNIT(1)(a0)
532+ C_ST REG2,UNIT(2)(a0)
533+ C_ST REG3,UNIT(3)(a0)
534+ C_ST REG4,UNIT(4)(a0)
535+ C_ST REG5,UNIT(5)(a0)
536+ C_ST REG6,UNIT(6)(a0)
537+ C_ST REG7,UNIT(7)(a0)
538+ PTR_ADDIU a0,a0,UNIT(8)
539+
540+/*
541+ * Here we have less than 32(64) bytes to copy. Set up for a loop to
542+ * copy one word (or double word) at a time. Set a2 to count how many
543+ * bytes we have to copy after all the word (or double word) chunks are
544+ * copied and a3 to the dst pointer after all the (d)word chunks have
545+ * been copied. We will loop, incrementing a0 and a1 until a0 equals a3.
546+ */
547+L(chk1w):
548+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
549+ beq a2,t8,L(lastw)
550+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
551+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
156552
157- slti t0, a2, 8 # Less than 8?
158- bne t0, zero, L(last8)
159- move v0, a0 # Setup exit value before too late
160-
161- xor t0, a1, a0 # Find a0/a1 displacement
162- andi t0, 0x3
163- bne t0, zero, L(shift) # Go handle the unaligned case
164- subu t1, zero, a1
165- andi t1, 0x3 # a0/a1 are aligned, but are we
166- beq t1, zero, L(chk8w) # starting in the middle of a word?
167- subu a2, t1
168- LWHI t0, 0(a1) # Yes we are... take care of that
169- addu a1, t1
170- SWHI t0, 0(a0)
171- addu a0, t1
172-
173-L(chk8w):
174- andi t0, a2, 0x1f # 32 or more bytes left?
175- beq t0, a2, L(chk1w)
176- subu a3, a2, t0 # Yes
177- addu a3, a1 # a3 = end address of loop
178- move a2, t0 # a2 = what will be left after loop
179-L(lop8w):
180- lw t0, 0(a1) # Loop taking 8 words at a time
181- lw t1, 4(a1)
182- lw t2, 8(a1)
183- lw t3, 12(a1)
184- lw t4, 16(a1)
185- lw t5, 20(a1)
186- lw t6, 24(a1)
187- lw t7, 28(a1)
188- addiu a0, 32
189- addiu a1, 32
190- sw t0, -32(a0)
191- sw t1, -28(a0)
192- sw t2, -24(a0)
193- sw t3, -20(a0)
194- sw t4, -16(a0)
195- sw t5, -12(a0)
196- sw t6, -8(a0)
197- bne a1, a3, L(lop8w)
198- sw t7, -4(a0)
199-
200-L(chk1w):
201- andi t0, a2, 0x3 # 4 or more bytes left?
202- beq t0, a2, L(last8)
203- subu a3, a2, t0 # Yes, handle them one word at a time
204- addu a3, a1 # a3 again end address
205- move a2, t0
206-L(lop1w):
207- lw t0, 0(a1)
208- addiu a0, 4
209- addiu a1, 4
210- bne a1, a3, L(lop1w)
211- sw t0, -4(a0)
212-
213-L(last8):
214- blez a2, L(lst8e) # Handle last 8 bytes, one at a time
215- addu a3, a2, a1
216-L(lst8l):
217- lb t0, 0(a1)
218- addiu a0, 1
219- addiu a1, 1
220- bne a1, a3, L(lst8l)
221- sb t0, -1(a0)
222-L(lst8e):
223- jr ra # Bye, bye
553+/* copying in words (4-byte or 8-byte chunks) */
554+L(wordCopy_loop):
555+ C_LD REG3,UNIT(0)(a1)
556+ PTR_ADDIU a0,a0,UNIT(1)
557+ PTR_ADDIU a1,a1,UNIT(1)
558+ bne a0,a3,L(wordCopy_loop)
559+ C_ST REG3,UNIT(-1)(a0)
560+
561+/* If we have been copying double words, see if we can copy a single word
562+ before doing byte copies. We can have, at most, one word to copy. */
563+
564+L(lastw):
565+#ifdef USE_DOUBLE
566+ andi t8,a2,3 /* a2 is the remainder past 4 byte chunks. */
567+ beq t8,a2,L(lastb)
568+ lw REG3,0(a1)
569+ sw REG3,0(a0)
570+ PTR_ADDIU a0,a0,4
571+ PTR_ADDIU a1,a1,4
572+ move a2,t8
573+#endif
574+
575+/* Copy the last 8 (or 16) bytes */
576+L(lastb):
577+ blez a2,L(leave)
578+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
579+L(lastbloop):
580+ lb v1,0(a1)
581+ PTR_ADDIU a0,a0,1
582+ PTR_ADDIU a1,a1,1
583+ bne a0,a3,L(lastbloop)
584+ sb v1,-1(a0)
585+L(leave):
586+ j ra
224587 nop
225588
226-L(shift):
227- subu a3, zero, a0 # Src and Dest unaligned
228- andi a3, 0x3 # (unoptimized case...)
229- beq a3, zero, L(shft1)
230- subu a2, a3 # a2 = bytes left
231- LWHI t0, 0(a1) # Take care of first odd part
232- LWLO t0, 3(a1)
233- addu a1, a3
234- SWHI t0, 0(a0)
235- addu a0, a3
236-L(shft1):
237- andi t0, a2, 0x3
238- subu a3, a2, t0
239- addu a3, a1
240-L(shfth):
241- LWHI t1, 0(a1) # Limp through, word by word
242- LWLO t1, 3(a1)
243- addiu a0, 4
244- addiu a1, 4
245- bne a1, a3, L(shfth)
246- sw t1, -4(a0)
247- b L(last8) # Handle anything which may be left
248- move a2, t0
589+/* We jump here with a memcpy of less than 8 or 16 bytes, depending on
590+ whether or not USE_DOUBLE is defined. Instead of just doing byte
591+ copies, check the alignment and size and use lw/sw if possible.
592+ Otherwise, do byte copies. */
249593
250- .set reorder
251-END (memcpy)
594+L(lasts):
595+ andi t8,a2,3
596+ beq t8,a2,L(lastb)
597+
598+ andi t9,a0,3
599+ bne t9,zero,L(lastb)
600+ andi t9,a1,3
601+ bne t9,zero,L(lastb)
602+
603+ PTR_SUBU a3,a2,t8
604+ PTR_ADDU a3,a0,a3
605+
606+L(wcopy_loop):
607+ lw REG3,0(a1)
608+ PTR_ADDIU a0,a0,4
609+ PTR_ADDIU a1,a1,4
610+ bne a0,a3,L(wcopy_loop)
611+ sw REG3,-4(a0)
252612
253-#endif /* !__mips64 */
613+ b L(lastb)
614+ move a2,t8
254615
255-libc_hidden_def(memcpy)
616+#ifndef R6_CODE
617+/*
618+ * UNALIGNED case, got here with a3 = "negu a0"
619+ * This code is nearly identical to the aligned code above
620+ * but only the destination (not the source) gets aligned
621+ * so we need to do partial loads of the source followed
622+ * by normal stores to the destination (once we have aligned
623+ * the destination).
624+ */
625+
626+L(unaligned):
627+ andi a3,a3,(NSIZE-1) /* copy a3 bytes to align a0/a1 */
628+ beqz a3,L(ua_chk16w) /* if a3=0, it is already aligned */
629+ PTR_SUBU a2,a2,a3 /* a2 is the remining bytes count */
630+
631+ C_LDHI v1,UNIT(0)(a1)
632+ C_LDLO v1,UNITM1(1)(a1)
633+ PTR_ADDU a1,a1,a3
634+ C_STHI v1,UNIT(0)(a0)
635+ PTR_ADDU a0,a0,a3
636+
637+/*
638+ * Now the destination (but not the source) is aligned
639+ * Set a2 to count how many bytes we have to copy after all the 64/128 byte
640+ * chunks are copied and a3 to the dst pointer after all the 64/128 byte
641+ * chunks have been copied. We will loop, incrementing a0 and a1 until a0
642+ * equals a3.
643+ */
644+
645+L(ua_chk16w):
646+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
647+ beq a2,t8,L(ua_chkw) /* if a2==t8, no 64-byte/128-byte chunks */
648+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
649+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
650+
651+# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
652+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
653+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
654+# endif
655+ PREFETCH_FOR_LOAD (0, a1)
656+ PREFETCH_FOR_LOAD (1, a1)
657+ PREFETCH_FOR_LOAD (2, a1)
658+# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
659+ PREFETCH_FOR_STORE (1, a0)
660+ PREFETCH_FOR_STORE (2, a0)
661+ PREFETCH_FOR_STORE (3, a0)
662+# endif
663+# if defined(RETURN_FIRST_PREFETCH) && defined(USE_PREFETCH)
664+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
665+ sltu v1,t9,a0
666+ bgtz v1,L(ua_skip_set)
667+ nop
668+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*4)
669+L(ua_skip_set):
670+# else
671+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*1)
672+# endif
673+# endif
674+L(ua_loop16w):
675+ PREFETCH_FOR_LOAD (3, a1)
676+ C_LDHI t0,UNIT(0)(a1)
677+ C_LDHI t1,UNIT(1)(a1)
678+ C_LDHI REG2,UNIT(2)(a1)
679+# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
680+ sltu v1,t9,a0
681+ bgtz v1,L(ua_skip_pref)
682+# endif
683+ C_LDHI REG3,UNIT(3)(a1)
684+ PREFETCH_FOR_STORE (4, a0)
685+ PREFETCH_FOR_STORE (5, a0)
686+L(ua_skip_pref):
687+ C_LDHI REG4,UNIT(4)(a1)
688+ C_LDHI REG5,UNIT(5)(a1)
689+ C_LDHI REG6,UNIT(6)(a1)
690+ C_LDHI REG7,UNIT(7)(a1)
691+ C_LDLO t0,UNITM1(1)(a1)
692+ C_LDLO t1,UNITM1(2)(a1)
693+ C_LDLO REG2,UNITM1(3)(a1)
694+ C_LDLO REG3,UNITM1(4)(a1)
695+ C_LDLO REG4,UNITM1(5)(a1)
696+ C_LDLO REG5,UNITM1(6)(a1)
697+ C_LDLO REG6,UNITM1(7)(a1)
698+ C_LDLO REG7,UNITM1(8)(a1)
699+ PREFETCH_FOR_LOAD (4, a1)
700+ C_ST t0,UNIT(0)(a0)
701+ C_ST t1,UNIT(1)(a0)
702+ C_ST REG2,UNIT(2)(a0)
703+ C_ST REG3,UNIT(3)(a0)
704+ C_ST REG4,UNIT(4)(a0)
705+ C_ST REG5,UNIT(5)(a0)
706+ C_ST REG6,UNIT(6)(a0)
707+ C_ST REG7,UNIT(7)(a0)
708+ C_LDHI t0,UNIT(8)(a1)
709+ C_LDHI t1,UNIT(9)(a1)
710+ C_LDHI REG2,UNIT(10)(a1)
711+ C_LDHI REG3,UNIT(11)(a1)
712+ C_LDHI REG4,UNIT(12)(a1)
713+ C_LDHI REG5,UNIT(13)(a1)
714+ C_LDHI REG6,UNIT(14)(a1)
715+ C_LDHI REG7,UNIT(15)(a1)
716+ C_LDLO t0,UNITM1(9)(a1)
717+ C_LDLO t1,UNITM1(10)(a1)
718+ C_LDLO REG2,UNITM1(11)(a1)
719+ C_LDLO REG3,UNITM1(12)(a1)
720+ C_LDLO REG4,UNITM1(13)(a1)
721+ C_LDLO REG5,UNITM1(14)(a1)
722+ C_LDLO REG6,UNITM1(15)(a1)
723+ C_LDLO REG7,UNITM1(16)(a1)
724+ PREFETCH_FOR_LOAD (5, a1)
725+ C_ST t0,UNIT(8)(a0)
726+ C_ST t1,UNIT(9)(a0)
727+ C_ST REG2,UNIT(10)(a0)
728+ C_ST REG3,UNIT(11)(a0)
729+ C_ST REG4,UNIT(12)(a0)
730+ C_ST REG5,UNIT(13)(a0)
731+ C_ST REG6,UNIT(14)(a0)
732+ C_ST REG7,UNIT(15)(a0)
733+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
734+ bne a0,a3,L(ua_loop16w)
735+ PTR_ADDIU a1,a1,UNIT(16) /* adding 64/128 to src */
736+ move a2,t8
737+
738+/* Here we have src and dest word-aligned but less than 64-bytes or
739+ * 128 bytes to go. Check for a 32(64) byte chunk and copy if if there
740+ * is one. Otherwise jump down to L(ua_chk1w) to handle the tail end of
741+ * the copy. */
742+
743+L(ua_chkw):
744+ PREFETCH_FOR_LOAD (0, a1)
745+ andi t8,a2,NSIZEMASK /* Is there a 32-byte/64-byte chunk. */
746+ /* t8 is the reminder count past 32-bytes */
747+ beq a2,t8,L(ua_chk1w) /* When a2=t8, no 32-byte chunk */
748+ nop
749+ C_LDHI t0,UNIT(0)(a1)
750+ C_LDHI t1,UNIT(1)(a1)
751+ C_LDHI REG2,UNIT(2)(a1)
752+ C_LDHI REG3,UNIT(3)(a1)
753+ C_LDHI REG4,UNIT(4)(a1)
754+ C_LDHI REG5,UNIT(5)(a1)
755+ C_LDHI REG6,UNIT(6)(a1)
756+ C_LDHI REG7,UNIT(7)(a1)
757+ C_LDLO t0,UNITM1(1)(a1)
758+ C_LDLO t1,UNITM1(2)(a1)
759+ C_LDLO REG2,UNITM1(3)(a1)
760+ C_LDLO REG3,UNITM1(4)(a1)
761+ C_LDLO REG4,UNITM1(5)(a1)
762+ C_LDLO REG5,UNITM1(6)(a1)
763+ C_LDLO REG6,UNITM1(7)(a1)
764+ C_LDLO REG7,UNITM1(8)(a1)
765+ PTR_ADDIU a1,a1,UNIT(8)
766+ C_ST t0,UNIT(0)(a0)
767+ C_ST t1,UNIT(1)(a0)
768+ C_ST REG2,UNIT(2)(a0)
769+ C_ST REG3,UNIT(3)(a0)
770+ C_ST REG4,UNIT(4)(a0)
771+ C_ST REG5,UNIT(5)(a0)
772+ C_ST REG6,UNIT(6)(a0)
773+ C_ST REG7,UNIT(7)(a0)
774+ PTR_ADDIU a0,a0,UNIT(8)
775+/*
776+ * Here we have less than 32(64) bytes to copy. Set up for a loop to
777+ * copy one word (or double word) at a time.
778+ */
779+L(ua_chk1w):
780+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
781+ beq a2,t8,L(ua_smallCopy)
782+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
783+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
784+
785+/* copying in words (4-byte or 8-byte chunks) */
786+L(ua_wordCopy_loop):
787+ C_LDHI v1,UNIT(0)(a1)
788+ C_LDLO v1,UNITM1(1)(a1)
789+ PTR_ADDIU a0,a0,UNIT(1)
790+ PTR_ADDIU a1,a1,UNIT(1)
791+ bne a0,a3,L(ua_wordCopy_loop)
792+ C_ST v1,UNIT(-1)(a0)
793+
794+/* Copy the last 8 (or 16) bytes */
795+L(ua_smallCopy):
796+ beqz a2,L(leave)
797+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
798+L(ua_smallCopy_loop):
799+ lb v1,0(a1)
800+ PTR_ADDIU a0,a0,1
801+ PTR_ADDIU a1,a1,1
802+ bne a0,a3,L(ua_smallCopy_loop)
803+ sb v1,-1(a0)
804+
805+ j ra
806+ nop
807+
808+#else /* R6_CODE */
809+
810+# ifdef __MIPSEB
811+# define SWAP_REGS(X,Y) X, Y
812+# define ALIGN_OFFSET(N) (N)
813+# else
814+# define SWAP_REGS(X,Y) Y, X
815+# define ALIGN_OFFSET(N) (NSIZE-N)
816+# endif
817+# define R6_UNALIGNED_WORD_COPY(BYTEOFFSET) \
818+ andi REG7, a2, (NSIZE-1);/* REG7 is # of bytes to by bytes. */ \
819+ beq REG7, a2, L(lastb); /* Check for bytes to copy by word */ \
820+ PTR_SUBU a3, a2, REG7; /* a3 is number of bytes to be copied in */ \
821+ /* (d)word chunks. */ \
822+ move a2, REG7; /* a2 is # of bytes to copy byte by byte */ \
823+ /* after word loop is finished. */ \
824+ PTR_ADDU REG6, a0, a3; /* REG6 is the dst address after loop. */ \
825+ PTR_SUBU REG2, a1, t8; /* REG2 is the aligned src address. */ \
826+ PTR_ADDU a1, a1, a3; /* a1 is addr of source after word loop. */ \
827+ C_LD t0, UNIT(0)(REG2); /* Load first part of source. */ \
828+L(r6_ua_wordcopy##BYTEOFFSET): \
829+ C_LD t1, UNIT(1)(REG2); /* Load second part of source. */ \
830+ C_ALIGN REG3, SWAP_REGS(t1,t0), ALIGN_OFFSET(BYTEOFFSET); \
831+ PTR_ADDIU a0, a0, UNIT(1); /* Increment destination pointer. */ \
832+ PTR_ADDIU REG2, REG2, UNIT(1); /* Increment aligned source pointer.*/ \
833+ move t0, t1; /* Move second part of source to first. */ \
834+ bne a0, REG6,L(r6_ua_wordcopy##BYTEOFFSET); \
835+ C_ST REG3, UNIT(-1)(a0); \
836+ j L(lastb); \
837+ nop
838+
839+ /* We are generating R6 code, the destination is 4 byte aligned and
840+ the source is not 4 byte aligned. t8 is 1, 2, or 3 depending on the
841+ alignment of the source. */
842+
843+L(r6_unaligned1):
844+ R6_UNALIGNED_WORD_COPY(1)
845+L(r6_unaligned2):
846+ R6_UNALIGNED_WORD_COPY(2)
847+L(r6_unaligned3):
848+ R6_UNALIGNED_WORD_COPY(3)
849+# ifdef USE_DOUBLE
850+L(r6_unaligned4):
851+ R6_UNALIGNED_WORD_COPY(4)
852+L(r6_unaligned5):
853+ R6_UNALIGNED_WORD_COPY(5)
854+L(r6_unaligned6):
855+ R6_UNALIGNED_WORD_COPY(6)
856+L(r6_unaligned7):
857+ R6_UNALIGNED_WORD_COPY(7)
858+# endif
859+#endif /* R6_CODE */
860+
861+ .set at
862+ .set reorder
863+END(MEMCPY_NAME)
864+#ifndef ANDROID_CHANGES
865+# ifdef _LIBC
866+# ifdef __UCLIBC__
867+libc_hidden_def(MEMCPY_NAME)
868+# else
869+libc_hidden_builtin_def (MEMCPY_NAME)
870+# endif
871+# endif
872+#endif
--- a/libc/string/mips/memset.S
+++ b/libc/string/mips/memset.S
@@ -1,6 +1,5 @@
1-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
1+/* Copyright (C) 2013-2015 Free Software Foundation, Inc.
22 This file is part of the GNU C Library.
3- Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
43
54 The GNU C Library is free software; you can redistribute it and/or
65 modify it under the terms of the GNU Lesser General Public
@@ -13,145 +12,420 @@
1312 Lesser General Public License for more details.
1413
1514 You should have received a copy of the GNU Lesser General Public
16- License along with the GNU C Library; if not, see
15+ License along with the GNU C Library. If not, see
1716 <http://www.gnu.org/licenses/>. */
1817
19-#include <features.h>
20-#include <sysdep.h>
21-#include <endian.h>
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 defined _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+
58+/* Some asm.h files do not have the L macro definition. */
59+#ifndef L
60+# if _MIPS_SIM == _ABIO32
61+# define L(label) $L ## label
62+# else
63+# define L(label) .L ## label
64+# endif
65+#endif
66+
67+/* Some asm.h files do not have the PTR_ADDIU macro definition. */
68+#ifndef PTR_ADDIU
69+# ifdef USE_DOUBLE
70+# define PTR_ADDIU daddiu
71+# else
72+# define PTR_ADDIU addiu
73+# endif
74+#endif
2275
23-/* void *memset(void *s, int c, size_t n). */
76+/* New R6 instructions that may not be in asm.h. */
77+#ifndef PTR_LSA
78+# if _MIPS_SIM == _ABI64
79+# define PTR_LSA dlsa
80+# else
81+# define PTR_LSA lsa
82+# endif
83+#endif
84+
85+/* Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
86+ or PREFETCH_STORE_STREAMED offers a large performance advantage
87+ but PREPAREFORSTORE has some special restrictions to consider.
88+
89+ Prefetch with the 'prepare for store' hint does not copy a memory
90+ location into the cache, it just allocates a cache line and zeros
91+ it out. This means that if you do not write to the entire cache
92+ line before writing it out to memory some data will get zero'ed out
93+ when the cache line is written back to memory and data will be lost.
94+
95+ There are ifdef'ed sections of this memcpy to make sure that it does not
96+ do prefetches on cache lines that are not going to be completely written.
97+ This code is only needed and only used when PREFETCH_STORE_HINT is set to
98+ PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are
99+ less than MAX_PREFETCH_SIZE bytes and if the cache line is larger it will
100+ not work correctly. */
101+
102+#ifdef USE_PREFETCH
103+# define PREFETCH_HINT_STORE 1
104+# define PREFETCH_HINT_STORE_STREAMED 5
105+# define PREFETCH_HINT_STORE_RETAINED 7
106+# define PREFETCH_HINT_PREPAREFORSTORE 30
107+
108+/* If we have not picked out what hints to use at this point use the
109+ standard load and store prefetch hints. */
110+# ifndef PREFETCH_STORE_HINT
111+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
112+# endif
113+
114+/* We double everything when USE_DOUBLE is true so we do 2 prefetches to
115+ get 64 bytes in that case. The assumption is that each individual
116+ prefetch brings in 32 bytes. */
117+# ifdef USE_DOUBLE
118+# define PREFETCH_CHUNK 64
119+# define PREFETCH_FOR_STORE(chunk, reg) \
120+ pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
121+ pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
122+# else
123+# define PREFETCH_CHUNK 32
124+# define PREFETCH_FOR_STORE(chunk, reg) \
125+ pref PREFETCH_STORE_HINT, (chunk)*32(reg)
126+# endif
24127
25-#ifdef __mips64
128+/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
129+ than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size
130+ of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
131+ hint is used, the code will not work correctly. If PREPAREFORSTORE is not
132+ used than MAX_PREFETCH_SIZE does not matter. */
133+# define MAX_PREFETCH_SIZE 128
134+/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
135+ than 5 on a STORE prefetch and that a single prefetch can never be larger
136+ than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because
137+ we actually do two prefetches in that case, one 32 bytes after the other. */
138+# ifdef USE_DOUBLE
139+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
140+# else
141+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
142+# endif
26143
27-#include <sys/asm.h>
144+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
145+ && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
146+/* We cannot handle this because the initial prefetches may fetch bytes that
147+ are before the buffer being copied. We start copies with an offset
148+ of 4 so avoid this situation when using PREPAREFORSTORE. */
149+# error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
150+# endif
151+#else /* USE_PREFETCH not defined */
152+# define PREFETCH_FOR_STORE(offset, reg)
153+#endif
154+
155+#if __mips_isa_rev > 5
156+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
157+# undef PREFETCH_STORE_HINT
158+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED
159+# endif
160+# define R6_CODE
161+#endif
28162
29-#if __BYTE_ORDER == __BIG_ENDIAN
30-# define SDHI sdl /* high part is left in big-endian */
163+/* Allow the routine to be named something else if desired. */
164+#ifndef MEMSET_NAME
165+# define MEMSET_NAME memset
166+#endif
167+
168+/* We load/store 64 bits at a time when USE_DOUBLE is true.
169+ The C_ prefix stands for CHUNK and is used to avoid macro name
170+ conflicts with system header files. */
171+
172+#ifdef USE_DOUBLE
173+# define C_ST sd
174+# ifdef __MIPSEB
175+# define C_STHI sdl /* high part is left in big-endian */
176+# else
177+# define C_STHI sdr /* high part is right in little-endian */
178+# endif
31179 #else
32-# define SDHI sdr /* high part is right in little-endian */
180+# define C_ST sw
181+# ifdef __MIPSEB
182+# define C_STHI swl /* high part is left in big-endian */
183+# else
184+# define C_STHI swr /* high part is right in little-endian */
185+# endif
33186 #endif
34187
35-ENTRY (memset)
36- .set noreorder
188+/* Bookkeeping values for 32 vs. 64 bit mode. */
189+#ifdef USE_DOUBLE
190+# define NSIZE 8
191+# define NSIZEMASK 0x3f
192+# define NSIZEDMASK 0x7f
193+#else
194+# define NSIZE 4
195+# define NSIZEMASK 0x1f
196+# define NSIZEDMASK 0x3f
197+#endif
198+#define UNIT(unit) ((unit)*NSIZE)
199+#define UNITM1(unit) (((unit)*NSIZE)-1)
37200
38- slti ta1, a2, 16 # Less than 16?
39- bne ta1, zero, L(last16)
40- move v0, a0 # Setup exit value before too late
41-
42- beq a1, zero, L(ueven) # If zero pattern, no need to extend
43- andi a1, 0xff # Avoid problems with bogus arguments
44- dsll ta0, a1, 8
45- or a1, ta0
46- dsll ta0, a1, 16
47- or a1, ta0 # a1 is now pattern in full word
48- dsll ta0, a1, 32
49- or a1, ta0 # a1 is now pattern in double word
50-
51-L(ueven):
52- PTR_SUBU ta0, zero, a0 # Unaligned address?
53- andi ta0, 0x7
54- beq ta0, zero, L(chkw)
55- PTR_SUBU a2, ta0
56- SDHI a1, 0(a0) # Yes, handle first unaligned part
57- PTR_ADDU a0, ta0 # Now both a0 and a2 are updated
201+#ifdef ANDROID_CHANGES
202+LEAF(MEMSET_NAME,0)
203+#else
204+LEAF(MEMSET_NAME)
205+#endif
58206
59-L(chkw):
60- andi ta0, a2, 0xf # Enough left for one loop iteration?
61- beq ta0, a2, L(chkl)
62- PTR_SUBU a3, a2, ta0
63- PTR_ADDU a3, a0 # a3 is last loop address +1
64- move a2, ta0 # a2 is now # of bytes left after loop
65-L(loopw):
66- PTR_ADDIU a0, 16 # Handle 2 dwords pr. iteration
67- sd a1, -16(a0)
68- bne a0, a3, L(loopw)
69- sd a1, -8(a0)
70-
71-L(chkl):
72- andi ta0, a2, 0x8 # Check if there is at least a double
73- beq ta0, zero, L(last16) # word remaining after the loop
74- PTR_SUBU a2, ta0
75- sd a1, 0(a0) # Yes...
76- PTR_ADDIU a0, 8
77-
78-L(last16):
79- blez a2, L(exit) # Handle last 16 bytes (if cnt>0)
80- PTR_ADDU a3, a2, a0 # a3 is last address +1
81-L(lst16l):
82- PTR_ADDIU a0, 1
83- bne a0, a3, L(lst16l)
84- sb a1, -1(a0)
85-L(exit):
86- j ra # Bye, bye
207+ .set nomips16
208+ .set noreorder
209+/* If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of
210+ size, copy dst pointer to v0 for the return value. */
211+ slti t2,a2,(2 * NSIZE)
212+ bne t2,zero,L(lastb)
213+ move v0,a0
214+
215+/* If memset value is not zero, we copy it to all the bytes in a 32 or 64
216+ bit word. */
217+ beq a1,zero,L(set0) /* If memset value is zero no smear */
218+ PTR_SUBU a3,zero,a0
87219 nop
88220
89- .set reorder
90-END (memset)
221+ /* smear byte into 32 or 64 bit word */
222+#if ((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2)
223+# ifdef USE_DOUBLE
224+ dins a1, a1, 8, 8 /* Replicate fill byte into half-word. */
225+ dins a1, a1, 16, 16 /* Replicate fill byte into word. */
226+ dins a1, a1, 32, 32 /* Replicate fill byte into dbl word. */
227+# else
228+ ins a1, a1, 8, 8 /* Replicate fill byte into half-word. */
229+ ins a1, a1, 16, 16 /* Replicate fill byte into word. */
230+# endif
231+#else
232+# ifdef USE_DOUBLE
233+ and a1,0xff
234+ dsll t2,a1,8
235+ or a1,t2
236+ dsll t2,a1,16
237+ or a1,t2
238+ dsll t2,a1,32
239+ or a1,t2
240+# else
241+ and a1,0xff
242+ sll t2,a1,8
243+ or a1,t2
244+ sll t2,a1,16
245+ or a1,t2
246+# endif
247+#endif
248+
249+/* If the destination address is not aligned do a partial store to get it
250+ aligned. If it is already aligned just jump to L(aligned). */
251+L(set0):
252+#ifndef R6_CODE
253+ andi t2,a3,(NSIZE-1) /* word-unaligned address? */
254+ beq t2,zero,L(aligned) /* t2 is the unalignment count */
255+ PTR_SUBU a2,a2,t2
256+ C_STHI a1,0(a0)
257+ PTR_ADDU a0,a0,t2
258+#else /* R6_CODE */
259+ andi t2,a0,(NSIZE-1)
260+ lapc t9,L(atable)
261+ PTR_LSA t9,t2,t9,2
262+ jrc t9
263+L(atable):
264+ bc L(aligned)
265+# ifdef USE_DOUBLE
266+ bc L(lb7)
267+ bc L(lb6)
268+ bc L(lb5)
269+ bc L(lb4)
270+# endif
271+ bc L(lb3)
272+ bc L(lb2)
273+ bc L(lb1)
274+L(lb7):
275+ sb a1,6(a0)
276+L(lb6):
277+ sb a1,5(a0)
278+L(lb5):
279+ sb a1,4(a0)
280+L(lb4):
281+ sb a1,3(a0)
282+L(lb3):
283+ sb a1,2(a0)
284+L(lb2):
285+ sb a1,1(a0)
286+L(lb1):
287+ sb a1,0(a0)
288+
289+ li t9,NSIZE
290+ subu t2,t9,t2
291+ PTR_SUBU a2,a2,t2
292+ PTR_ADDU a0,a0,t2
293+#endif /* R6_CODE */
294+
295+L(aligned):
296+/* If USE_DOUBLE is not set we may still want to align the data on a 16
297+ byte boundry instead of an 8 byte boundry to maximize the opportunity
298+ of proAptiv chips to do memory bonding (combining two sequential 4
299+ byte stores into one 8 byte store). We know there are at least 4 bytes
300+ left to store or we would have jumped to L(lastb) earlier in the code. */
301+#ifdef DOUBLE_ALIGN
302+ andi t2,a3,4
303+ beq t2,zero,L(double_aligned)
304+ PTR_SUBU a2,a2,t2
305+ sw a1,0(a0)
306+ PTR_ADDU a0,a0,t2
307+L(double_aligned):
308+#endif
91309
92-#else /* !__mips64 */
310+/* Now the destination is aligned to (word or double word) aligned address
311+ Set a2 to count how many bytes we have to copy after all the 64/128 byte
312+ chunks are copied and a3 to the dest pointer after all the 64/128 byte
313+ chunks have been copied. We will loop, incrementing a0 until it equals
314+ a3. */
315+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
316+ beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */
317+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
318+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
93319
94-#if __BYTE_ORDER == __BIG_ENDIAN
95-# define SWHI swl /* high part is left in big-endian */
320+/* When in the loop we may prefetch with the 'prepare to store' hint,
321+ in this case the a0+x should not be past the "t0-32" address. This
322+ means: for x=128 the last "safe" a0 address is "t0-160". Alternatively,
323+ for x=64 the last "safe" a0 address is "t0-96" In the current version we
324+ will use "prefetch hint,128(a0)", so "t0-160" is the limit. */
325+#if defined(USE_PREFETCH) \
326+ && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
327+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
328+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
329+#endif
330+#if defined(USE_PREFETCH) \
331+ && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
332+ PREFETCH_FOR_STORE (1, a0)
333+ PREFETCH_FOR_STORE (2, a0)
334+ PREFETCH_FOR_STORE (3, a0)
335+#endif
336+
337+L(loop16w):
338+#if defined(USE_PREFETCH) \
339+ && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
340+ sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */
341+ bgtz v1,L(skip_pref)
342+ nop
343+#endif
344+#ifdef R6_CODE
345+ PREFETCH_FOR_STORE (2, a0)
96346 #else
97-# define SWHI swr /* high part is right in little-endian */
347+ PREFETCH_FOR_STORE (4, a0)
348+ PREFETCH_FOR_STORE (5, a0)
98349 #endif
350+L(skip_pref):
351+ C_ST a1,UNIT(0)(a0)
352+ C_ST a1,UNIT(1)(a0)
353+ C_ST a1,UNIT(2)(a0)
354+ C_ST a1,UNIT(3)(a0)
355+ C_ST a1,UNIT(4)(a0)
356+ C_ST a1,UNIT(5)(a0)
357+ C_ST a1,UNIT(6)(a0)
358+ C_ST a1,UNIT(7)(a0)
359+ C_ST a1,UNIT(8)(a0)
360+ C_ST a1,UNIT(9)(a0)
361+ C_ST a1,UNIT(10)(a0)
362+ C_ST a1,UNIT(11)(a0)
363+ C_ST a1,UNIT(12)(a0)
364+ C_ST a1,UNIT(13)(a0)
365+ C_ST a1,UNIT(14)(a0)
366+ C_ST a1,UNIT(15)(a0)
367+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
368+ bne a0,a3,L(loop16w)
369+ nop
370+ move a2,t8
99371
100-ENTRY (memset)
101- .set noreorder
372+/* Here we have dest word-aligned but less than 64-bytes or 128 bytes to go.
373+ Check for a 32(64) byte chunk and copy if if there is one. Otherwise
374+ jump down to L(chk1w) to handle the tail end of the copy. */
375+L(chkw):
376+ andi t8,a2,NSIZEMASK /* is there a 32-byte/64-byte chunk. */
377+ /* the t8 is the reminder count past 32-bytes */
378+ beq a2,t8,L(chk1w)/* when a2==t8, no 32-byte chunk */
379+ nop
380+ C_ST a1,UNIT(0)(a0)
381+ C_ST a1,UNIT(1)(a0)
382+ C_ST a1,UNIT(2)(a0)
383+ C_ST a1,UNIT(3)(a0)
384+ C_ST a1,UNIT(4)(a0)
385+ C_ST a1,UNIT(5)(a0)
386+ C_ST a1,UNIT(6)(a0)
387+ C_ST a1,UNIT(7)(a0)
388+ PTR_ADDIU a0,a0,UNIT(8)
389+
390+/* Here we have less than 32(64) bytes to set. Set up for a loop to
391+ copy one word (or double word) at a time. Set a2 to count how many
392+ bytes we have to copy after all the word (or double word) chunks are
393+ copied and a3 to the dest pointer after all the (d)word chunks have
394+ been copied. We will loop, incrementing a0 until a0 equals a3. */
395+L(chk1w):
396+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
397+ beq a2,t8,L(lastb)
398+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
399+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
102400
103- slti t1, a2, 8 # Less than 8?
104- bne t1, zero, L(last8)
105- move v0, a0 # Setup exit value before too late
106-
107- beq a1, zero, L(ueven) # If zero pattern, no need to extend
108- andi a1, 0xff # Avoid problems with bogus arguments
109- sll t0, a1, 8
110- or a1, t0
111- sll t0, a1, 16
112- or a1, t0 # a1 is now pattern in full word
113-
114-L(ueven):
115- subu t0, zero, a0 # Unaligned address?
116- andi t0, 0x3
117- beq t0, zero, L(chkw)
118- subu a2, t0
119- SWHI a1, 0(a0) # Yes, handle first unaligned part
120- addu a0, t0 # Now both a0 and a2 are updated
121-
122-L(chkw):
123- andi t0, a2, 0x7 # Enough left for one loop iteration?
124- beq t0, a2, L(chkl)
125- subu a3, a2, t0
126- addu a3, a0 # a3 is last loop address +1
127- move a2, t0 # a2 is now # of bytes left after loop
128-L(loopw):
129- addiu a0, 8 # Handle 2 words pr. iteration
130- sw a1, -8(a0)
131- bne a0, a3, L(loopw)
132- sw a1, -4(a0)
133-
134-L(chkl):
135- andi t0, a2, 0x4 # Check if there is at least a full
136- beq t0, zero, L(last8) # word remaining after the loop
137- subu a2, t0
138- sw a1, 0(a0) # Yes...
139- addiu a0, 4
140-
141-L(last8):
142- blez a2, L(exit) # Handle last 8 bytes (if cnt>0)
143- addu a3, a2, a0 # a3 is last address +1
144-L(lst8l):
145- addiu a0, 1
146- bne a0, a3, L(lst8l)
147- sb a1, -1(a0)
148-L(exit):
149- j ra # Bye, bye
401+/* copying in words (4-byte or 8 byte chunks) */
402+L(wordCopy_loop):
403+ PTR_ADDIU a0,a0,UNIT(1)
404+ bne a0,a3,L(wordCopy_loop)
405+ C_ST a1,UNIT(-1)(a0)
406+
407+/* Copy the last 8 (or 16) bytes */
408+L(lastb):
409+ blez a2,L(leave)
410+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
411+L(lastbloop):
412+ PTR_ADDIU a0,a0,1
413+ bne a0,a3,L(lastbloop)
414+ sb a1,-1(a0)
415+L(leave):
416+ j ra
150417 nop
151418
419+ .set at
152420 .set reorder
153-END (memset)
154-
155-#endif /* !__mips64 */
421+END(MEMSET_NAME)
422+#ifndef ANDROID_CHANGES
423+# ifdef _LIBC
424+# ifdef __UCLIBC__
425+libc_hidden_def(MEMSET_NAME)
426+# else
427+libc_hidden_builtin_def (MEMSET_NAME)
428+# endif
429+# endif
430+#endif
156431
157-libc_hidden_def(memset)
Show on old repository browser