2.9
[glibc/nacl-glibc.git] / sysdeps / alpha / alphaev6 / memcpy.S
blob7cff521da20c24e68ca5a047d9d7f63c190ba7e0
1 /* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    EV6 optimized by Rick Gorton <rick.gorton@alpha-processor.com>.
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.
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.
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.  */
21  * Much of the information about 21264 scheduling/coding comes from:
22  *      Compiler Writer's Guide for the Alpha 21264
23  *      abbreviated as 'CWG' in other comments here
24  *      ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
25  * Scheduling notation:
26  *      E       - either cluster
27  *      U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
28  *      L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
29  *
30  * Temp usage notes:
31  *      $0              - destination address
32  *      $1,$2,          - scratch
33  */
35 #include <sysdep.h>
37         .arch ev6
38         .set noreorder
39         .set noat
41 ENTRY(memcpy)
42         .prologue 0
44         mov     $16, $0                 # E : copy dest to return
45         ble     $18, $nomoredata        # U : done with the copy?
46         xor     $16, $17, $1            # E : are source and dest alignments the same?
47         and     $1, 7, $1               # E : are they the same mod 8?
49         bne     $1, $misaligned         # U : Nope - gotta do this the slow way
50         /* source and dest are same mod 8 address */
51         and     $16, 7, $1              # E : Are both 0mod8?
52         beq     $1, $both_0mod8         # U : Yes
53         nop                             # E :
55         /*
56          * source and dest are same misalignment.  move a byte at a time
57          * until a 0mod8 alignment for both is reached.
58          * At least one byte more to move
59          */
61 $head_align:
62         ldbu    $1, 0($17)              # L : grab a byte
63         subq    $18, 1, $18             # E : count--
64         addq    $17, 1, $17             # E : src++
65         stb     $1, 0($16)              # L :
66         addq    $16, 1, $16             # E : dest++
67         and     $16, 7, $1              # E : Are we at 0mod8 yet?
68         ble     $18, $nomoredata        # U : done with the copy?
69         bne     $1, $head_align         # U :
71 $both_0mod8:
72         cmple   $18, 127, $1            # E : Can we unroll the loop?
73         bne     $1, $no_unroll          # U :
74         and     $16, 63, $1             # E : get mod64 alignment
75         beq     $1, $do_unroll          # U : no single quads to fiddle
77 $single_head_quad:
78         ldq     $1, 0($17)              # L : get 8 bytes
79         subq    $18, 8, $18             # E : count -= 8
80         addq    $17, 8, $17             # E : src += 8
81         nop                             # E :
83         stq     $1, 0($16)              # L : store
84         addq    $16, 8, $16             # E : dest += 8
85         and     $16, 63, $1             # E : get mod64 alignment
86         bne     $1, $single_head_quad   # U : still not fully aligned
88 $do_unroll:
89         addq    $16, 64, $7             # E : Initial (+1 trip) wh64 address
90         cmple   $18, 127, $1            # E : Can we go through the unrolled loop?
91         bne     $1, $tail_quads         # U : Nope
92         nop                             # E :
94 $unroll_body:
95         wh64    ($7)                    # L1 : memory subsystem hint: 64 bytes at
96                                         # ($7) are about to be over-written
97         ldq     $6, 0($17)              # L0 : bytes 0..7
98         nop                             # E :
99         nop                             # E :
101         ldq     $4, 8($17)              # L : bytes 8..15
102         ldq     $5, 16($17)             # L : bytes 16..23
103         addq    $7, 64, $7              # E : Update next wh64 address
104         nop                             # E :
106         ldq     $3, 24($17)             # L : bytes 24..31
107         addq    $16, 64, $1             # E : fallback value for wh64
108         nop                             # E :
109         nop                             # E :
111         addq    $17, 32, $17            # E : src += 32 bytes
112         stq     $6, 0($16)              # L : bytes 0..7
113         nop                             # E :
114         nop                             # E :
116         stq     $4, 8($16)              # L : bytes 8..15
117         stq     $5, 16($16)             # L : bytes 16..23
118         subq    $18, 192, $2            # E : At least two more trips to go?
119         nop                             # E :
121         stq     $3, 24($16)             # L : bytes 24..31
122         addq    $16, 32, $16            # E : dest += 32 bytes
123         nop                             # E :
124         nop                             # E :
126         ldq     $6, 0($17)              # L : bytes 0..7
127         ldq     $4, 8($17)              # L : bytes 8..15
128         cmovlt  $2, $1, $7              # E : Latency 2, extra map slot - Use
129                                         # fallback wh64 address if < 2 more trips
130         nop                             # E :
132         ldq     $5, 16($17)             # L : bytes 16..23
133         ldq     $3, 24($17)             # L : bytes 24..31
134         addq    $16, 32, $16            # E : dest += 32
135         subq    $18, 64, $18            # E : count -= 64
137         addq    $17, 32, $17            # E : src += 32
138         stq     $6, -32($16)            # L : bytes 0..7
139         stq     $4, -24($16)            # L : bytes 8..15
140         cmple   $18, 63, $1             # E : At least one more trip?
142         stq     $5, -16($16)            # L : bytes 16..23
143         stq     $3, -8($16)             # L : bytes 24..31
144         nop                             # E :
145         beq     $1, $unroll_body
147 $tail_quads:
148 $no_unroll:
149         .align 4
150         subq    $18, 8, $18             # E : At least a quad left?
151         blt     $18, $less_than_8       # U : Nope
152         nop                             # E :
153         nop                             # E :
155 $move_a_quad:
156         ldq     $1, 0($17)              # L : fetch 8
157         subq    $18, 8, $18             # E : count -= 8
158         addq    $17, 8, $17             # E : src += 8
159         nop                             # E :
161         stq     $1, 0($16)              # L : store 8
162         addq    $16, 8, $16             # E : dest += 8
163         bge     $18, $move_a_quad       # U :
164         nop                             # E :
166 $less_than_8:
167         .align 4
168         addq    $18, 8, $18             # E : add back for trailing bytes
169         ble     $18, $nomoredata        # U : All-done
170         nop                             # E :
171         nop                             # E :
173         /* Trailing bytes */
174 $tail_bytes:
175         subq    $18, 1, $18             # E : count--
176         ldbu    $1, 0($17)              # L : fetch a byte
177         addq    $17, 1, $17             # E : src++
178         nop                             # E :
180         stb     $1, 0($16)              # L : store a byte
181         addq    $16, 1, $16             # E : dest++
182         bgt     $18, $tail_bytes        # U : more to be done?
183         nop                             # E :
185         /* branching to exit takes 3 extra cycles, so replicate exit here */
186         ret     $31, ($26), 1           # L0 :
187         nop                             # E :
188         nop                             # E :
189         nop                             # E :
191 $misaligned:
192         mov     $0, $4                  # E : dest temp
193         and     $0, 7, $1               # E : dest alignment mod8
194         beq     $1, $dest_0mod8         # U : life doesnt totally suck
195         nop
197 $aligndest:
198         ble     $18, $nomoredata        # U :
199         ldbu    $1, 0($17)              # L : fetch a byte
200         subq    $18, 1, $18             # E : count--
201         addq    $17, 1, $17             # E : src++
203         stb     $1, 0($4)               # L : store it
204         addq    $4, 1, $4               # E : dest++
205         and     $4, 7, $1               # E : dest 0mod8 yet?
206         bne     $1, $aligndest          # U : go until we are aligned.
208         /* Source has unknown alignment, but dest is known to be 0mod8 */
209 $dest_0mod8:
210         subq    $18, 8, $18             # E : At least a quad left?
211         blt     $18, $misalign_tail     # U : Nope
212         ldq_u   $3, 0($17)              # L : seed (rotating load) of 8 bytes
213         nop                             # E :
215 $mis_quad:
216         ldq_u   $16, 8($17)             # L : Fetch next 8
217         extql   $3, $17, $3             # U : masking
218         extqh   $16, $17, $1            # U : masking
219         bis     $3, $1, $1              # E : merged bytes to store
221         subq    $18, 8, $18             # E : count -= 8
222         addq    $17, 8, $17             # E : src += 8
223         stq     $1, 0($4)               # L : store 8 (aligned)
224         mov     $16, $3                 # E : "rotate" source data
226         addq    $4, 8, $4               # E : dest += 8
227         bge     $18, $mis_quad          # U : More quads to move
228         nop
229         nop
231 $misalign_tail:
232         addq    $18, 8, $18             # E : account for tail stuff
233         ble     $18, $nomoredata        # U :
234         nop
235         nop
237 $misalign_byte:
238         ldbu    $1, 0($17)              # L : fetch 1
239         subq    $18, 1, $18             # E : count--
240         addq    $17, 1, $17             # E : src++
241         nop                             # E :
243         stb     $1, 0($4)               # L : store
244         addq    $4, 1, $4               # E : dest++
245         bgt     $18, $misalign_byte     # U : more to go?
246         nop
249 $nomoredata:
250         ret     $31, ($26), 1           # L0 :
251         nop                             # E :
252         nop                             # E :
253         nop                             # E :
255 END(memcpy)
256 libc_hidden_builtin_def (memcpy)