sparc: Fix sparc64 memmove length comparison (BZ 31266)
[glibc.git] / sysdeps / sparc / sparc64 / memmove.S
blobf14b09afafdd9ec107b795e8fa206ace15feec20
1 /* Copy memory to memory until the specified number of bytes
2    has been copied.  Overlap is handled correctly.
3    For SPARC V9.
4    Copyright (C) 2017-2024 Free Software Foundation, Inc.
5    This file is part of the GNU C Library.
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <https://www.gnu.org/licenses/>.  */
21 #include <sysdep.h>
23 #ifndef XCC
24 # define XCC    xcc
25         .register       %g2, #scratch
26 #endif
28 ENTRY(memmove)
29         mov     %o0, %g2        /* Save pointer to destination  */
30         cmp     %o1, %o0        /* if from address is >= to use forward copy  */
31         bgeu,a  %XCC, 2f        /* else use backward if ...  */
32          cmp    %o2, 17         /* delay slot, for small counts copy bytes  */
34         sub     %o0, %o1, %o4   /* get difference of two addresses  */
35         cmp     %o2, %o4        /* compare size and difference of addresses  */
36         bgu     %XCC, .Lovbc    /* if size is bigger, have to do overlapped copy  */
37          cmp    %o2, 17         /* delay slot, for small counts copy bytes  */
39  * normal, copy forwards
40  */
41 2:      bleu    %XCC, .Ldbytecp
42          andcc  %o1, 3, %o5     /* is src word aligned  */
43         bz,pn   %icc, .Laldst
44          cmp    %o5, 2          /* is src half-word aligned  */
45         be,pn   %icc, .Ls2alg
46          cmp    %o5, 3          /* src is byte aligned  */
47         ldub    [%o1], %o3      /* move 1 or 3 bytes to align it  */
48         inc     1, %o1
49         stb     %o3, [%o0]      /* move a byte to align src  */
50         inc     1, %o0
51         bne,pn  %icc, .Ls2alg
52          dec    %o2
53         b       .Lald           /* now go align dest  */
54          andcc  %o0, 3, %o5
56 .Ls2alg:
57         lduh    [%o1], %o3      /* know src is 2 byte aligned  */
58         inc     2, %o1
59         srl     %o3, 8, %o4
60         stb     %o4, [%o0]      /* have to do bytes,  */
61         stb     %o3, [%o0 + 1]  /* don't know dst alignment  */
62         inc     2, %o0
63         dec     2, %o2
65 .Laldst:
66         andcc   %o0, 3, %o5     /* align the destination address  */
67 .Lald:  bz,pn   %icc, .Lw4cp
68          cmp    %o5, 2
69         bz,pn   %icc, .Lw2cp
70          cmp    %o5, 3
71 .Lw3cp:
72         lduw    [%o1], %o4
73         inc     4, %o1
74         srl     %o4, 24, %o5
75         stb     %o5, [%o0]
76         bne,pt  %icc, .Lw1cp
77          inc    %o0
78         dec     1, %o2
79         andn    %o2, 3, %o3     /* i3 is aligned word count  */
80         dec     4, %o3          /* avoid reading beyond tail of src  */
81         sub     %o1, %o0, %o1   /* i1 gets the difference  */
83 1:      sll     %o4, 8, %g1     /* save residual bytes  */
84         lduw    [%o1+%o0], %o4
85         deccc   4, %o3
86         srl     %o4, 24, %o5    /* merge with residual  */
87         or      %o5, %g1, %g1
88         st      %g1, [%o0]
89         bnz,pt  %XCC, 1b
90          inc    4, %o0
91         sub     %o1, 3, %o1     /* used one byte of last word read  */
92         and     %o2, 3, %o2
93         b       7f
94          inc    4, %o2
96 .Lw1cp:
97         srl     %o4, 8, %o5
98         sth     %o5, [%o0]
99         inc     2, %o0
100         dec     3, %o2
101         andn    %o2, 3, %o3
102         dec     4, %o3          /* avoid reading beyond tail of src  */
103         sub     %o1, %o0, %o1   /* i1 gets the difference  */
105 2:      sll     %o4, 24, %g1    /* save residual bytes  */
106         lduw    [%o1+%o0], %o4
107         deccc   4, %o3
108         srl     %o4, 8, %o5     /* merge with residual  */
109         or      %o5, %g1, %g1
110         st      %g1, [%o0]
111         bnz,pt  %XCC, 2b
112          inc    4, %o0
113         sub     %o1, 1, %o1     /* used three bytes of last word read  */
114         and     %o2, 3, %o2
115         b       7f
116         inc     4, %o2
118 .Lw2cp:
119         lduw    [%o1], %o4
120         inc     4, %o1
121         srl     %o4, 16, %o5
122         sth     %o5, [%o0]
123         inc     2, %o0
124         dec     2, %o2
125         andn    %o2, 3, %o3     /* i3 is aligned word count  */
126         dec     4, %o3          /* avoid reading beyond tail of src  */
127         sub     %o1, %o0, %o1   /* i1 gets the difference  */
129 3:      sll     %o4, 16, %g1    /* save residual bytes  */
130         lduw    [%o1+%o0], %o4
131         deccc   4, %o3
132         srl     %o4, 16, %o5    /* merge with residual  */
133         or      %o5, %g1, %g1
134         st      %g1, [%o0]
135         bnz,pt  %XCC, 3b
136          inc    4, %o0
137         sub     %o1, 2, %o1     /* used two bytes of last word read  */
138         and     %o2, 3, %o2
139         b       7f
140          inc    4, %o2
142 .Lw4cp:
143         andn    %o2, 3, %o3     /* i3 is aligned word count  */
144         sub     %o1, %o0, %o1   /* i1 gets the difference  */
146 1:      lduw    [%o1+%o0], %o4  /* read from address  */
147         deccc   4, %o3          /* decrement count  */
148         st      %o4, [%o0]      /* write at destination address  */
149         bg,pt   %XCC, 1b
150          inc    4, %o0          /* increment to address  */
151         b       7f
152          and    %o2, 3, %o2     /* number of leftover bytes, if any  */
155  * differenced byte copy, works with any alignment
156  */
157 .Ldbytecp:
158         b       7f
159          sub    %o1, %o0, %o1   /* i1 gets the difference  */
161 4:      stb     %o4, [%o0]      /* write to address  */
162         inc     %o0             /* inc to address  */
163 7:      deccc   %o2             /* decrement count  */
164         bge,a   %XCC, 4b        /* loop till done  */
165          ldub   [%o1+%o0], %o4  /* read from address  */
166         retl
167          mov    %g2, %o0        /* return pointer to destination  */
170  * an overlapped copy that must be done "backwards"
171  */
172 .Lovbc:
173         add     %o1, %o2, %o1   /* get to end of source space  */
174         add     %o0, %o2, %o0   /* get to end of destination space  */
175         sub     %o1, %o0, %o1   /* i1 gets the difference  */
177 5:      dec     %o0             /* decrement to address  */
178         ldub    [%o1+%o0], %o3  /* read a byte  */
179         deccc   %o2             /* decrement count  */
180         bg,pt   %XCC, 5b        /* loop until done  */
181          stb    %o3, [%o0]      /* write byte  */
182         retl
183          mov    %g2, %o0        /* return pointer to destination  */
184 END(memmove)
186 libc_hidden_builtin_def (memmove)