revert between 56095 -> 55830 in arch
[AROS.git] / arch / i386-all / exec / copymem_SSE.S
blob4cc6171543dd7c6d9e658a6e41f53d62fe23e33c
1 /*
2     Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3     $Id$
4 */
6 /*****************************************************************************
8     NAME
10         AROS_LH3(void, CopyMem_SSE,
12     SYNOPSIS
13         AROS_LHA(CONST_APTR, source, A0),
14         AROS_LHA(APTR, destination, A1),
15         AROS_LHA(IPTR, len, D0),
17     LOCATION
18         struct ExecBase *, SysBase, 104, Exec) (if we're lucky)
20     FUNCTION
21         Copy some data from one location to another in memory using
22         SSE optimised copying method if enough data.
24     INPUTS
25         source - Pointer to source area
26         dest   - Pointer to destination
27         size   - number of bytes to copy
29     RESULT
31     NOTES
33     EXAMPLE
35     BUGS
37     SEE ALSO
39     INTERNALS
40         The source and destination area *ARE* allowed to overlap.
42 ******************************************************************************/
43 #include "aros/i386/asm.h"
44 #include <aros/config.h>
46     .text
47     .globl  AROS_SLIB_ENTRY(CopyMem_SSE,Exec,104)
48     _FUNCTION(AROS_SLIB_ENTRY(CopyMem_SSE,Exec,104))
49 AROS_SLIB_ENTRY(CopyMem_SSE,Exec,104):
50     movl        12(%esp),%eax
51     cmpl        $4096,%eax
52     jge         .begin
53     jmp         AROS_SLIB_ENTRY(CopyMem,Exec,104)    /* non-SSE version is faster for small copies */
55     .globl  AROS_SLIB_ENTRY(CopyMemQuick_SSE,Exec,105)
56     _FUNCTION(AROS_SLIB_ENTRY(CopyMemQuick_SSE,Exec,105))
57 AROS_SLIB_ENTRY(CopyMemQuick_SSE,Exec,105):
58     movl        12(%esp),%eax
59     cmpl        $4096,%eax
60     jge         .begin
61     jmp         AROS_SLIB_ENTRY(CopyMemQuick,Exec,105)    /* non-SSE version is faster for small copies */
63 .begin:
64     pushl       %edi
65     pushl       %esi
66     pushl       %ecx
68     movl        16(%esp),%esi
69     movl        20(%esp),%edi
70     movl        24(%esp),%eax
72     /*
73     ** okay, so the user wants to copy at least 4096 bytes.
74     ** let's go!
75     */
76     pushl       %ebx
77     pushl       %ebp
78     movl        %esp,%ebp
80     /*
81     ** align memory to save xmm regs
82     */
83     subl        $16*4,%esp
84     andl        $-16,%esp
85     movntps     %xmm0,(%esp)
86     movntps     %xmm1,16(%esp)
87     movntps     %xmm2,32(%esp)
88     movntps     %xmm3,48(%esp)
89     movl        %eax,%ebx
91     /*
92     ** compute step
93     cmp    %edi,%esi
94     jl    .copy_backward
95     */
97 .copy_forward:
98     /*
99     ** prefetch area 
100     */
101     prefetchnta (%esi)
102     prefetchnta 32(%esi)
103     prefetchnta 64(%esi)
104     prefetchnta 96(%esi)
105     prefetchnta 128(%esi)
106     prefetchnta 160(%esi)
108     /*
109     ** check memory alignment
110     ** a little trick ;)
111     */
112     movl        $16,%eax
113     sub         %edi,%eax
114     andl        $15,%eax
115     je          .noalign
117     movl        %eax,%ecx        /* set count register */
118     subl        %eax,%ebx        /* update "to-do" length */
119     cld
120     rep         movsb
122 .noalign:
123     movl        %esi,%eax        /* start checking alignment here */
124     subl        $64,%ebx        /* another trick here - don't use cmp, but neg flag instead */
125     jl          .fast_copy_done
126     andl        $15,%eax
127     je          .aligned_copy
129 .unaligned_copy:
130     prefetchnta 160(%esi)        /* it's true we prefetched "something". but we may have moved during alignment */
131     movups      (%esi),%xmm0    /* transfer block 16 bytes by 16 bytes */
132     movups      16(%esi),%xmm1
133     movups      32(%esi),%xmm2
134     movups      48(%esi),%xmm3
135     movntps     %xmm0,(%edi)
136     movntps     %xmm1,16(%edi)
137     movntps     %xmm2,32(%edi)
138     movntps     %xmm3,48(%edi)
139     addl        $64,%esi
140     addl        $64,%edi
141     subl        $64,%ebx        /* update count */
142     jge         .unaligned_copy /* continue */
143     jmp         .fast_copy_done
145 .aligned_copy:
146     prefetchnta 160(%esi)        /* it's true we prefetched "something". but we may have moved during alignment */
147     movaps      (%esi),%xmm0    /* transfer block 16 bytes by 16 bytes */
148     movaps      16(%esi),%xmm1
149     movaps      32(%esi),%xmm2
150     movaps      48(%esi),%xmm3
151     movntps     %xmm0,(%edi)
152     movntps     %xmm1,16(%edi)
153     movntps     %xmm2,32(%edi)
154     movntps     %xmm3,48(%edi)
155     addl        $64,%esi
156     addl        $64,%edi
157     subl        $64,%ebx        /* update count */
158     jge         .aligned_copy   /* continue */
159     jmp         .fast_copy_done
161 .copy_backward:
162     /*
163     ** adjust pointers first
164     */
165     add         %eax,%esi
166     add         %eax,%edi
167     subl        $1,%esi
168     subl        $1,%edi
170     /*
171     ** prefetch area 
172     */
173     prefetchnta -191(%esi)
174     prefetchnta -159(%esi)
175     prefetchnta -127(%esi)
176     prefetchnta -95(%esi)
177     prefetchnta -63(%esi)
178     prefetchnta -31(%esi)
180     /*
181     ** check memory alignment
182     ** a little trick ;)
183     */
184     mov         %edi,%eax
185     add         $1,%eax
186     andl        $15,%eax
187     je          .noalign
189     movl        %eax,%ecx        /* set count register */
190     subl        %eax,%ebx        /* update "to-do" length */
191     std                /* indicate we want to copy backwards */
192     rep         movsb
194 .noalign_back:
195     movl        %esi,%eax        /* start checking alignment here */
196     subl        $64,%ebx        /* another trick here - don't use cmp, but neg flag instead */
197     jl          .fast_copy_done
198     andl        $15,%eax
199     cmp         $15,%eax
200     je          .aligned_reverse_copy
202 .unaligned_reverse_copy:
203     prefetchnta -191(%esi)        /* it's true we prefetched "something". but we may have moved during alignment */
204     movups      -63(%esi),%xmm0    /* transfer block 16 bytes by 16 bytes */
205     movups      -47(%esi),%xmm1
206     movups      -31(%esi),%xmm2
207     movups      -15(%esi),%xmm3
208     movntps     %xmm0,-63(%edi)
209     movntps     %xmm1,-47(%edi)
210     movntps     %xmm2,-31(%edi)
211     movntps     %xmm3,-15(%edi)
212     subl        $64,%esi
213     subl        $64,%edi
214     subl        $64,%ebx        /* update count */
215     jge         .unaligned_reverse_copy /* continue */
216     jmp         .fast_copy_done
218 .aligned_reverse_copy:
219     prefetchnta -192(%esi)        /* it's true we prefetched "something". but we may have moved during alignment */
220     movaps      -63(%esi),%xmm0    /* transfer block 16 bytes by 16 bytes */
221     movaps      -47(%esi),%xmm1
222     movaps      -31(%esi),%xmm2
223     movaps      -15(%esi),%xmm3
224     movntps     %xmm0,-63(%edi)
225     movntps     %xmm1,-47(%edi)
226     movntps     %xmm2,-31(%edi)
227     movntps     %xmm3,-15(%edi)
228     subl        $64,%esi
229     subl        $64,%edi
230     subl        $64,%ebx        /* update count */
231     jge         .aligned_reverse_copy   /* continue */
232     jmp         .fast_copy_done
236 .fast_copy_done:
237     /*
238     ** prefetch stack. we'll be leaving soon
239     */
240     prefetchnta (%esp)
241     prefetchnta 32(%esp)
242     prefetchnta 64(%esp)
244     /*
245     ** copy remaining bytes
246     ** note: std not needed for reverse resume
247     */
248     addl        $64,%ebx
249     movl        %ebx,%ecx
250     rep         movsb
251     
252     /*
253     ** restore everything
254     */
255     movaps      (%esp),%xmm0
256     movaps      16(%esp),%xmm1
257     movaps      32(%esp),%xmm2
258     movaps      48(%esp),%xmm3
259     movl        %ebp,%esp
260     popl        %ebp
261     popl        %ebx
262     popl        %ecx
263     popl        %esi
264     popl        %edi
266     /*
267     ** just cleanup..
268     */
269     cld
270     ret