c77f1b8d972087b0ff61f472885b1915c7eecebb
[jlayton/glibc.git] / sysdeps / mips / memcpy.S
1 /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <sysdep.h>
21 #include <endian.h>
22
23
24 /* void *memcpy(void *s1, const void *s2, size_t n);
25
26    This routine could be optimized further for MIPS64, but this is left
27    as an exercise for the future. When it is done, the file should be kept
28    as a sisterfile to this one, and placed in the sysdeps/mips/mips64 
29    directory.  */
30
31 #if __BYTE_ORDER == __BIG_ENDIAN
32 #  define LWHI  lwl             /* high part is left in big-endian      */
33 #  define SWHI  swl             /* high part is left in big-endian      */
34 #  define LWLO  lwr             /* low part is right in big-endian      */
35 #  define SWLO  swr             /* low part is right in big-endian      */
36 #else
37 #  define LWHI  lwr             /* high part is right in little-endian  */
38 #  define SWHI  swr             /* high part is right in little-endian  */
39 #  define LWLO  lwl             /* low part is left in little-endian    */
40 #  define SWLO  swl             /* low part is left in little-endian    */
41 #endif
42
43 #ifndef t0
44 # define t0 a4
45 #endif
46 #ifndef t1
47 # define t1 a5
48 #endif
49 #ifndef t2
50 # define t2 a6
51 #endif
52 #ifndef t3
53 # define t3 a7
54 #endif
55
56 ENTRY (memcpy)
57         .set    noreorder
58
59         slti    t0, a2, 8               # Less than 8?
60         bne     t0, zero, L(last8)
61         move    v0, a0                  # Setup exit value before too late
62
63         xor     t0, a1, a0              # Find a0/a1 displacement
64         andi    t0, 0x3
65         bne     t0, zero, L(shift)      # Go handle the unaligned case
66         subu    t1, zero, a1
67         andi    t1, 0x3                 # a0/a1 are aligned, but are we
68         beq     t1, zero, L(chk8w)      #  starting in the middle of a word?
69         subu    a2, t1
70         LWHI    t0, 0(a1)               # Yes we are... take care of that
71         addu    a1, t1
72         SWHI    t0, 0(a0)
73         addu    a0, t1
74
75 L(chk8w):       andi    t0, a2, 0x1f            # 32 or more bytes left?
76         beq     t0, a2, L(chk1w)
77         subu    a3, a2, t0              # Yes
78         addu    a3, a1                  # a3 = end address of loop
79         move    a2, t0                  # a2 = what will be left after loop
80 L(lop8w):       lw      t0,  0(a1)              # Loop taking 8 words at a time
81         lw      t1,  4(a1)
82         lw      t2,  8(a1)
83         lw      t3, 12(a1)
84         lw      t4, 16(a1)
85         lw      t5, 20(a1)
86         lw      t6, 24(a1)
87         lw      t7, 28(a1)
88         addiu   a0, 32
89         addiu   a1, 32
90         sw      t0, -32(a0)
91         sw      t1, -28(a0)
92         sw      t2, -24(a0)
93         sw      t3, -20(a0)
94         sw      t4, -16(a0)
95         sw      t5, -12(a0)
96         sw      t6,  -8(a0)
97         bne     a1, a3, L(lop8w)
98         sw      t7,  -4(a0)
99
100 L(chk1w):       andi    t0, a2, 0x3             # 4 or more bytes left?
101         beq     t0, a2, L(last8)
102         subu    a3, a2, t0              # Yes, handle them one word at a time
103         addu    a3, a1                  # a3 again end address
104         move    a2, t0
105 L(lop1w):       lw      t0, 0(a1)
106         addiu   a0, 4
107         addiu   a1, 4
108         bne     a1, a3, L(lop1w)
109         sw      t0, -4(a0)
110
111 L(last8):       blez    a2, L(lst8e)            # Handle last 8 bytes, one at a time
112         addu    a3, a2, a1
113 L(lst8l):       lb      t0, 0(a1)
114         addiu   a0, 1
115         addiu   a1, 1
116         bne     a1, a3, L(lst8l)
117         sb      t0, -1(a0)
118 L(lst8e):       jr      ra                      # Bye, bye
119         nop
120
121 L(shift):       subu    a3, zero, a0            # Src and Dest unaligned 
122         andi    a3, 0x3                 #  (unoptimized case...)
123         beq     a3, zero, L(shft1)
124         subu    a2, a3                  # a2 = bytes left
125         LWHI    t0, 0(a1)               # Take care of first odd part
126         LWLO    t0, 3(a1)
127         addu    a1, a3
128         SWHI    t0, 0(a0)
129         addu    a0, a3
130 L(shft1):       andi    t0, a2, 0x3
131         subu    a3, a2, t0
132         addu    a3, a1
133 L(shfth):       LWHI    t1, 0(a1)               # Limp through, word by word
134         LWLO    t1, 3(a1)
135         addiu   a0, 4
136         addiu   a1, 4
137         bne     a1, a3, L(shfth)
138         sw      t1, -4(a0)
139         b       L(last8)                        # Handle anything which may be left
140         move    a2, t0
141
142         .set    reorder
143 END (memcpy)