Add unwind directives. Drop superfluous restore of ar.pfs.
[kopensolaris-gnu/glibc.git] / sysdeps / ia64 / memmove.S
1 /* Optimized version of the standard memmove() function.
2    This file is part of the GNU C Library.
3    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
4    Contributed by Dan Pop <Dan.Pop@cern.ch>.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 /* Return: dest
22
23    Inputs:
24         in0:    dest
25         in1:    src
26         in2:    byte count
27
28    The core of the function is the memcpy implementation used in memcpy.S.
29    When bytes have to be copied backwards, only the easy case, when 
30    all arguments are multiples of 8, is optimised.
31
32    In this form, it assumes little endian mode.  For big endian mode,
33    sh1 must be computed using an extra instruction: sub sh1 = 64, sh1
34    or the UM.be bit should be cleared at the beginning and set at the end.  */
35
36 #include <sysdep.h>
37 #undef ret
38
39 #define OP_T_THRES      16
40 #define OPSIZ            8
41
42 #define adest           r15
43 #define saved_pr        r17
44 #define saved_lc        r18
45 #define dest            r19
46 #define src             r20
47 #define len             r21
48 #define asrc            r22
49 #define tmp2            r23
50 #define tmp3            r24
51 #define tmp4            r25
52 #define ptable          r26
53 #define ploop56         r27
54 #define loopaddr        r28
55 #define sh1             r29
56 #define loopcnt         r30
57 #define value           r31
58
59 #define LOOP(shift)                                                     \
60                 .align  32 ;                                            \
61 .loop##shift##:                                                         \
62 (p[0])          ld8     r[0] = [asrc], 8 ;      /* w1 */                \
63 (p[MEMLAT+1])   st8     [dest] = value, 8 ;                             \
64 (p[MEMLAT])     shrp    value = r[MEMLAT], r[MEMLAT+1], shift ; \
65                 nop.b   0 ;                                             \
66                 nop.b   0 ;                                             \
67                 br.ctop.sptk .loop##shift ;                             \
68                 br.cond.sptk .cpyfew ; /* deal with the remaining bytes */
69
70 ENTRY(memmove)
71         .prologue
72         alloc   r2 = ar.pfs, 3, 29, 0, 32
73 #include "softpipe.h"
74         .rotr   r[MEMLAT + 2], q[MEMLAT + 1]
75         .rotp   p[MEMLAT + 2]
76         mov     ret0 = in0              // return value = dest
77         .save pr, saved_pr
78         mov     saved_pr = pr           // save the predicate registers
79         .save ar.lc, saved_lc
80         mov     saved_lc = ar.lc        // save the loop counter
81         .body
82         or      tmp3 = in0, in1 ;;      // tmp3 = dest | src
83         or      tmp3 = tmp3, in2        // tmp3 = dest | src | len
84         mov     dest = in0              // dest
85         mov     src = in1               // src
86         mov     len = in2               // len
87         sub     tmp2 = r0, in0          // tmp2 = -dest
88         cmp.eq  p6, p0 = in2, r0        // if (len == 0)
89 (p6)    br.cond.spnt .restore_and_exit;;//      return dest;
90         and     tmp4 = 7, tmp3          // tmp4 = (dest | src | len) & 7
91         cmp.le  p6, p0 = dest, src      // if dest <= src it's always safe
92 (p6)    br.cond.spnt .forward           // to copy forward
93         add     tmp3 = src, len;;       
94         cmp.lt  p6, p0 = dest, tmp3     // if dest > src && dest < src + len
95 (p6)    br.cond.spnt .backward          // we have to copy backward
96
97 .forward:
98         shr.u   loopcnt = len, 4 ;;     // loopcnt = len / 16
99         cmp.ne  p6, p0 = tmp4, r0       // if ((dest | src | len) & 7 != 0)
100 (p6)    br.cond.sptk .next              //      goto next;
101
102 // The optimal case, when dest, src and len are all multiples of 8
103
104         and     tmp3 = 0xf, len
105         mov     pr.rot = 1 << 16        // set rotating predicates
106         mov     ar.ec = MEMLAT + 1 ;;   // set the epilog counter
107         cmp.ne  p6, p0 = tmp3, r0       // do we have to copy an extra word?
108         adds    loopcnt = -1, loopcnt;; // --loopcnt
109 (p6)    ld8     value = [src], 8;;
110 (p6)    st8     [dest] = value, 8       // copy the "odd" word
111         mov     ar.lc = loopcnt         // set the loop counter
112         cmp.eq  p6, p0 = 8, len
113 (p6)    br.cond.spnt .restore_and_exit;;// the one-word special case
114         adds    adest = 8, dest         // set adest one word ahead of dest
115         adds    asrc = 8, src ;;        // set asrc one word ahead of src
116         nop.b   0                       // get the "golden" alignment for 
117         nop.b   0                       // the next loop
118 .l0:
119 (p[0])          ld8     r[0] = [src], 16
120 (p[0])          ld8     q[0] = [asrc], 16
121 (p[MEMLAT])     st8     [dest] = r[MEMLAT], 16
122 (p[MEMLAT])     st8     [adest] = q[MEMLAT], 16
123                 br.ctop.dptk .l0 ;;
124
125         mov     pr = saved_pr, -1       // restore the predicate registers
126         mov     ar.lc = saved_lc        // restore the loop counter
127         br.ret.sptk.many b0
128 .next:
129         cmp.ge  p6, p0 = OP_T_THRES, len        // is len <= OP_T_THRES
130         and     loopcnt = 7, tmp2               // loopcnt = -dest % 8
131 (p6)    br.cond.spnt    .cpyfew                 // copy byte by byte
132         ;;
133         cmp.eq  p6, p0 = loopcnt, r0
134 (p6)    br.cond.sptk    .dest_aligned
135         sub     len = len, loopcnt      // len -= -dest % 8
136         adds    loopcnt = -1, loopcnt   // --loopcnt
137         ;;
138         mov     ar.lc = loopcnt
139 .l1:                                    // copy -dest % 8 bytes
140         ld1     value = [src], 1        // value = *src++
141         ;;
142         st1     [dest] = value, 1       // *dest++ = value  
143         br.cloop.dptk .l1       
144 .dest_aligned:
145         and     sh1 = 7, src            // sh1 = src % 8
146         and     tmp2 = -8, len          // tmp2 = len & -OPSIZ
147         and     asrc = -8, src          // asrc = src & -OPSIZ  -- align src
148         shr.u   loopcnt = len, 3        // loopcnt = len / 8
149         and     len = 7, len;;          // len = len % 8
150         adds    loopcnt = -1, loopcnt   // --loopcnt
151         addl    tmp4 = @ltoff(.table), gp 
152         addl    tmp3 = @ltoff(.loop56), gp
153         mov     ar.ec = MEMLAT + 1      // set EC
154         mov     pr.rot = 1 << 16;;      // set rotating predicates
155         mov     ar.lc = loopcnt         // set LC
156         cmp.eq  p6, p0 = sh1, r0        // is the src aligned?
157 (p6)    br.cond.sptk .src_aligned
158         add     src = src, tmp2         // src += len & -OPSIZ
159         shl     sh1 = sh1, 3            // sh1 = 8 * (src % 8)
160         ld8     ploop56 = [tmp3]        // ploop56 = &loop56
161         ld8     ptable = [tmp4];;       // ptable = &table
162         add     tmp3 = ptable, sh1;;    // tmp3 = &table + sh1
163         mov     ar.ec = MEMLAT + 1 + 1 // one more pass needed
164         ld8     tmp4 = [tmp3];;         // tmp4 = loop offset
165         sub     loopaddr = ploop56,tmp4 // loopadd = &loop56 - loop offset
166         ld8     r[1] = [asrc], 8;;      // w0
167         mov     b6 = loopaddr;;
168         br      b6                      // jump to the appropriate loop
169
170         LOOP(8)
171         LOOP(16)
172         LOOP(24)
173         LOOP(32)
174         LOOP(40)
175         LOOP(48)
176         LOOP(56)
177         
178 .src_aligned:
179 .l3:
180 (p[0])          ld8     r[0] = [src], 8
181 (p[MEMLAT])     st8     [dest] = r[MEMLAT], 8
182                 br.ctop.dptk .l3
183 .cpyfew:
184         cmp.eq  p6, p0 = len, r0        // is len == 0 ?
185         adds    len = -1, len           // --len;
186 (p6)    br.cond.spnt    .restore_and_exit ;;
187         mov     ar.lc = len
188 .l4:
189         ld1     value = [src], 1
190         ;;
191         st1     [dest] = value, 1
192         br.cloop.dptk   .l4 ;;
193 .restore_and_exit:
194         mov     pr = saved_pr, -1       // restore the predicate registers
195         mov     ar.lc = saved_lc        // restore the loop counter
196         br.ret.sptk.many b0
197
198 // In the case of a backward copy, optimise only the case when everything
199 // is a multiple of 8, otherwise copy byte by byte.  The backward copy is
200 // used only when the blocks are overlapping and dest > src.
201
202 .backward:
203         shr.u   loopcnt = len, 3        // loopcnt = len / 8
204         add     src = src, len          // src points one byte past the end
205         add     dest = dest, len ;;     // dest points one byte past the end
206         mov     ar.ec = MEMLAT + 1      // set the epilog counter
207         mov     pr.rot = 1 << 16        // set rotating predicates
208         adds    loopcnt = -1, loopcnt   // --loopcnt
209         cmp.ne  p6, p0 = tmp4, r0       // if ((dest | src | len) & 7 != 0)
210 (p6)    br.cond.sptk .bytecopy ;;       // copy byte by byte backward
211         adds    src = -8, src           // src points to the last word
212         adds    dest = -8, dest         // dest points to the last word
213         mov     ar.lc = loopcnt;;       // set the loop counter
214 .l5:
215 (p[0])          ld8     r[0] = [src], -8
216 (p[MEMLAT])     st8     [dest] = r[MEMLAT], -8
217                 br.ctop.dptk .l5
218                 br.cond.sptk .restore_and_exit
219 .bytecopy:
220         adds    src = -1, src           // src points to the last byte
221         adds    dest = -1, dest         // dest points to the last byte
222         adds    loopcnt = -1, len;;     // loopcnt = len - 1
223         mov     ar.lc = loopcnt;;       // set the loop counter 
224 .l6:
225 (p[0])          ld1     r[0] = [src], -1
226 (p[MEMLAT])     st1     [dest] = r[MEMLAT], -1
227                 br.ctop.dptk .l6
228                 br.cond.sptk .restore_and_exit
229 .table:
230         data8   0                       // dummy entry
231         data8   .loop56 - .loop8
232         data8   .loop56 - .loop16
233         data8   .loop56 - .loop24
234         data8   .loop56 - .loop32
235         data8   .loop56 - .loop40
236         data8   .loop56 - .loop48
237         data8   .loop56 - .loop56
238
239 END(memmove)